]> git.saurik.com Git - apple/security.git/commitdiff
Security-55471.14.18.tar.gz os-x-1095 v55471.14.18
authorApple <opensource@apple.com>
Tue, 23 Sep 2014 21:24:36 +0000 (21:24 +0000)
committerApple <opensource@apple.com>
Tue, 23 Sep 2014 21:24:36 +0000 (21:24 +0000)
91 files changed:
CloudKeychainProxy/CloudKeychainProxy-Info.plist
Keychain Circle Notification/Keychain Circle Notification-Info.plist
Keychain/Keychain-Info.plist
Security.xcodeproj/project.pbxproj
Security.xcodeproj/project.xcworkspace/xcuserdata/jkauth.xcuserdatad/UserInterfaceState.xcuserstate [new file with mode: 0644]
Security.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
authd/Info.plist
codesign_tests/FatDynamicValidation.c [new file with mode: 0644]
codesign_tests/validation.sh [new file with mode: 0755]
lib/Info-Security.plist
lib/plugins/csparser-Info.plist
lib/security.exp-in
libsecurity_apple_csp/libsecurity_apple_csp.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_apple_cspdl/libsecurity_apple_cspdl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_apple_file_dl/libsecurity_apple_file_dl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_apple_x509_cl/libsecurity_apple_x509_cl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_apple_x509_tp/libsecurity_apple_x509_tp.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_asn1/libsecurity_asn1.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_authorization/libsecurity_authorization.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_cdsa_client/libsecurity_cdsa_client.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_cdsa_plugin/libsecurity_cdsa_plugin.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_cdsa_utilities/libsecurity_cdsa_utilities.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_cdsa_utils/libsecurity_cdsa_utils.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_checkpw/libsecurity_checkpw.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_cms/libsecurity_cms.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_codesigning/lib/CSCommon.h
libsecurity_codesigning/lib/SecAssessment.cpp
libsecurity_codesigning/lib/SecAssessment.h
libsecurity_codesigning/lib/SecCodeSigner.cpp
libsecurity_codesigning/lib/SecCodeSigner.h
libsecurity_codesigning/lib/SecStaticCode.cpp
libsecurity_codesigning/lib/SecStaticCode.h
libsecurity_codesigning/lib/SecStaticCodePriv.h
libsecurity_codesigning/lib/StaticCode.cpp
libsecurity_codesigning/lib/StaticCode.h
libsecurity_codesigning/lib/bundlediskrep.cpp
libsecurity_codesigning/lib/bundlediskrep.h
libsecurity_codesigning/lib/dirscanner.cpp [new file with mode: 0644]
libsecurity_codesigning/lib/dirscanner.h [new file with mode: 0644]
libsecurity_codesigning/lib/diskrep.cpp
libsecurity_codesigning/lib/diskrep.h
libsecurity_codesigning/lib/kerneldiskrep.cpp
libsecurity_codesigning/lib/kerneldiskrep.h
libsecurity_codesigning/lib/machorep.cpp
libsecurity_codesigning/lib/machorep.h
libsecurity_codesigning/lib/opaquewhitelist.cpp [new file with mode: 0644]
libsecurity_codesigning/lib/opaquewhitelist.h [new file with mode: 0644]
libsecurity_codesigning/lib/piddiskrep.cpp
libsecurity_codesigning/lib/piddiskrep.h
libsecurity_codesigning/lib/policyengine.cpp
libsecurity_codesigning/lib/policyengine.h
libsecurity_codesigning/lib/resources.cpp
libsecurity_codesigning/lib/resources.h
libsecurity_codesigning/lib/security_codesigning.exp
libsecurity_codesigning/lib/signer.cpp
libsecurity_codesigning/lib/signer.h
libsecurity_codesigning/lib/singlediskrep.cpp
libsecurity_codesigning/lib/singlediskrep.h
libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj
libsecurity_codesigning/libsecurity_codesigning.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_comcryption/libsecurity_comcryption.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_cryptkit/libsecurity_cryptkit.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_cssm/libsecurity_cssm.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_filedb/libsecurity_filedb.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_keychain/lib/SecTrust.cpp
libsecurity_keychain/lib/Trust.cpp
libsecurity_keychain/lib/Trust.h
libsecurity_keychain/libDER/libDER.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_keychain/libsecurity_keychain.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_manifest/libsecurity_manifest.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_mds/libsecurity_mds.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_ocspd/libsecurity_ocspd.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_pkcs12/libsecurity_pkcs12.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_sd_cspdl/libsecurity_sd_cspdl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_smime/libsecurity_smime.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_ssl/lib/sslCrypto.c
libsecurity_ssl/libsecurity_ssl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_transform/libsecurity_transform.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurity_utilities/lib/cfmunge.cpp
libsecurity_utilities/lib/cfutilities.cpp
libsecurity_utilities/lib/cfutilities.h
libsecurity_utilities/lib/errors.h
libsecurity_utilities/lib/macho++.cpp
libsecurity_utilities/lib/macho++.h
libsecurity_utilities/lib/unix++.cpp
libsecurity_utilities/lib/unix++.h
libsecurity_utilities/libsecurity_utilities.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
libsecurityd/libsecurityd.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
sec/sec.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist [new file with mode: 0644]
sec/securityd/Regressions/secd-55-account-circle.c
sec/securityd/SecItemServer.c

index 753b00e358061e692a72b318408833627d41ff14..116d48a13e9d54a09d346872841867838fddf2e0 100644 (file)
@@ -21,7 +21,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>55471.14.8</string>
+       <string>55471.14.18</string>
        <key>NSHumanReadableCopyright</key>
        <string>Copyright Â© 2013 Apple, Inc. All rights reserved.</string>
 </dict>
index a7c85cbda5504c2fcf88bbcc92eed8618a08270f..0896253d37f4ad597107243d5c6ce7f7316796d1 100644 (file)
@@ -21,7 +21,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>55471.14.8</string>
+       <string>55471.14.18</string>
        <key>LSApplicationCategoryType</key>
        <string></string>
        <key>LSMinimumSystemVersion</key>
index db90fc621ad35653247c720cb1080241ce291297..94b28a955f6003cdb2328633b436ad5ecf7a60a2 100644 (file)
@@ -21,7 +21,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>55471.14.8</string>
+       <string>55471.14.18</string>
        <key>LSMinimumSystemVersion</key>
        <string>${MACOSX_DEPLOYMENT_TARGET}</string>
        <key>NSMainNibFile</key>
index 8e20972e351124399f15ea123b84840bcae744ea..04caee6371d38ea46008dd320b3179f9065f8288 100644 (file)
@@ -53,6 +53,7 @@
                        );
                        dependencies = (
                                721680B3179B4C6C00406BB4 /* PBXTargetDependency */,
+                               37A7CEDA197DBA8700926CE8 /* PBXTargetDependency */,
                                722CF218175D602F00BCE0A5 /* PBXTargetDependency */,
                                521470291697842500DF0DB3 /* PBXTargetDependency */,
                                18F235FF15CA100300060520 /* PBXTargetDependency */,
                18FE688B1471A46700A2CBE3 /* SecureTransportPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 182BB372146F13BB000BF1F3 /* SecureTransportPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                18FE688C1471A46700A2CBE3 /* TrustSettingsSchema.h in Headers */ = {isa = PBXBuildFile; fileRef = 182BB1C8146EAD5D000BF1F3 /* TrustSettingsSchema.h */; settings = {ATTRIBUTES = (Private, ); }; };
                18FE688D1471A46700A2CBE3 /* X509Templates.h in Headers */ = {isa = PBXBuildFile; fileRef = 1844609E146DFCB700B12992 /* X509Templates.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               37A7CEAE197DB8FA00926CE8 /* FatDynamicValidation.c in Sources */ = {isa = PBXBuildFile; fileRef = 37A7CEAD197DB8FA00926CE8 /* FatDynamicValidation.c */; };
+               37A7CEDD197DCEE500926CE8 /* validation.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = 37A7CEDB197DCDD700926CE8 /* validation.sh */; };
                395E7CEE16C64EA500CD82A4 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 395E7CED16C64EA500CD82A4 /* SystemConfiguration.framework */; };
                39BFB04516D304DE0022564B /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 395E7CED16C64EA500CD82A4 /* SystemConfiguration.framework */; };
                4A5C1790161A9DFB00ABF784 /* authd_private.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 18F2351A15C9FA3C00060520 /* authd_private.h */; };
                        remoteGlobalIDString = 18FE67E91471A3AA00A2CBE3;
                        remoteInfo = copyHeaders;
                };
+               37A7CED9197DBA8700926CE8 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 18073841146D0D4E00F05C24 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 37A7CEAA197DB8FA00926CE8;
+                       remoteInfo = codesign_tests;
+               };
                4AD6F6F31651CC2500DB4CE6 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 186CDD1614CA11C700AF9171 /* sec.xcodeproj */;
                        name = "Copy asl module";
                        runOnlyForDeploymentPostprocessing = 1;
                };
+               37A7CEDC197DCECD00926CE8 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /AppleInternal/CoreOS/codesign_tests;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               37A7CEDD197DCEE500926CE8 /* validation.sh in CopyFiles */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               37A7CF21197DD10900926CE8 /* CopyFiles */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /AppleInternal/CoreOS;
+                       dstSubfolderSpec = 0;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
                4A5C178F161A9DE000ABF784 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                18F235FC15CA0EDB00060520 /* libstdc++.6.0.9.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.6.0.9.dylib"; path = "/usr/lib/libstdc++.6.0.9.dylib"; sourceTree = "<absolute>"; };
                18F2360015CAF41100060520 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_codesigning.a; path = /usr/local/lib/libsecurity_codesigning.a; sourceTree = "<absolute>"; };
                18FE67EA1471A3AA00A2CBE3 /* Security.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Security.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+               37A7CEAB197DB8FA00926CE8 /* codesign_tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = codesign_tests; sourceTree = BUILT_PRODUCTS_DIR; };
+               37A7CEAD197DB8FA00926CE8 /* FatDynamicValidation.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = FatDynamicValidation.c; sourceTree = "<group>"; };
+               37A7CEDB197DCDD700926CE8 /* validation.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = validation.sh; sourceTree = "<group>"; };
                395E7CED16C64EA500CD82A4 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
                4C12893715FFECF3008CE3E3 /* utilities.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = utilities.xcodeproj; sourceTree = "<group>"; };
                4C2505B616D2DF9F002CE025 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = "<group>"; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               37A7CEA8197DB8FA00926CE8 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                4C96F7BE16D6DF8300D3B39D /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                                4C96F7C316D6DF8400D3B39D /* Keychain Circle Notification */,
                                72756C00175D485D00F52070 /* cloud_keychain_diagnose */,
                                721680A7179B40F600406BB4 /* iCloudStats */,
+                               37A7CEAC197DB8FA00926CE8 /* codesign_tests */,
                                1807384D146D0D4E00F05C24 /* Frameworks */,
                                1807384C146D0D4E00F05C24 /* Products */,
                        );
                                4C96F7C116D6DF8300D3B39D /* Keychain Circle Notification.app */,
                                72756BFE175D485D00F52070 /* cloud_keychain_diagnose */,
                                721680A5179B40F600406BB4 /* iCloudStats */,
+                               37A7CEAB197DB8FA00926CE8 /* codesign_tests */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                        name = "Supporting Files";
                        sourceTree = "<group>";
                };
+               4C0F6FAF1985879300178101 /* sectask */ = {
+                       isa = PBXGroup;
+                       children = (
+                               4C0F6F861985877800178101 /* SecEntitlements.h */,
+                       );
+                       name = sectask;
+                       path = ../sectask;
+                       sourceTree = "<group>";
+               };
+               37A7CEAC197DB8FA00926CE8 /* codesign_tests */ = {
+                       isa = PBXGroup;
+                       children = (
+                               37A7CEAD197DB8FA00926CE8 /* FatDynamicValidation.c */,
+                               37A7CEDB197DCDD700926CE8 /* validation.sh */,
+                       );
+                       path = codesign_tests;
+                       sourceTree = "<group>";
+               };
                4C1288F615FFECF2008CE3E3 /* utilities */ = {
                        isa = PBXGroup;
                        children = (
                        productReference = 18FE67EA1471A3AA00A2CBE3 /* Security.framework */;
                        productType = "com.apple.product-type.framework";
                };
+               37A7CEAA197DB8FA00926CE8 /* codesign_tests */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 37A7CED8197DB8FA00926CE8 /* Build configuration list for PBXNativeTarget "codesign_tests" */;
+                       buildPhases = (
+                               37A7CEA7197DB8FA00926CE8 /* Sources */,
+                               37A7CEA8197DB8FA00926CE8 /* Frameworks */,
+                               37A7CEDC197DCECD00926CE8 /* CopyFiles */,
+                               37A7CF21197DD10900926CE8 /* CopyFiles */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = codesign_tests;
+                       productName = codesign_tests;
+                       productReference = 37A7CEAB197DB8FA00926CE8 /* codesign_tests */;
+                       productType = "com.apple.product-type.tool";
+               };
                4C96F7C016D6DF8300D3B39D /* Keychain Circle Notification */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 4C96F7D516D6DF8400D3B39D /* Build configuration list for PBXNativeTarget "Keychain Circle Notification" */;
                        isa = PBXProject;
                        attributes = {
                                LastUpgradeCheck = 0420;
+                               TargetAttributes = {
+                                       37A7CEAA197DB8FA00926CE8 = {
+                                               CreatedOnToolsVersion = 6.0;
+                                       };
+                               };
                        };
                        buildConfigurationList = 18073844146D0D4E00F05C24 /* Build configuration list for PBXProject "Security" */;
                        compatibilityVersion = "Xcode 3.2";
                                4CE4729E16D833FD009070D1 /* Security_temporary_UI */,
                                72756BFD175D485D00F52070 /* cloud_keychain_diagnose */,
                                721680A4179B40F600406BB4 /* iCloudStats */,
+                               37A7CEAA197DB8FA00926CE8 /* codesign_tests */,
                        );
                };
 /* End PBXProject section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               37A7CEA7197DB8FA00926CE8 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               37A7CEAE197DB8FA00926CE8 /* FatDynamicValidation.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                4C96F7BD16D6DF8300D3B39D /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        target = 18FE67E91471A3AA00A2CBE3 /* copyHeaders */;
                        targetProxy = 18FE688E1471A4C900A2CBE3 /* PBXContainerItemProxy */;
                };
+               37A7CEDA197DBA8700926CE8 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 37A7CEAA197DB8FA00926CE8 /* codesign_tests */;
+                       targetProxy = 37A7CED9197DBA8700926CE8 /* PBXContainerItemProxy */;
+               };
                4AD6F6F41651CC2500DB4CE6 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        name = libSecOtrOSX;
                        };
                        name = Release;
                };
+               37A7CEAF197DB8FA00926CE8 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               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_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_IDENTITY = "-";
+                               COPY_PHASE_STRIP = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INSTALL_PATH = /AppleInternal/CoreOS/codesign_tests;
+                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx;
+                       };
+                       name = Debug;
+               };
+               37A7CEB0197DB8FA00926CE8 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               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_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_IDENTITY = "-";
+                               COPY_PHASE_STRIP = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INSTALL_PATH = /AppleInternal/CoreOS/codesign_tests;
+                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx;
+                       };
+                       name = Release;
+               };
                4C96F7D616D6DF8400D3B39D /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               37A7CED8197DB8FA00926CE8 /* Build configuration list for PBXNativeTarget "codesign_tests" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               37A7CEAF197DB8FA00926CE8 /* Debug */,
+                               37A7CEB0197DB8FA00926CE8 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                4C96F7D516D6DF8400D3B39D /* Build configuration list for PBXNativeTarget "Keychain Circle Notification" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
diff --git a/Security.xcodeproj/project.xcworkspace/xcuserdata/jkauth.xcuserdatad/UserInterfaceState.xcuserstate b/Security.xcodeproj/project.xcworkspace/xcuserdata/jkauth.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644 (file)
index 0000000..a5e3d88
Binary files /dev/null and b/Security.xcodeproj/project.xcworkspace/xcuserdata/jkauth.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/Security.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/Security.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..fc11631
--- /dev/null
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0C6C630A15D193C800BC68CD</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>0C6C642915D5ADB500BC68CD</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>0CC3350716C1ED8000399E53</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>1807384A146D0D4E00F05C24</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>18270ED514CF282600B05E7F</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>182BB567146F4DCA000BF1F3</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>182BB598146FE295000BF1F3</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>186F778814E59FB200434E1F</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>186F778C14E59FDA00434E1F</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>18F234EA15C9F9A600060520</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>18FE67E91471A3AA00A2CBE3</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>37A7CEAA197DB8FA00926CE8</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4C96F7C016D6DF8300D3B39D</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CB23B45169F5873003A0131</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CC7A7B216CC2A84003E10C1</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CE4729E16D833FD009070D1</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>5214700516977CB800DF0DB3</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>721680A4179B40F600406BB4</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>72756BFD175D485D00F52070</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
index 4169be64a4d43e7862ac6ff426c017cb614fa282..45709370da45dd696c8a00fbde6f308e344e84e9 100644 (file)
@@ -19,7 +19,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>55471.14.8</string>
+       <string>55471.14.18</string>
        <key>NSHumanReadableCopyright</key>
        <string>Copyright Â© 2012 Apple. All rights reserved.</string>
        <key>XPCService</key>
diff --git a/codesign_tests/FatDynamicValidation.c b/codesign_tests/FatDynamicValidation.c
new file mode 100644 (file)
index 0000000..a8bfeae
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014 Apple Computer, Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, 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 <stdio.h>
+#include <unistd.h>
+
+int main(int argc, const char * argv[]) {
+
+       printf("Going to sleep for 60 seconds\n");
+
+       sleep(60);
+
+       return 0;
+}
diff --git a/codesign_tests/validation.sh b/codesign_tests/validation.sh
new file mode 100755 (executable)
index 0000000..c439893
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+echo "[TEST] codesign dynamic validation"
+
+echo "[BEGIN] Dynamic validate pid 1"
+codesign --verify --verbose=3 1
+
+if [ $? -ne 0 ]
+then
+       echo "[FAIL]"
+else
+       echo "[PASS]"
+fi
+
+echo "[BEGIN] Dynamic validate a universal binary"
+
+/AppleInternal/CoreOS/codesign_tests/codesign_tests &
+pid=$!
+codesign --verify --verbose=3 $!
+
+if [ $? -ne 0 ]
+then
+       echo "[FAIL]"
+else
+       echo "[PASS]"
+fi
+
+echo "[BEGIN] Dynamic validate a universal binary, 32 bit slice"
+
+arch -i386 /AppleInternal/CoreOS/codesign_tests/codesign_tests &
+pid=$!
+codesign --verify --verbose=3 $!
+
+if [ $? -ne 0 ]
+then
+       echo "[FAIL]"
+else
+       echo "[PASS]"
+fi
+
+# Will exit with status of last command.
+
+exit $?
index 72270a74c7d96c563f76600edfc4b6d542fce910..4be65305bd61ca801737602dd22f69525c266554 100644 (file)
@@ -19,6 +19,6 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>55471.14.8</string>
+       <string>55471.14.18</string>
 </dict>
 </plist>
index 76a993e0ee4725311bf6196503f3391a42dee28e..0d076c45b353e7de46e33315e3200a8f91359a42 100644 (file)
@@ -17,7 +17,7 @@
        <key>CFBundleSignature</key>
        <string>????</string>
        <key>CFBundleVersion</key>
-       <string>55471.14.8</string>
+       <string>55471.14.18</string>
        <key>CFBundleShortVersionString</key>
        <string>3.0</string>
 </dict>
index 4e0838c20c3bbd3630966718b336125f85826783..e3d3e43716911bb52c5a16af9e23dbe3032963e3 100644 (file)
@@ -415,6 +415,8 @@ _kSecAssessmentAssessmentFromCache
 _kSecAssessmentAssessmentOriginator
 _kSecAssessmentAssessmentSource
 _kSecAssessmentAssessmentVerdict
+_kSecAssessmentAssessmentWeakSignature
+_kSecAssessmentAssessmentCodeSigningError
 _kSecAssessmentRuleKeyID
 _kSecAssessmentRuleKeyPriority
 _kSecAssessmentRuleKeyAllow
diff --git a/libsecurity_apple_csp/libsecurity_apple_csp.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_apple_csp/libsecurity_apple_csp.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..7e8cf9b
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0539107D0A37721E00B9E848</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_apple_cspdl/libsecurity_apple_cspdl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_apple_cspdl/libsecurity_apple_cspdl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_apple_file_dl/libsecurity_apple_file_dl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_apple_file_dl/libsecurity_apple_file_dl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_apple_x509_cl/libsecurity_apple_x509_cl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_apple_x509_cl/libsecurity_apple_x509_cl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..669930d
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C207F276053B21E600FF85CB</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_apple_x509_tp/libsecurity_apple_x509_tp.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_apple_x509_tp/libsecurity_apple_x509_tp.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_asn1/libsecurity_asn1.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_asn1/libsecurity_asn1.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..f262dc8
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>795CA7FE0D38013D00BAE6A2</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_authorization/libsecurity_authorization.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_authorization/libsecurity_authorization.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_cdsa_client/libsecurity_cdsa_client.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_cdsa_client/libsecurity_cdsa_client.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_cdsa_plugin/libsecurity_cdsa_plugin.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_cdsa_plugin/libsecurity_cdsa_plugin.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..7ebc9c5
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C2C38A530535EDE600D7421F</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_cdsa_utilities/libsecurity_cdsa_utilities.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_cdsa_utilities/libsecurity_cdsa_utilities.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..0bbe8b3
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA2A5390523D32800978A7B</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CF9C5B80535E557009B9B8D</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_cdsa_utils/libsecurity_cdsa_utils.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_cdsa_utils/libsecurity_cdsa_utils.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_checkpw/libsecurity_checkpw.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_checkpw/libsecurity_checkpw.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..c4b3b59
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>1C6C40211121FC0C00031CDE</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>1CD90B6611011176008DD07F</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_cms/libsecurity_cms.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_cms/libsecurity_cms.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
index 15f04c70fe3a1bb3dbd3d8de9dc4639e3336ba32..372592294a2912f0c1dd631cd969ebb0cbd67c85 100644 (file)
@@ -99,6 +99,16 @@ enum {
        errSecCSBadCallbackValue =                      -67020, /* monitor callback returned invalid value */
        errSecCSHelperFailed =                          -67019, /* the codesign_allocate helper tool cannot be found or used */
        errSecCSVetoed =                                        -67018,
+       errSecCSBadLVArch =                                     -67017, /* library validation flag cannot be used with an i386 binary */
+       errSecCSResourceNotSupported =          -67016, /* unsupported resource found (something not a directory, file or symlink) */
+       errSecCSRegularFile =                           -67015, /* the main executable or Info.plist must be a regular file (no symlinks, etc.) */
+       errSecCSUnsealedAppRoot =                       -67014, /* unsealed contents present in the bundle root */
+       errSecCSWeakResourceRules =                     -67013, /* resource envelope is obsolete */
+       errSecCSDSStoreSymlink =                        -67012, /* .DS_Store files cannot be a symlink */ 
+       errSecCSAmbiguousBundleFormat =         -67011, /* bundle format is ambiguous (could be app or framework) */
+       errSecCSBadMainExecutable =                     -67010, /* main executable failed strict validation */
+       errSecCSBadFrameworkVersion =           -67009, /* embedded framework contains modified or invalid version */
+       errSecCSUnsealedFrameworkRoot =         -67008, /* unsealed contents present in the root directory of an embedded framework */
 };
 
 
index 2e9862ea418e8f0458ad6d5efd70ac1872a2fb5e..68417ce6a5af9ce0e2c2f158ce5a90d57ea9a4b1 100644 (file)
@@ -48,9 +48,10 @@ static void esp_do_check(const char *op, CFDictionaryRef dict)
 //
 struct _SecAssessment : private CFRuntimeBase {
 public:
-       _SecAssessment(CFURLRef p, AuthorityType typ, CFDictionaryRef r) : path(p), type(typ), result(r) { }
+       _SecAssessment(CFURLRef p, AuthorityType typ, CFDictionaryRef c, CFDictionaryRef r) : path(p), context(c), type(typ), result(r) { }
        
        CFCopyRef<CFURLRef> path;
+       CFCopyRef<CFDictionaryRef> context;
        AuthorityType type;
        CFRef<CFDictionaryRef> result;
 
@@ -106,6 +107,8 @@ CFStringRef kSecAssessmentOperationTypeExecute = CFSTR("operation:execute");
 CFStringRef kSecAssessmentOperationTypeInstall = CFSTR("operation:install");
 CFStringRef kSecAssessmentOperationTypeOpenDocument = CFSTR("operation:lsopen");
 
+CFStringRef kSecAssessmentContextQuarantineFlags = CFSTR("context:qtnflags");
+
 
 //
 // Read-only in-process access to the policy database
@@ -134,6 +137,8 @@ CFStringRef kSecAssessmentAssessmentAuthorityRow = CFSTR("assessment:authority:r
 CFStringRef kSecAssessmentAssessmentAuthorityOverride = CFSTR("assessment:authority:override");
 CFStringRef kSecAssessmentAssessmentAuthorityOriginalVerdict = CFSTR("assessment:authority:verdict");
 CFStringRef kSecAssessmentAssessmentFromCache = CFSTR("assessment:authority:cached");
+CFStringRef kSecAssessmentAssessmentWeakSignature = CFSTR("assessment:authority:weak");
+CFStringRef kSecAssessmentAssessmentCodeSigningError = CFSTR("assessment:cserror");
 
 CFStringRef kDisabledOverride = CFSTR("security disabled");
 
@@ -161,7 +166,7 @@ SecAssessmentRef SecAssessmentCreate(CFURLRef path,
                // check the object cache first unless caller denied that or we need extended processing
                if (!(flags & (kSecAssessmentFlagRequestOrigin | kSecAssessmentFlagIgnoreCache))) {
                        if (gDatabase().checkCache(path, type, flags, result))
-                               return new SecAssessment(path, type, result.yield());
+                               return new SecAssessment(path, type, context, result.yield());
                }
                
                if (flags & kSecAssessmentFlagDirect) {
@@ -196,7 +201,7 @@ SecAssessmentRef SecAssessmentCreate(CFURLRef path,
                __esp_notify_ns("cs-assessment-evaluate", (void *)(CFDictionaryRef)dict);
        }
 
-       return new SecAssessment(path, type, result.yield());
+       return new SecAssessment(path, type, context, result.yield());
 
        END_CSAPI_ERRORS1(NULL)
 }
@@ -268,7 +273,7 @@ static void traceResult(CFURLRef target, MessageTrace &trace, std::string &sanit
        trace.add("signature3", "%s", sanitized.c_str());
        trace.add("signature5", "%s", version.c_str());
 }
-       
+
 static void traceAssessment(SecAssessment &assessment, AuthorityType type, CFDictionaryRef result)
 {
        if (CFDictionaryGetValue(result, CFSTR("assessment:remote")))
@@ -355,7 +360,9 @@ CFDictionaryRef SecAssessmentCopyResult(SecAssessmentRef assessmentRef,
                        result = adulterated.get();
                }
        }
-       traceAssessment(assessment, assessment.type, result);
+       bool trace = CFDictionaryContainsKey(assessment.context, kSecAssessmentContextQuarantineFlags);
+       if (trace)
+               traceAssessment(assessment, assessment.type, result);
        return result.yield();
 
        END_CSAPI_ERRORS1(NULL)
index 7c9e3ba6fb1b5d082d46be4763aaff655cdba34b..04a43bb4578edc5cfe1c5f7521f3a3baf824e7fd 100644 (file)
@@ -70,6 +70,8 @@ extern CFStringRef kSecAssessmentOperationTypeExecute;        // .. execute code
 extern CFStringRef kSecAssessmentOperationTypeInstall; // .. install software
 extern CFStringRef kSecAssessmentOperationTypeOpenDocument; // .. LaunchServices-level document open
 
+extern CFStringRef kSecAssessmentContextQuarantineFlags;
+
 
 /*!
        Operational flags for SecAssessment calls
@@ -84,6 +86,9 @@ extern CFStringRef kSecAssessmentOperationTypeOpenDocument; // .. LaunchServices
                Any content already there is left undisturbed. Independent of kSecAssessmentFlagIgnoreCache.
        @constant kSecAssessmentFlagEnforce Perform normal operations even if assessments have been
                globally bypassed (which would usually approve anything).
+       @constant kSecAssessmentAllowWeak Allow signatures that contain known weaknesses, such as an
+               insecure resource envelope.
+       @constant kSecAssessmentIgnoreWhitelist Do not search the weak signature whitelist.
        
        Flags common to multiple calls are assigned from high-bit down. Flags for particular calls
        are assigned low-bit up, and are documented with that call.
@@ -97,6 +102,8 @@ enum {
        kSecAssessmentFlagIgnoreCache = 1 << 28,                // do not search cache
        kSecAssessmentFlagNoCache = 1 << 27,                    // do not populate cache
        kSecAssessmentFlagEnforce = 1 << 26,                    // force on (disable bypass switches)
+       kSecAssessmentFlagAllowWeak = 1 << 25,                  // allow weak signatures
+       kSecAssessmentFlagIgnoreWhitelist = 1 << 24,    // do not search weak signature whitelist
 };
 
 
@@ -130,6 +137,8 @@ extern CFStringRef kSecAssessmentAssessmentOriginator;      // CFStringRef: describin
 extern CFStringRef kSecAssessmentAssessmentAuthority;  // CFDictionaryRef: authority used to arrive at result
 extern CFStringRef kSecAssessmentAssessmentSource;             // CFStringRef: primary source of authority
 extern CFStringRef kSecAssessmentAssessmentFromCache;  // present if result is from cache
+extern CFStringRef kSecAssessmentAssessmentWeakSignature; // present if result attributable to signature weakness
+extern CFStringRef kSecAssessmentAssessmentCodeSigningError; // error code returned by code signing API
 extern CFStringRef kSecAssessmentAssessmentAuthorityRow; // (internal)
 extern CFStringRef kSecAssessmentAssessmentAuthorityOverride; // (internal)
 extern CFStringRef kSecAssessmentAssessmentAuthorityOriginalVerdict; // (internal)
index a705ba7180d281eddd7f1781c1e8d8b5372ef8c8..8fed4b1dbd2e153f511bf0a828ec808eaabdc6e9 100644 (file)
@@ -91,7 +91,9 @@ OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags,
                | kSecCSSignNestedCode
                | kSecCSSignOpaque
                | kSecCSSignV1
-               | kSecCSSignNoV1);
+               | kSecCSSignNoV1
+               | kSecCSSignBundleRoot
+               | kSecCSSignStrictPreflight);
        SecPointer<SecCodeSigner> signer = new SecCodeSigner(flags);
        signer->parameters(parameters);
        CodeSigning::Required(signerRef) = signer->handle();
index d5c15962eb9523382b8ed1c8023ed3578a0d57de..f34f273bca17ef24d2800788cc47691857d73a55 100644 (file)
@@ -190,6 +190,8 @@ enum {
        kSecCSSignOpaque = 1 << 3,                      // treat all files as resources (no nest scan, no flexibility)
        kSecCSSignV1 = 1 << 4,                          // sign ONLY in V1 form
        kSecCSSignNoV1 = 1 << 5,                        // do not include V1 form
+       kSecCSSignBundleRoot = 1 << 6,          // include files in bundle root
+       kSecCSSignStrictPreflight = 1 << 7, // fail signing operation if signature would fail strict validation
 };
 
 
index f0a67ccccc0894367b6ef817107a8f25054bdf31..ee14ed9cdbb78a3feac0902a56ab1a6df4518b94 100644 (file)
@@ -112,7 +112,8 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se
                | kSecCSDoNotValidateResources
                | kSecCSConsiderExpiration
                | kSecCSEnforceRevocationChecks
-               | kSecCSCheckNestedCode);
+               | kSecCSCheckNestedCode
+               | kSecCSStrictValidate);
 
        SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
        const SecRequirement *req = SecRequirement::optional(requirementRef);
@@ -141,7 +142,7 @@ OSStatus SecCodeCopyPath(SecStaticCodeRef staticCodeRef, SecCSFlags flags, CFURL
        
        checkFlags(flags);
        SecPointer<SecStaticCode> staticCode = SecStaticCode::requiredStatic(staticCodeRef);
-       CodeSigning::Required(path) = staticCode->canonicalPath();
+       CodeSigning::Required(path) = staticCode->copyCanonicalPath();
 
        END_CSAPI
 }
@@ -233,3 +234,15 @@ OSStatus SecStaticCodeSetCallback(SecStaticCodeRef codeRef, SecCSFlags flags, Se
 
        END_CSAPI
 }
+
+
+OSStatus SecStaticCodeSetValidationConditions(SecStaticCodeRef codeRef, CFDictionaryRef conditions)
+{
+       BEGIN_CSAPI
+       
+       checkFlags(0);
+       SecStaticCode *code = SecStaticCode::requiredStatic(codeRef);
+       code->setValidationModifiers(conditions);
+       
+       END_CSAPI
+}
index ba083b41f4bc16bd2fada1197ad6bc8b43a20b32..8e5f8c202a6c92e7fc43aeab36fa2297ee6748ca 100644 (file)
@@ -125,6 +125,10 @@ OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flag
        @constant kSecCSCheckNestedCode
        For code in bundle form, locate and recursively check embedded code. Only code
        in standard locations is considered.
+       @constant kSecCSStrictValidate
+       For code in bundle form, perform additional checks to verify that the bundle
+       is not structured in a way that would allow tampering, and reject any resource
+       envelope that introduces weaknesses into the signature.
        
        @param requirement On optional code requirement specifying additional conditions
        the staticCode object must satisfy to be considered valid. If NULL, no additional
@@ -142,6 +146,7 @@ enum {
        kSecCSDoNotValidateResources = 1 << 2,
        kSecCSBasicValidateOnly = kSecCSDoNotValidateExecutable | kSecCSDoNotValidateResources,
        kSecCSCheckNestedCode = 1 << 3,
+       kSecCSStrictValidate = 1 << 4,
 };
 
 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags,
index e40f0dfa120b7d98492042c22fff89e331d215d0..ccd9d2b50d09cd7b86b497ed8c1e98306ae1391e 100644 (file)
@@ -58,6 +58,18 @@ extern "C" {
  */
 OSStatus SecStaticCodeSetCallback(SecStaticCodeRef code, SecCSFlags flag, SecCodeCallback *olds, SecCodeCallback callback);
 
+       
+/*
+       @function SecStaticCodeSetValidationConditions
+       Set various parameters that modify the evaluation of a signature.
+       This is an internal affordance used by Gatekeeper to implement checkfix evaluation.
+       It is not meant to be a generally useful mechanism.
+       @param code A Code or StaticCode object whose validation should be modified.
+       @param conditions A dictionary containing one or more validation conditions. Must not be NULL.
+ */
+OSStatus SecStaticCodeSetValidationConditions(SecStaticCodeRef code, CFDictionaryRef conditions);
+
 
 #ifdef __cplusplus
 }
index 2f6b48d2eeb344511ada813abcb52e7f41c76a3c..446647adc5b16d82879bd34dcad8fa49308367e9 100644 (file)
@@ -35,6 +35,7 @@
 #include "detachedrep.h"
 #include "csdatabase.h"
 #include "csutilities.h"
+#include "dirscanner.h"
 #include <CoreFoundation/CFURLAccess.h>
 #include <Security/SecPolicyPriv.h>
 #include <Security/SecTrustPriv.h>
@@ -48,6 +49,8 @@
 #include <security_utilities/cfmunge.h>
 #include <Security/CMSDecoder.h>
 #include <security_utilities/logging.h>
+#include <dirent.h>
+#include <sstream>
 
 
 namespace Security {
@@ -117,7 +120,7 @@ bool SecStaticCode::equal(SecCFObject &secOther)
        if (mine || his)
                return mine && his && CFEqual(mine, his);
        else
-               return CFEqual(this->canonicalPath(), other->canonicalPath());
+               return CFEqual(CFRef<CFURLRef>(this->copyCanonicalPath()), CFRef<CFURLRef>(other->copyCanonicalPath()));
 }
 
 CFHashCode SecStaticCode::hash()
@@ -125,7 +128,7 @@ CFHashCode SecStaticCode::hash()
        if (CFDataRef h = this->cdHash())
                return CFHash(h);
        else
-               return CFHash(this->canonicalPath());
+               return CFHash(CFRef<CFURLRef>(this->copyCanonicalPath()));
 }
 
 
@@ -139,6 +142,30 @@ CFTypeRef SecStaticCode::reportEvent(CFStringRef stage, CFDictionaryRef info)
        else
                return NULL;
 }
+       
+       
+//
+// Set validation conditions for fine-tuning legacy tolerance
+//
+static void addError(CFTypeRef cfError, void* context)
+{
+       if (CFGetTypeID(cfError) == CFNumberGetTypeID()) {
+               int64_t error;
+               CFNumberGetValue(CFNumberRef(cfError), kCFNumberSInt64Type, (void*)&error);
+               MacOSErrorSet* errors = (MacOSErrorSet*)context;
+               errors->insert(OSStatus(error));
+       }
+}
+
+void SecStaticCode::setValidationModifiers(CFDictionaryRef conditions)
+{
+       if (conditions) {
+               CFDictionary source(conditions, errSecCSDbCorrupt);
+               mAllowOmissions = source.get<CFArrayRef>("omissions");
+               if (CFArrayRef errors = source.get<CFArrayRef>("errors"))
+                       CFArrayApplyFunction(errors, CFRangeMake(0, CFArrayGetCount(errors)), addError, &this->mTolerateErrors);
+       }
+}
 
 
 //
@@ -691,7 +718,7 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                try {
                        // sanity first
                        CFDictionaryRef sealedResources = resourceDictionary();
-                       if (this->resourceBase())               // disk has resources
+                       if (this->resourceBase())       // disk has resources
                                if (sealedResources)
                                        /* go to work below */;
                                else
@@ -722,11 +749,17 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                        }
                        if (!rules || !files)
                                MacOSError::throwMe(errSecCSResourcesInvalid);
+                       // check for weak resource rules
+                       bool strict = flags & kSecCSStrictValidate;
+                       if (strict && (version == 1 || hasWeakResourceRules(rules, mAllowOmissions)))
+                               if (mTolerateErrors.find(errSecCSWeakResourceRules) == mTolerateErrors.end())
+                                       MacOSError::throwMe(errSecCSWeakResourceRules);
                        __block CFRef<CFMutableDictionaryRef> resourceMap = makeCFMutableDictionary(files);
-                       ResourceBuilder resources(cfString(this->resourceBase()), rules, codeDirectory()->hashType);
+                       string base = cfString(this->resourceBase());
+                       ResourceBuilder resources(base, base, rules, codeDirectory()->hashType, strict, mTolerateErrors);
                        diskRep()->adjustResources(resources);
                        resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, ResourceBuilder::Rule *rule) {
-                               validateResource(files, relpath, *mResourcesValidContext, flags, version);
+                               validateResource(files, relpath, ent->fts_info == FTS_SL, *mResourcesValidContext, flags, version);
                                CFDictionaryRemoveValue(resourceMap, CFTempString(relpath));
                        });
                        
@@ -776,6 +809,42 @@ void SecStaticCode::checkOptionalResource(CFTypeRef key, CFTypeRef value, void *
 }
 
 
+static bool isOmitRule(CFTypeRef value)
+{
+       if (CFGetTypeID(value) == CFBooleanGetTypeID())
+               return value == kCFBooleanFalse;
+       CFDictionary rule(value, errSecCSResourceRulesInvalid);
+       return rule.get<CFBooleanRef>("omit") == kCFBooleanTrue;
+}
+
+bool SecStaticCode::hasWeakResourceRules(CFDictionaryRef rulesDict, CFArrayRef allowedOmissions)
+{
+       // compute allowed omissions
+       CFRef<CFArrayRef> defaultOmissions = this->diskRep()->allowedResourceOmissions();
+       assert(defaultOmissions);
+       CFRef<CFMutableArrayRef> allowed = CFArrayCreateMutableCopy(NULL, 0, defaultOmissions);
+       if (allowedOmissions)
+               CFArrayAppendArray(allowed, allowedOmissions, CFRangeMake(0, CFArrayGetCount(allowedOmissions)));
+       CFRange range = CFRangeMake(0, CFArrayGetCount(allowed));
+       
+       // check all resource rules for weakness
+       __block bool coversAll = false;
+       __block bool forbiddenOmission = false;
+       CFDictionary rules(rulesDict, errSecCSResourceRulesInvalid);
+       rules.apply(^(CFStringRef key, CFTypeRef value) {
+               string pattern = cfString(key, errSecCSResourceRulesInvalid);
+               if (pattern == "^.*" && value == kCFBooleanTrue) {
+                       coversAll = true;
+                       return;
+               }
+               if (isOmitRule(value))
+                       forbiddenOmission |= !CFArrayContainsValue(allowed, range, key);
+       });
+
+       return !coversAll || forbiddenOmission;
+}
+
+
 //
 // Load, validate, cache, and return CFDictionary forms of sealed resources.
 //
@@ -909,7 +978,7 @@ CFDataRef SecStaticCode::resource(string path)
 }
 
 
-void SecStaticCode::validateResource(CFDictionaryRef files, string path, ValidationContext &ctx, SecCSFlags flags, uint32_t version)
+void SecStaticCode::validateResource(CFDictionaryRef files, string path, bool isSymlink, ValidationContext &ctx, SecCSFlags flags, uint32_t version)
 {
        if (!resourceBase())    // no resources in DiskRep
                MacOSError::throwMe(errSecCSResourcesNotFound);
@@ -917,7 +986,12 @@ void SecStaticCode::validateResource(CFDictionaryRef files, string path, Validat
        if (CFTypeRef file = CFDictionaryGetValue(files, CFTempString(path))) {
                ResourceSeal seal = file;
                if (seal.nested()) {
-                       validateNestedCode(fullpath, seal, flags);
+                       if (isSymlink)
+                               return ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAltered, fullpath); // changed type
+                       string suffix = ".framework";
+                       bool isFramework = (path.length() > suffix.length())
+                               && (path.compare(path.length()-suffix.length(), suffix.length(), suffix) == 0);
+                       validateNestedCode(fullpath, seal, flags, isFramework);
                } else if (seal.link()) {
                        char target[PATH_MAX];
                        ssize_t len = ::readlink(cfString(fullpath).c_str(), target, sizeof(target)-1);
@@ -953,7 +1027,7 @@ void SecStaticCode::validateResource(CFDictionaryRef files, string path, Validat
        ctx.reportProblem(errSecCSBadResource, kSecCFErrorResourceAdded, CFTempURL(path, false, resourceBase()));
 }
 
-void SecStaticCode::validateNestedCode(CFURLRef path, const ResourceSeal &seal, SecCSFlags flags)
+void SecStaticCode::validateNestedCode(CFURLRef path, const ResourceSeal &seal, SecCSFlags flags, bool isFramework)
 {
        CFRef<SecRequirementRef> req;
        if (SecRequirementCreateWithString(seal.requirement(), kSecCSDefaultFlags, &req.aref()))
@@ -966,6 +1040,16 @@ void SecStaticCode::validateNestedCode(CFURLRef path, const ResourceSeal &seal,
                SecPointer<SecStaticCode> code = new SecStaticCode(DiskRep::bestGuess(cfString(path)));
                code->setMonitor(this->monitor());
                code->staticValidate(flags, SecRequirement::required(req));
+
+               if (isFramework && (flags & kSecCSStrictValidate))
+                       try {
+                               validateOtherVersions(path, flags, req, code);
+                       } catch (const CSError &err) {
+                               MacOSError::throwMe(errSecCSBadFrameworkVersion);
+                       } catch (const MacOSError &err) {
+                               MacOSError::throwMe(errSecCSBadFrameworkVersion);
+                       }
+
        } catch (CSError &err) {
                if (err.error == errSecCSReqFailed) {
                        mResourcesValidContext->reportProblem(errSecCSBadNestedCode, kSecCFErrorResourceAltered, path);
@@ -982,6 +1066,52 @@ void SecStaticCode::validateNestedCode(CFURLRef path, const ResourceSeal &seal,
        }
 }
 
+void SecStaticCode::validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRequirementRef req, SecStaticCode *code)
+{
+       // Find out what current points to and do not revalidate
+       std::string mainPath = cfStringRelease(code->diskRep()->copyCanonicalPath());
+
+       char main_path[PATH_MAX];
+       bool foundTarget = false;
+
+       /* If it failed to get the target of the symlink, do not fail. It is a performance loss,
+        not a security hole */
+       if (realpath(mainPath.c_str(), main_path) != NULL)
+               foundTarget = true;
+
+       std::ostringstream versionsPath;
+       versionsPath << cfString(path) << "/Versions/";
+
+       DirScanner scanner(versionsPath.str());
+
+       if (scanner.initialized()) {
+               struct dirent *entry = NULL;
+               while ((entry = scanner.getNext()) != NULL) {
+                       std::ostringstream fullPath;
+
+                       if (entry->d_type != DT_DIR ||
+                               strcmp(entry->d_name, ".") == 0 ||
+                               strcmp(entry->d_name, "..") == 0 ||
+                               strcmp(entry->d_name, "Current") == 0)
+                               continue;
+
+                       fullPath << versionsPath.str() << entry->d_name;
+
+                       char real_full_path[PATH_MAX];
+                       if (realpath(fullPath.str().c_str(), real_full_path) == NULL)
+                               UnixError::check(-1);
+
+                       // Do case insensitive comparions because realpath() was called for both paths
+                       if (foundTarget && strcmp(main_path, real_full_path) == 0)
+                               continue;
+
+                       SecPointer<SecStaticCode> frameworkVersion = new SecStaticCode(DiskRep::bestGuess(real_full_path));
+                       frameworkVersion->setMonitor(this->monitor());
+                       frameworkVersion->staticValidate(flags, SecRequirement::required(req));
+               }
+       }
+}
+
 
 //
 // Test a CodeDirectory flag.
@@ -1318,10 +1448,17 @@ void SecStaticCode::staticValidate(SecCSFlags flags, const SecRequirement *req)
                        subcode->staticValidateCore(flags, req);
                });
        
+       // allow monitor intervention in source validation phase
+       reportEvent(CFSTR("prepared"), NULL);
+       
        // resources: once for all architectures
        if (!(flags & kSecCSDoNotValidateResources))
                this->validateResources(flags);
 
+       // perform strict validation if desired
+       if (flags & kSecCSStrictValidate)
+               mRep->strictValidate(mTolerateErrors);
+
        // allow monitor intervention
        if (CFRef<CFTypeRef> veto = reportEvent(CFSTR("validated"), NULL)) {
                if (CFGetTypeID(veto) == CFNumberGetTypeID())
@@ -1375,6 +1512,9 @@ void SecStaticCode::handleOtherArchitectures(void (^handle)(SecStaticCode* other
                        size_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(errSecCSInternalError);
+                               ctx.size = fat->lengthOfSlice((size_t)ctx.offset);
                                if (ctx.offset != activeOffset) {       // inactive architecture; check it
                                        SecPointer<SecStaticCode> subcode = new SecStaticCode(DiskRep::bestGuess(this->mainExecutablePath(), &ctx));
                                        subcode->detachedSignature(this->mDetachedSig); // carry over explicit (but not implicit) detached signature
index b7c5b72aa3699f8f534744ba4bf7abe6b231bc84..29816541fbd38cd0e4285dd58565e3e13ad3ccfb 100644 (file)
@@ -117,7 +117,7 @@ public:
        DiskRep *diskRep() { return mRep; }
        bool isDetached() const { return mRep->base() != mRep; }
        std::string mainExecutablePath() { return mRep->mainExecutablePath(); }
-       CFURLRef canonicalPath() const { return mRep->canonicalPath(); }
+       CFURLRef copyCanonicalPath() const { return mRep->copyCanonicalPath(); }
        std::string identifier() { return codeDirectory()->identifier(); }
        const char *teamID() { return codeDirectory()->teamID(); }
        std::string format() const { return mRep->format(); }
@@ -131,7 +131,7 @@ public:
        CFURLRef resourceBase();
        CFDataRef resource(std::string path);
        CFDataRef resource(std::string path, ValidationContext &ctx);
-       void validateResource(CFDictionaryRef files, std::string path, ValidationContext &ctx, SecCSFlags flags, uint32_t version);
+       void validateResource(CFDictionaryRef files, std::string path, bool isSymlink, ValidationContext &ctx, SecCSFlags flags, uint32_t version);
        
        bool flag(uint32_t tested);
 
@@ -139,6 +139,8 @@ public:
        void setMonitor(SecCodeCallback monitor) { mMonitor = monitor; }
        CFTypeRef reportEvent(CFStringRef stage, CFDictionaryRef info);
        
+       void setValidationModifiers(CFDictionaryRef modifiers);
+       
        void resetValidity();                                           // clear validation caches (if something may have changed)
        
        bool validated() const  { return mValidated; }
@@ -152,7 +154,7 @@ public:
        void validateNonResourceComponents();
        void validateResources(SecCSFlags flags);
        void validateExecutable();
-       void validateNestedCode(CFURLRef path, const ResourceSeal &seal, SecCSFlags flags);
+       void validateNestedCode(CFURLRef path, const ResourceSeal &seal, SecCSFlags flags, bool isFramework);
        
        const Requirements *internalRequirements();
        const Requirement *internalRequirement(SecRequirementType type);
@@ -182,13 +184,21 @@ protected:
        CFTypeRef verificationPolicy(SecCSFlags flags);
 
        static void checkOptionalResource(CFTypeRef key, CFTypeRef value, void *context);
+       bool hasWeakResourceRules(CFDictionaryRef rulesDict, CFArrayRef allowedOmissions);
 
        void handleOtherArchitectures(void (^handle)(SecStaticCode* other));
 
+private:
+       void validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRequirementRef req, SecStaticCode *code);
+
 private:
        RefPointer<DiskRep> mRep;                       // on-disk representation
        CFRef<CFDataRef> mDetachedSig;          // currently applied explicit detached signature
        
+       // private validation modifiers (only used by Gatekeeper checkfixes)
+       MacOSErrorSet mTolerateErrors;          // soft error conditions to ignore
+       CFRef<CFArrayRef> mAllowOmissions;      // additionally allowed resource omissions
+       
        // master validation state
        bool mValidated;                                        // core validation was attempted
        OSStatus mValidationResult;                     // outcome of core validation
index 41423fafe531e3e1dfca25955fdcda755c607f88..636e213a0e20106f36aeb284e3047dad8932f36e 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include "bundlediskrep.h"
 #include "filediskrep.h"
+#include "dirscanner.h"
 #include <CoreFoundation/CFURLAccess.h>
 #include <CoreFoundation/CFBundlePriv.h>
 #include <security_utilities/cfmunge.h>
@@ -68,22 +69,36 @@ BundleDiskRep::~BundleDiskRep()
 void BundleDiskRep::setup(const Context *ctx)
 {
        mInstallerPackage = false;      // default
-       
-       // deal with versioned bundles (aka Frameworks)
-       string version = resourcesRootPath()
-               + "/Versions/"
+
+       // capture the path of the main executable before descending into a specific version
+       CFRef<CFURLRef> mainExecBefore = CFBundleCopyExecutableURL(mBundle);
+
+       // validate the bundle root; fish around for the desired framework version
+       string root = cfStringRelease(copyCanonicalPath());
+       string contents = root + "/Contents";
+       string version = root + "/Versions/"
                + ((ctx && ctx->version) ? ctx->version : "Current")
                + "/.";
-       if (::access(version.c_str(), F_OK) == 0) {             // versioned bundle
+       if (::access(contents.c_str(), F_OK) == 0) {    // not shallow
+               DirValidator val;
+               val.require("^Contents$", DirValidator::directory);      // duh
+               val.allow("^(\\.LSOverride|\\.DS_Store|Icon\r|\\.SoftwareDepot\\.tracking)$", DirValidator::file | DirValidator::noexec);
+               try {
+                       val.validate(root, errSecCSUnsealedAppRoot);
+               } catch (const MacOSError &err) {
+                       recordStrictError(err.error);
+               }
+       } else if (::access(version.c_str(), F_OK) == 0) {      // versioned bundle
                if (CFBundleRef versionBundle = CFBundleCreate(NULL, CFTempURL(version)))
                        mBundle.take(versionBundle);    // replace top bundle ref
                else
                        MacOSError::throwMe(errSecCSStaticCodeNotFound);
+               validateFrameworkRoot(root);
        } else {
                if (ctx && ctx->version)        // explicitly specified
                        MacOSError::throwMe(errSecCSStaticCodeNotFound);
        }
-       
+
        CFDictionaryRef infoDict = CFBundleGetInfoDictionary(mBundle);
        assert(infoDict);       // CFBundle will always make one up for us
        CFTypeRef mainHTML = CFDictionaryGetValue(infoDict, CFSTR("MainHTML"));
@@ -92,8 +107,28 @@ void BundleDiskRep::setup(const Context *ctx)
        // conventional executable bundle: CFBundle identifies an executable for us
        if (CFRef<CFURLRef> mainExec = CFBundleCopyExecutableURL(mBundle))              // if CFBundle claims an executable...
                if (mainHTML == NULL) {                                                                                         // ... and it's not a widget
+
+                       // Note that this check is skipped if there is a specific framework version checked.
+                       // That's because you know what you are doing if you are looking at a specific version.
+                       // This check is designed to stop someone who did a verification on an app root, from mistakenly
+                       // verifying a framework
+                       if (mainExecBefore && (!ctx || !ctx->version)) {
+                               char main_exec_before[PATH_MAX];
+                               char main_exec[PATH_MAX];
+                               // The realpath call is important because alot of Framework bundles have a symlink
+                               // to their "Current" version binary in the main bundle
+                               if (realpath(cfString(mainExecBefore).c_str(), main_exec_before) == NULL ||
+                                       realpath(cfString(mainExec).c_str(), main_exec) == NULL)
+                                       MacOSError::throwMe(errSecCSInternalError);
+
+                               if (strcmp(main_exec_before, main_exec) != 0)
+                                       recordStrictError(errSecCSAmbiguousBundleFormat);
+                       }
+
                        mMainExecutableURL = mainExec;
                        mExecRep = DiskRep::bestFileGuess(this->mainExecutablePath(), ctx);
+                       if (!mExecRep->fd().isPlainFile(this->mainExecutablePath()))
+                               recordStrictError(errSecCSRegularFile);
                        mFormat = "bundle with " + mExecRep->format();
                        return;
                }
@@ -107,6 +142,8 @@ void BundleDiskRep::setup(const Context *ctx)
                if (!mMainExecutableURL)
                        MacOSError::throwMe(errSecCSBadBundleFormat);
                mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
+               if (!mExecRep->fd().isPlainFile(this->mainExecutablePath()))
+                       recordStrictError(errSecCSRegularFile);
                mFormat = "widget bundle";
                return;
        }
@@ -116,6 +153,8 @@ void BundleDiskRep::setup(const Context *ctx)
                // focus on the Info.plist (which we know exists) as the nominal "main executable" file
                mMainExecutableURL = infoURL;
                mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
+               if (!mExecRep->fd().isPlainFile(this->mainExecutablePath()))
+                       recordStrictError(errSecCSRegularFile);
                if (packageVersion) {
                        mInstallerPackage = true;
                        mFormat = "installer package bundle";
@@ -130,6 +169,8 @@ void BundleDiskRep::setup(const Context *ctx)
        if (!distFile.empty()) {
                mMainExecutableURL = makeCFURL(distFile);
                mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
+               if (!mExecRep->fd().isPlainFile(this->mainExecutablePath()))
+                       recordStrictError(errSecCSRegularFile);
                mInstallerPackage = true;
                mFormat = "installer package bundle";
                return;
@@ -206,7 +247,7 @@ void BundleDiskRep::createMeta()
        string meta = metaPath(BUNDLEDISKREP_DIRECTORY);
        if (!mMetaExists) {
                if (::mkdir(meta.c_str(), 0755) == 0) {
-                       copyfile(cfString(canonicalPath(), true).c_str(), meta.c_str(), NULL, COPYFILE_SECURITY);
+                       copyfile(cfStringRelease(copyCanonicalPath()).c_str(), meta.c_str(), NULL, COPYFILE_SECURITY);
                        mMetaPath = meta;
                        mMetaExists = true;
                } else if (errno != EEXIST)
@@ -214,6 +255,31 @@ void BundleDiskRep::createMeta()
        }
 }
 
+//
+// Load's a CFURL and makes sure that it is a regular file and not a symlink (or fifo, etc.)
+//
+CFDataRef BundleDiskRep::loadRegularFile(CFURLRef url)
+{
+       assert(url);
+
+       CFDataRef data = NULL;
+
+       std::string path(cfString(url));
+
+       AutoFileDesc fd(path);
+
+       if (!fd.isPlainFile(path))
+               recordStrictError(errSecCSRegularFile);
+
+       data = cfLoadFile(fd, fd.fileSize());
+
+       if (!data) {
+               secdebug(__PRETTY_FUNCTION__, "failed to load %s", cfString(url).c_str());
+               MacOSError::throwMe(errSecCSInternalError);
+       }
+
+       return data;
+}
 
 //
 // Load and return a component, by slot number.
@@ -228,7 +294,7 @@ CFDataRef BundleDiskRep::component(CodeDirectory::SpecialSlot slot)
        // the Info.plist comes from the magic CFBundle-indicated place and ONLY from there
        case cdInfoSlot:
                if (CFRef<CFURLRef> info = _CFBundleCopyInfoPlistURL(mBundle))
-                       return cfLoadFile(info);
+                       return loadRegularFile(info);
                else
                        return NULL;
        // by default, we take components from the executable image or files
@@ -258,7 +324,7 @@ CFDataRef BundleDiskRep::identification()
 //
 // Various aspects of our DiskRep personality.
 //
-CFURLRef BundleDiskRep::canonicalPath()
+CFURLRef BundleDiskRep::copyCanonicalPath()
 {
        if (CFURLRef url = CFBundleCopyBundleURL(mBundle))
                return url;
@@ -361,10 +427,10 @@ string BundleDiskRep::recommendedIdentifier(const SigningContext &)
                        return cfString(identifier);
        
        // fall back to using the canonical path
-       return canonicalIdentifier(cfString(this->canonicalPath()));
+       return canonicalIdentifier(cfStringRelease(this->copyCanonicalPath()));
 }
 
-CFDictionaryRef BundleDiskRep::defaultResourceRules(const SigningContext &ctx)
+string BundleDiskRep::resourcesRelativePath()
 {
        // figure out the resource directory base. Clean up some gunk inserted by CFBundle in frameworks
        string rbase = this->resourcesRootPath();
@@ -385,6 +451,13 @@ CFDictionaryRef BundleDiskRep::defaultResourceRules(const SigningContext &ctx)
        else
                resources = resources.substr(rbase.length() + 1) + "/"; // differential path segment
 
+       return resources;
+}
+
+CFDictionaryRef BundleDiskRep::defaultResourceRules(const SigningContext &ctx)
+{
+       string resources = this->resourcesRelativePath();
+
        // installer package rules
        if (mInstallerPackage)
                return cfmake<CFDictionaryRef>("{rules={"
@@ -447,6 +520,20 @@ CFDictionaryRef BundleDiskRep::defaultResourceRules(const SigningContext &ctx)
        );
 }
 
+
+CFArrayRef BundleDiskRep::allowedResourceOmissions()
+{
+       return cfmake<CFArrayRef>("["
+               "'^(.*/)?\\.DS_Store$'"
+               "'^Info\\.plist$'"
+               "'^PkgInfo$'"
+               "%s"
+               "]",
+               (string("^") + this->resourcesRelativePath() + ".*\\.lproj/locversion.plist$").c_str()
+       );
+}
+
+
 const Requirements *BundleDiskRep::defaultRequirements(const Architecture *arch, const SigningContext &ctx)
 {
        return mExecRep->defaultRequirements(arch, ctx);
@@ -458,6 +545,61 @@ size_t BundleDiskRep::pageSize(const SigningContext &ctx)
 }
 
 
+//
+// Strict validation.
+// Takes an array of CFNumbers of errors to tolerate.
+//
+void BundleDiskRep::strictValidate(const ToleratedErrors& tolerated)
+{
+       std::vector<OSStatus> fatalErrors;
+       set_difference(mStrictErrors.begin(), mStrictErrors.end(), tolerated.begin(), tolerated.end(), back_inserter(fatalErrors));
+       if (!fatalErrors.empty())
+               MacOSError::throwMe(fatalErrors[0]);
+       mExecRep->strictValidate(tolerated);
+}
+
+void BundleDiskRep::recordStrictError(OSStatus error)
+{
+       mStrictErrors.insert(error);
+}
+
+
+//
+// Check framework root for unsafe symlinks and unsealed content.
+//
+void BundleDiskRep::validateFrameworkRoot(string root)
+{
+       // build regex element that matches either the "Current" symlink, or the name of the current version
+       string current = "Current";
+       char currentVersion[PATH_MAX];
+       ssize_t len = ::readlink((root + "/Versions/Current").c_str(), currentVersion, sizeof(currentVersion)-1);
+       if (len > 0) {
+               currentVersion[len] = '\0';
+               current = string("(Current|") + ResourceBuilder::escapeRE(currentVersion) + ")";
+       }
+
+       DirValidator val;
+       val.require("^Versions$", DirValidator::directory | DirValidator::descend);     // descend into Versions directory
+       val.require("^Versions/[^/]+$", DirValidator::directory);                                       // require at least one version
+       val.require("^Versions/Current$", DirValidator::symlink,                                        // require Current symlink...
+               "^(\\./)?(\\.\\.[^/]+|\\.?[^\\./][^/]*)$");                                                             // ...must point to a version
+       val.allow("^(Versions/)?\\.DS_Store$", DirValidator::file | DirValidator::noexec); // allow .DS_Store files
+       val.allow("^[^/]+$", DirValidator::symlink, ^ string (const string &name, const string &target) {
+               // top-level symlinks must point to namesake in current version
+               return string("^(\\./)?Versions/") + current + "/" + ResourceBuilder::escapeRE(name) + "$";
+       });
+       // module.map must be regular non-executable file, or symlink to module.map in current version
+       val.allow("^module\\.map$", DirValidator::file | DirValidator::noexec | DirValidator::symlink,
+               string("^(\\./)?Versions/") + current + "/module\\.map$");
+
+       try {
+               val.validate(root, errSecCSUnsealedFrameworkRoot);
+       } catch (const MacOSError &err) {
+               recordStrictError(err.error);
+       }
+}
+
+
 //
 // Writers
 //
index 6dfb12fb805d3cc95660c511e6cc21a9e3ae1820..a697237ae899ffedc44c00d2060e6fc0b5ad5641 100644 (file)
@@ -56,8 +56,9 @@ public:
        CFDataRef component(CodeDirectory::SpecialSlot slot);
        CFDataRef identification();
        std::string mainExecutablePath();
-       CFURLRef canonicalPath();
+       CFURLRef copyCanonicalPath();
        std::string resourcesRootPath();
+       std::string resourcesRelativePath();
        void adjustResources(ResourceBuilder &builder);
        Universal *mainExecutableImage();
        size_t signingBase();
@@ -72,6 +73,9 @@ public:
        const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx);
        size_t pageSize(const SigningContext &ctx);
 
+       void strictValidate(const ToleratedErrors& tolerated);
+       CFArrayRef allowedResourceOmissions();
+
        CFBundleRef bundle() const { return mBundle; }
        
 public:
@@ -87,6 +91,9 @@ protected:
 private:
        void setup(const Context *ctx);                 // shared init
        void checkModifiedFile(CFMutableArrayRef files, CodeDirectory::SpecialSlot slot);
+       CFDataRef loadRegularFile(CFURLRef url);
+       void recordStrictError(OSStatus error);
+       void validateFrameworkRoot(std::string root);
 
 private:
        CFRef<CFBundleRef> mBundle;
@@ -96,6 +103,7 @@ private:
        bool mInstallerPackage;                                 // is an installer (not executable) bundle
        string mFormat;                                                 // format description string
        RefPointer<DiskRep> mExecRep;                   // DiskRep for main executable file
+       std::set<OSStatus> mStrictErrors;               // strict validation errors encountered
 };
 
 
diff --git a/libsecurity_codesigning/lib/dirscanner.cpp b/libsecurity_codesigning/lib/dirscanner.cpp
new file mode 100644 (file)
index 0000000..12756ab
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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 <dirent.h>
+#include <unistd.h>
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/debugging.h>
+#include "dirscanner.h"
+
+namespace Security {
+namespace CodeSigning {
+
+
+DirScanner::DirScanner(const char *path)
+       : init(false)
+{
+       this->path = std::string(path);
+       this->initialize();
+}
+
+DirScanner::DirScanner(string path)
+       : init(false)
+{
+       this->path = path;
+       this->initialize();
+}
+
+DirScanner::~DirScanner()
+{
+        if (this->dp != NULL)
+                (void) closedir(this->dp);
+}
+
+void DirScanner::initialize()
+{
+       if (this->dp == NULL) {
+               errno = 0;
+               if ((this->dp = opendir(this->path.c_str())) == NULL) {
+                       if (errno == ENOENT) {
+                               init = false;
+                       } else {
+                               UnixError::check(-1);
+                       }
+               } else
+                       init = true;
+       } else
+               MacOSError::throwMe(errSecInternalError);
+}
+
+struct dirent * DirScanner::getNext()
+{
+       return readdir(this->dp);
+}
+
+bool DirScanner::initialized()
+{
+       return this->init;
+}
+
+
+DirValidator::~DirValidator()
+{
+       for (Rules::iterator it = mRules.begin(); it != mRules.end(); ++it)
+               delete *it;
+}
+
+void DirValidator::validate(const string &root, OSStatus error)
+{
+       std::set<Rule *> reqMatched;
+       FTS fts(root);
+       while (FTSENT *ent = fts_read(fts)) {
+               const char *relpath = ent->fts_path + root.size() + 1;  // skip prefix + "/"
+               bool executable = ent->fts_statp->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH);
+               Rule *rule = NULL;
+               switch (ent->fts_info) {
+               case FTS_F:
+                       secdebug("dirval", "file %s", ent->fts_path);
+                       rule = match(relpath, file, executable);
+                       break;
+               case FTS_SL: {
+                       secdebug("dirval", "symlink %s", ent->fts_path);
+                       char target[PATH_MAX];
+                       ssize_t len = ::readlink(ent->fts_accpath, target, sizeof(target)-1);
+                       if (len < 0)
+                               UnixError::throwMe();
+                       target[len] = '\0';
+                       rule = match(relpath, symlink, executable, target);
+                       break;
+               }
+               case FTS_D:
+                       secdebug("dirval", "entering %s", ent->fts_path);
+                       if (ent->fts_level == FTS_ROOTLEVEL)
+                               continue;       // skip root directory
+                       rule = match(relpath, directory, executable);
+                       if (!rule || !(rule->flags & descend))
+                               fts_set(fts, ent, FTS_SKIP);    // do not descend
+                       break;
+               case FTS_DP:
+                       secdebug("dirval", "leaving %s", ent->fts_path);
+                       continue;
+               default:
+                       secdebug("dirval", "type %d (errno %d): %s", ent->fts_info, ent->fts_errno, ent->fts_path);
+                       MacOSError::throwMe(error);      // not a file, symlink, or directory
+               }
+               if (!rule)
+                       MacOSError::throwMe(error);      // no match
+               else if (rule->flags & required)
+                       reqMatched.insert(rule);
+       }
+       if (reqMatched.size() != mRequireCount) {
+               secdebug("dirval", "matched %d of %d required rules", reqMatched.size(), mRequireCount);
+               MacOSError::throwMe(error);              // not all required rules were matched
+       }
+}
+
+DirValidator::Rule * DirValidator::match(const char *path, uint32_t flags, bool executable, const char *target)
+{
+       for (Rules::iterator it = mRules.begin(); it != mRules.end(); ++it) {
+               Rule *rule = *it;
+               if ((rule->flags & flags)
+                   && !(executable && (rule->flags & noexec))
+                   && rule->match(path)
+                   && (!target || rule->matchTarget(path, target)))
+                       return rule;
+       }
+       return NULL;
+}
+
+DirValidator::FTS::FTS(const string &path, int options)
+{
+       const char * paths[2] = { path.c_str(), NULL };
+       mFTS = fts_open((char * const *)paths, options, NULL);
+       if (!mFTS)
+               UnixError::throwMe();
+}
+
+DirValidator::FTS::~FTS()
+{
+       fts_close(mFTS);
+}
+
+DirValidator::Rule::Rule(const string &pattern, uint32_t flags, TargetPatternBuilder targetBlock)
+       : ResourceBuilder::Rule(pattern, 0, flags), mTargetBlock(NULL)
+{
+       if (targetBlock)
+               mTargetBlock = Block_copy(targetBlock);
+}
+
+DirValidator::Rule::~Rule()
+{
+       if (mTargetBlock)
+               Block_release(mTargetBlock);
+}
+
+bool DirValidator::Rule::matchTarget(const char *path, const char *target) const
+{
+       if (!mTargetBlock)
+               MacOSError::throwMe(errSecCSInternalError);
+       string pattern = mTargetBlock(path, target);
+       if (pattern.empty())
+               return true;    // always match empty pattern
+       secdebug("dirval", "%s: match target %s against %s", path, target, pattern.c_str());
+       regex_t re;
+       if (::regcomp(&re, pattern.c_str(), REG_EXTENDED | REG_NOSUB))
+               MacOSError::throwMe(errSecCSInternalError);
+       switch (::regexec(&re, target, 0, NULL, 0)) {
+       case 0:
+               return true;
+       case REG_NOMATCH:
+               return false;
+       default:
+               MacOSError::throwMe(errSecCSInternalError);
+       }
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/libsecurity_codesigning/lib/dirscanner.h b/libsecurity_codesigning/lib/dirscanner.h
new file mode 100644 (file)
index 0000000..ddd5e56
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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@
+ */
+
+#ifndef _H_DIRSCANNER
+#define _H_DIRSCANNER
+
+#include "resources.h"
+#include <dirent.h>
+#include <fts.h>
+#include <security_utilities/cfutilities.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+class DirScanner {
+public:
+       DirScanner(const char *path);
+       DirScanner(string path);
+       ~DirScanner();
+
+       struct dirent *getNext();       // gets the next item out of this DirScanner
+       bool initialized();                     // returns false if the constructor failed to initialize the dirent
+
+private:
+       string path;
+       DIR *dp = NULL;
+       void initialize();
+       bool init;
+};
+
+
+class DirValidator {
+public:
+       DirValidator() : mRequireCount(0) { }
+       ~DirValidator();
+
+       enum {
+               file = 0x01,
+               directory = 0x02,
+               symlink = 0x04,
+               noexec = 0x08,
+               required = 0x10,
+               descend = 0x20,
+       };
+
+       typedef std::string (^TargetPatternBuilder)(const std::string &name, const std::string &target);
+
+private:
+       class Rule : public ResourceBuilder::Rule {
+       public:
+               Rule(const std::string &pattern, uint32_t flags, TargetPatternBuilder targetBlock);
+               ~Rule();
+
+               bool matchTarget(const char *path, const char *target) const;
+
+       private:
+               TargetPatternBuilder mTargetBlock;
+       };
+       void addRule(Rule *rule) { mRules.push_back(rule); }
+
+       class FTS {
+       public:
+               FTS(const std::string &path, int options = FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR);
+               ~FTS();
+
+               operator ::FTS* () const { return mFTS; }
+
+       private:
+               ::FTS *mFTS;
+       };
+
+public:
+       void allow(const std::string &namePattern, uint32_t flags, TargetPatternBuilder targetBlock = NULL)
+       { addRule(new Rule(namePattern, flags, targetBlock)); }
+       void require(const std::string &namePattern, uint32_t flags, TargetPatternBuilder targetBlock = NULL)
+       { addRule(new Rule(namePattern, flags | required, targetBlock)); mRequireCount++; }
+
+       void allow(const std::string &namePattern, uint32_t flags, std::string targetPattern)
+       { allow(namePattern, flags, ^ string (const std::string &name, const std::string &target) { return targetPattern; }); }
+       void require(const std::string &namePattern, uint32_t flags, std::string targetPattern)
+       { require(namePattern, flags, ^ string (const std::string &name, const std::string &target) { return targetPattern; }); }
+
+       void validate(const std::string &root, OSStatus error);
+
+private:
+       Rule * match(const char *relpath, uint32_t flags, bool executable, const char *target = NULL);
+
+private:
+       typedef std::vector<Rule *> Rules;
+       Rules mRules;
+       int mRequireCount;
+};
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif // !_H_DIRSCANNER
index 395402c65f8650f3ac5fa9427e880ac24af3f25d..695980846f91ffe04a08e3467db05f0fc234c9ed 100644 (file)
@@ -221,6 +221,17 @@ size_t DiskRep::pageSize(const SigningContext &)
 }
 
 
+void DiskRep::strictValidate(const ToleratedErrors&)
+{
+       // do nothing
+}
+
+CFArrayRef DiskRep::allowedResourceOmissions()
+{
+       return NULL;
+}
+
+
 //
 // Given some string (usually a pathname), derive a suggested signing identifier
 // in a canonical way (so there's some consistency).
index e5de06be354d5f5fd4da29203eb7864d6f61388f..c63a3d2bb4ffc1c1a42aaad99affa6f15252e734 100644 (file)
@@ -53,6 +53,8 @@ class DiskRep : public RefCount {
 public:
        class SigningContext;
        
+       typedef std::set<OSStatus> ToleratedErrors;
+       
 public:
        DiskRep();
        virtual ~DiskRep();
@@ -60,7 +62,7 @@ public:
        virtual CFDataRef component(CodeDirectory::SpecialSlot slot) = 0; // fetch component
        virtual CFDataRef identification() = 0;                                 // binary lookup identifier
        virtual std::string mainExecutablePath() = 0;                   // path to main executable
-       virtual CFURLRef canonicalPath() = 0;                                   // path to whole code
+       virtual CFURLRef copyCanonicalPath() = 0;                                       // path to whole code
        virtual std::string resourcesRootPath();                                // resource directory if any [none]
        virtual void adjustResources(ResourceBuilder &builder); // adjust resource rule set [no change]
        virtual Universal *mainExecutableImage();                               // Mach-O image if Mach-O based [null]
@@ -77,7 +79,10 @@ public:
        virtual const Requirements *defaultRequirements(const Architecture *arch,
                const SigningContext &ctx);                                                     // default internal requirements [none]
        virtual size_t pageSize(const SigningContext &ctx);             // default main executable page size [infinite, i.e. no paging]
-       
+
+       virtual void strictValidate(const ToleratedErrors& tolerated); // perform strict validation
+       virtual CFArrayRef allowedResourceOmissions();                  // allowed (default) resource omission rules
+
        bool mainExecutableIsMachO() { return mainExecutableImage() != NULL; }
        
        // shorthands
@@ -91,12 +96,13 @@ public:
 public:
        // optional information that might be used to create a suitable DiskRep. All optional
        struct Context {
-               Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL) { }
+               Context() : arch(Architecture::none), version(NULL), offset(0), fileOnly(false), inMemory(NULL), size(0) { }
                Architecture arch;                      // explicit architecture (choose amongst universal variants)
                const char *version;            // bundle version (string)
                off_t offset;                           // explicit file offset
                bool fileOnly;                          // only consider single-file representations (no bundles etc.)
                const void *inMemory;           // consider using in-memory copy at this address
+               size_t size;                            // size of this mach-o slice
        };
 
        static DiskRep *bestGuess(const char *path, const Context *ctx = NULL); // canonical heuristic, any path
@@ -195,7 +201,7 @@ public:
        // the rest of the virtual behavior devolves on the original DiskRep
        CFDataRef identification()                              { return mOriginal->identification(); }
        std::string mainExecutablePath()                { return mOriginal->mainExecutablePath(); }
-       CFURLRef canonicalPath()                                { return mOriginal->canonicalPath(); }
+       CFURLRef copyCanonicalPath()                    { return mOriginal->copyCanonicalPath(); }
        std::string resourcesRootPath()                 { return mOriginal->resourcesRootPath(); }
        void adjustResources(ResourceBuilder &builder) { return mOriginal->adjustResources(builder); }
        Universal *mainExecutableImage()                { return mOriginal->mainExecutableImage(); }
index f39cc511f0bf4dc6703a1dc5a4fa93877a63ae98..b196c07156e3a4f17c6d257f84958126bd9857dd 100644 (file)
@@ -54,7 +54,7 @@ CFDataRef KernelDiskRep::identification()
 }
 
 
-CFURLRef KernelDiskRep::canonicalPath()
+CFURLRef KernelDiskRep::copyCanonicalPath()
 {
        return makeCFURL("/mach_kernel");
 }
index 997462f657051789fadca6062f61af218a5a06ee..0b1085e12a37c79324270120b33326379254ffbd 100644 (file)
@@ -49,7 +49,7 @@ public:
        CFDataRef component(CodeDirectory::SpecialSlot slot);
        CFDataRef identification();
        std::string mainExecutablePath();
-       CFURLRef canonicalPath();
+       CFURLRef copyCanonicalPath();
        size_t signingLimit();
        std::string format();
        UnixPlusPlus::FileDesc &fd();
index 2130171d7659bb8d01a55899cf51aacf9811d189..7d9f5d02309f56a512adfc501e7e518e576c8d4b 100644 (file)
@@ -47,14 +47,15 @@ MachORep::MachORep(const char *path, const Context *ctx)
 {
        if (ctx)
                if (ctx->offset)
-                       mExecutable = new Universal(fd(), (size_t)ctx->offset);
+                       mExecutable = new Universal(fd(), (size_t)ctx->offset, ctx->size);
                else if (ctx->arch) {
                        auto_ptr<Universal> full(new Universal(fd()));
-                       mExecutable = new Universal(fd(), full->archOffset(ctx->arch));
+                       mExecutable = new Universal(fd(), full->archOffset(ctx->arch), full->archLength(ctx->arch));
                } else
                        mExecutable = new Universal(fd());
        else
                mExecutable = new Universal(fd());
+
        assert(mExecutable);
        CODESIGN_DISKREP_CREATE_MACHO(this, (char*)path, (void*)ctx);
 }
@@ -248,12 +249,13 @@ string MachORep::format()
 void MachORep::flush()
 {
        size_t offset = mExecutable->offset();
+       size_t length = mExecutable->length();
        delete mExecutable;
        mExecutable = NULL;
        ::free(mSigningData);
        mSigningData = NULL;
        SingleDiskRep::flush();
-       mExecutable = new Universal(fd(), offset);
+       mExecutable = new Universal(fd(), offset, length);
 }
 
 
@@ -359,6 +361,16 @@ size_t MachORep::pageSize(const SigningContext &)
 }
 
 
+//
+// Strict validation
+//
+void MachORep::strictValidate(const ToleratedErrors& tolerated)
+{
+       if (mExecutable->isSuspicious() && tolerated.find(errSecCSBadMainExecutable) == tolerated.end())
+               MacOSError::throwMe(errSecCSBadMainExecutable);
+}
+
+
 //
 // FileDiskRep::Writers
 //
index 2486139533924d034e005e8839ffaf4a0a0b21c6..b7f248abc9c57d39d47433cd1057b45828e5da63 100644 (file)
@@ -59,6 +59,8 @@ public:
        std::string recommendedIdentifier(const SigningContext &ctx);
        const Requirements *defaultRequirements(const Architecture *arch, const SigningContext &ctx);
        size_t pageSize(const SigningContext &ctx);
+
+       void strictValidate(const ToleratedErrors& tolerated);
        
        void flush();           // flush cache
        
diff --git a/libsecurity_codesigning/lib/opaquewhitelist.cpp b/libsecurity_codesigning/lib/opaquewhitelist.cpp
new file mode 100644 (file)
index 0000000..ae5b6e2
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * 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 "opaquewhitelist.h"
+#include "csutilities.h"
+#include "StaticCode.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/SecCodePriv.h>
+#include <Security/SecCodeSigner.h>
+#include <Security/SecStaticCode.h>
+#include <security_utilities/cfutilities.h>
+#include <security_utilities/cfmunge.h>
+#include <CoreFoundation/CFBundlePriv.h>
+
+namespace Security {
+namespace CodeSigning {
+
+using namespace SQLite;
+
+
+static void traceHash(MessageTrace &trace, const char *key, CFDataRef hash);
+static void attachOpaque(SecStaticCodeRef code);
+
+
+//
+// Open the database
+//
+OpaqueWhitelist::OpaqueWhitelist(const char *path, int flags)
+       : SQLite::Database(path ? path : opaqueDatabase, flags)
+{
+       SQLite::Statement createConditions(*this,
+               "CREATE TABLE IF NOT EXISTS conditions ("
+               " label text,"
+          " weight real not null unique,"
+          " source text,"
+          " identifier text,"
+          " version text,"
+          " conditions text not null);"
+       );
+       createConditions.execute();
+
+}
+
+OpaqueWhitelist::~OpaqueWhitelist()
+{ /* virtual */ }
+
+
+//
+// Check if a code object is whitelisted
+//
+bool OpaqueWhitelist::contains(SecStaticCodeRef codeRef, OSStatus reason, bool trace)
+{
+       // make our own copy of the code object, so we can poke at it without disturbing the original
+       SecPointer<SecStaticCode> code = new SecStaticCode(SecStaticCode::requiredStatic(codeRef)->diskRep());
+
+       CFCopyRef<CFDataRef> current = code->cdHash();  // current cdhash
+       CFDataRef opaque = NULL;        // holds computed opaque cdhash
+       bool match = false;     // holds final result
+
+       if (!current)
+               return false;   // unsigned
+
+       // collect auxiliary information for trace
+       CFRef<CFDictionaryRef> info;
+       std::string team = "";
+       CFStringRef cfVersion = NULL, cfShortVersion = NULL, cfExecutable = NULL;
+       if (errSecSuccess == SecCodeCopySigningInformation(code->handle(false), kSecCSSigningInformation, &info.aref())) {
+               if (CFStringRef cfTeam = CFStringRef(CFDictionaryGetValue(info, kSecCodeInfoTeamIdentifier)))
+                       team = cfString(cfTeam);
+               if (CFDictionaryRef infoPlist = CFDictionaryRef(CFDictionaryGetValue(info, kSecCodeInfoPList))) {
+                       if (CFTypeRef version = CFDictionaryGetValue(infoPlist, kCFBundleVersionKey))
+                               if (CFGetTypeID(version) == CFStringGetTypeID())
+                                       cfVersion = CFStringRef(version);
+                       if (CFTypeRef shortVersion = CFDictionaryGetValue(infoPlist, _kCFBundleShortVersionStringKey))
+                               if (CFGetTypeID(shortVersion) == CFStringGetTypeID())
+                                       cfShortVersion = CFStringRef(shortVersion);
+                       if (CFTypeRef executable = CFDictionaryGetValue(infoPlist, kCFBundleExecutableKey))
+                               if (CFGetTypeID(executable) == CFStringGetTypeID())
+                                       cfExecutable = CFStringRef(executable);
+               }
+       }
+
+       // compute and attach opaque signature
+       attachOpaque(code->handle(false));
+       opaque = code->cdHash();
+
+       // lookup current cdhash in whitelist
+       SQLite::Statement lookup(*this, "SELECT opaque FROM whitelist WHERE current=:current");
+       lookup.bind(":current") = current.get();
+       while (lookup.nextRow()) {
+               CFRef<CFDataRef> expected = lookup[0].data();
+               if (CFEqual(opaque, expected)) {
+                       match = true;   // actual opaque cdhash matches expected
+                       break;
+               }
+       }
+
+       if (trace) {
+               // send a trace indicating the result
+               MessageTrace trace("com.apple.security.assessment.whitelist2", code->identifier().c_str());
+               traceHash(trace, "signature2", current);
+               traceHash(trace, "signature3", opaque);
+               trace.add("result", match ? "pass" : "fail");
+               trace.add("reason", "%d", reason);
+               if (!team.empty())
+                       trace.add("teamid", "%s", team.c_str());
+               if (cfVersion)
+                       trace.add("version", "%s", cfString(cfVersion).c_str());
+               if (cfShortVersion)
+                       trace.add("version2", "%s", cfString(cfShortVersion).c_str());
+               if (cfExecutable)
+                       trace.add("execname", "%s", cfString(cfExecutable).c_str());
+               trace.send("");
+       }
+
+       return match;
+}
+       
+
+//
+// Obtain special validation conditions for a static code, based on database configuration.
+//
+CFDictionaryRef OpaqueWhitelist::validationConditionsFor(SecStaticCodeRef code)
+{
+       // figure out which team key to use
+       std::string team = "UNKNOWN";
+       CFStringRef cfId = NULL;
+       CFStringRef cfVersion = NULL;
+       CFRef<CFDictionaryRef> info;    // holds lifetimes for the above
+       if (errSecSuccess == SecCodeCopySigningInformation(code, kSecCSSigningInformation, &info.aref())) {
+               if (CFStringRef cfTeam = CFStringRef(CFDictionaryGetValue(info, kSecCodeInfoTeamIdentifier)))
+                       team = cfString(cfTeam);
+               cfId = CFStringRef(CFDictionaryGetValue(info, kSecCodeInfoIdentifier));
+               if (CFDictionaryRef infoPlist = CFDictionaryRef(CFDictionaryGetValue(info, kSecCodeInfoPList)))
+                       if (CFTypeRef version = CFDictionaryGetValue(infoPlist, _kCFBundleShortVersionStringKey))
+                               if (CFGetTypeID(version) == CFStringGetTypeID())
+                                       cfVersion = CFStringRef(version);
+       }
+       if (cfId == NULL)       // unsigned; punt
+               return NULL;
+       
+       // find the highest weight matching condition. We perform no merging and the heaviest rule wins
+       SQLite::Statement matches(*this,
+               "SELECT conditions FROM conditions"
+               " WHERE (source = :source or source IS NULL)"
+               " AND (identifier = :identifier or identifier is NULL)"
+               " AND ((:version IS NULL AND version IS NULL) OR (version = :version OR version IS NULL))"
+               " ORDER BY weight DESC"
+               " LIMIT 1"
+       );
+       matches.bind(":source") = team;
+       matches.bind(":identifier") = cfString(cfId);
+       if (cfVersion)
+               matches.bind(":version") = cfString(cfVersion);
+       if (matches.nextRow()) {
+               CFTemp<CFDictionaryRef> conditions((const char*)matches[0]);
+               return conditions.yield();
+       }
+       // no matches
+       return NULL;
+}
+
+
+//
+// Convert a SHA1 hash to hex and add to a trace
+//
+static void traceHash(MessageTrace &trace, const char *key, CFDataRef hash)
+{
+       if (CFDataGetLength(hash) != sizeof(SHA1::Digest)) {
+               trace.add(key, "(unknown format)");
+       } else {
+               const UInt8 *bytes = CFDataGetBytePtr(hash);
+               char s[2 * SHA1::digestLength + 1];
+               for (unsigned n = 0; n < SHA1::digestLength; n++)
+                       sprintf(&s[2*n], "%2.2x", bytes[n]);
+               trace.add(key, s);
+       }
+}
+
+
+//
+// Add a code object to the whitelist
+//
+void OpaqueWhitelist::add(SecStaticCodeRef codeRef)
+{
+       // make our own copy of the code object
+       SecPointer<SecStaticCode> code = new SecStaticCode(SecStaticCode::requiredStatic(codeRef)->diskRep());
+
+       CFCopyRef<CFDataRef> current = code->cdHash();
+       attachOpaque(code->handle(false));      // compute and attach an opaque signature
+       CFDataRef opaque = code->cdHash();
+
+       SQLite::Statement insert(*this, "INSERT OR REPLACE INTO whitelist (current,opaque) VALUES (:current, :opaque)");
+       insert.bind(":current") = current.get();
+       insert.bind(":opaque") = opaque;
+       insert.execute();
+}
+
+
+//
+// Generate and attach an ad-hoc opaque signature
+//
+static void attachOpaque(SecStaticCodeRef code)
+{
+       CFTemp<CFDictionaryRef> rules("{"       // same resource rules as used for collection
+               "rules={"
+                       "'^.*' = #T"
+                       "'^Info\\.plist$' = {omit=#T,weight=10}"
+               "},rules2={"
+                       "'^(Frameworks|SharedFrameworks|Plugins|Plug-ins|XPCServices|Helpers|MacOS)/' = {nested=#T, weight=0}" 
+                       "'^.*' = #T"
+                       "'^Info\\.plist$' = {omit=#T,weight=10}"
+                       "'^[^/]+$' = {top=#T, weight=0}"
+               "}"
+       "}");
+
+       CFRef<CFDataRef> signature = CFDataCreateMutable(NULL, 0);
+       CFTemp<CFDictionaryRef> arguments("{%O=%O, %O=#N, %O=%O}",
+               kSecCodeSignerDetached, signature.get(),
+               kSecCodeSignerIdentity, /* kCFNull, */
+               kSecCodeSignerResourceRules, rules.get());
+       CFRef<SecCodeSignerRef> signer;
+       SecCSFlags flags = kSecCSSignOpaque | kSecCSSignNoV1 | kSecCSSignBundleRoot;
+       MacOSError::check(SecCodeSignerCreate(arguments, flags, &signer.aref()));
+       MacOSError::check(SecCodeSignerAddSignature(signer, code, kSecCSDefaultFlags));
+       MacOSError::check(SecCodeSetDetachedSignature(code, signature, kSecCSDefaultFlags));
+}
+
+
+} // end namespace CodeSigning
+} // end namespace Security
diff --git a/libsecurity_codesigning/lib/opaquewhitelist.h b/libsecurity_codesigning/lib/opaquewhitelist.h
new file mode 100644 (file)
index 0000000..732cce3
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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@
+ */
+#ifndef _H_OPAQUEWHITELIST
+#define _H_OPAQUEWHITELIST
+
+#include "SecAssessment.h"
+#include <Security/CodeSigning.h>
+#include <security_utilities/sqlite++.h>
+
+namespace Security {
+namespace CodeSigning {
+
+
+namespace SQLite = SQLite3;
+
+
+static const char opaqueDatabase[] = "/var/db/gkopaque.bundle/Contents/Resources/gkopaque.db";
+
+
+class OpaqueWhitelist : public SQLite::Database {
+public:
+       OpaqueWhitelist(const char *path = NULL, int flags = SQLITE_OPEN_READWRITE);
+       virtual ~OpaqueWhitelist();
+
+public:
+       void add(SecStaticCodeRef code);
+       bool contains(SecStaticCodeRef code, OSStatus reason, bool trace);
+       
+       CFDictionaryRef validationConditionsFor(SecStaticCodeRef code);
+};
+
+
+} // end namespace CodeSigning
+} // end namespace Security
+
+#endif //_H_OPAQUEWHITELIST
index aafba02feff2db32ce44a03df0e7456b4dc9e1ff..37398eb0ba3b5addd9030fb9aa631e8861008ace 100644 (file)
@@ -130,7 +130,7 @@ CFDataRef PidDiskRep::identification()
 }
 
 
-CFURLRef PidDiskRep::canonicalPath()
+CFURLRef PidDiskRep::copyCanonicalPath()
 {
         return mBundleURL.retain();
 }
index b7f4215975179994966ffb1b76c0e48a5f83251e..b804a20d85a50964d77b321467b1e8b9d4c15146 100644 (file)
@@ -46,7 +46,7 @@ public:
         CFDataRef component(CodeDirectory::SpecialSlot slot);
         CFDataRef identification();
         std::string mainExecutablePath();
-        CFURLRef canonicalPath();
+        CFURLRef copyCanonicalPath();
         size_t signingLimit();
         std::string format();
         UnixPlusPlus::FileDesc &fd();
index e3b6fe8e208adcf8769780ff8125330112c33fdf..eb253d43b5fecdf62a2d8915b877ab98e5bc6a2f 100644 (file)
@@ -78,42 +78,6 @@ PolicyEngine::PolicyEngine()
 PolicyEngine::~PolicyEngine()
 { }
 
-#define GKBIS_XPC_SERVICE_NAME "com.apple.gkbisd"
-#define GKBIS_REQUEST_KEY_PATH "path"
-#define GKBIS_REQUEST_KEY_DEFER "defer"
-#define GKBIS_REQUEST_KEY_QUARANTINED "quarantined"
-
-static void
-gkbis_invoke_collector(const char *path)
-{
-       dispatch_queue_t queue = dispatch_queue_create("gkbis_invoke_collector", NULL);
-       dispatch_group_t group = dispatch_group_create();
-       /* Set up a connection to gkbisd. */
-       xpc_connection_t connection = xpc_connection_create_mach_service(GKBIS_XPC_SERVICE_NAME,
-                                                                                                                                        queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
-       xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
-       });
-       xpc_connection_resume(connection);
-
-       /* Construct and send the request. */
-       xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
-       xpc_dictionary_set_string(message, GKBIS_REQUEST_KEY_PATH, path);
-    xpc_dictionary_set_bool(message, GKBIS_REQUEST_KEY_QUARANTINED, true);
-       xpc_dictionary_set_bool(message, GKBIS_REQUEST_KEY_DEFER, true);
-       xpc_connection_send_message(connection, message);
-       xpc_release(message);
-       /* Cancel the connection after the request has been sent. */
-       dispatch_group_enter(group);
-       xpc_connection_send_barrier(connection, ^{
-               xpc_connection_cancel(connection);
-               xpc_release(connection);
-               dispatch_group_leave(group);
-       });
-       /* Wait until the connection is canceled. */
-       dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-       dispatch_release(queue);
-       dispatch_release(group);
-}
 
 //
 // Top-level evaluation driver
@@ -125,7 +89,6 @@ void PolicyEngine::evaluate(CFURLRef path, AuthorityType type, SecAssessmentFlag
 
        switch (type) {
        case kAuthorityExecute:
-               gkbis_invoke_collector(cfString(path).c_str());
                evaluateCode(path, kAuthorityExecute, flags, context, result, true);
                break;
        case kAuthorityInstall:
@@ -177,11 +140,13 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author
                
                CFRef<SecRequirementRef> requirement;
                MacOSError::check(SecRequirementCreateWithString(CFTempString(reqString), kSecCSDefaultFlags, &requirement.aref()));
-               switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSDefaultFlags, requirement)) {
+               switch (OSStatus rc = SecStaticCodeCheckValidity(code, kSecCSBasicValidateOnly, requirement)) {
                case errSecSuccess:
                        break;                                          // rule match; process below
                case errSecCSReqFailed:
                        continue;                                       // rule does not apply
+               case errSecCSVetoed:
+                       return;                                         // nested code has failed to pass
                default:
                        MacOSError::throwMe(rc);        // general error; pass to caller
                }
@@ -257,6 +222,13 @@ void PolicyEngine::evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, Author
        cfadd(result, "{%O=%B}", kSecAssessmentAssessmentVerdict, false);
        addAuthority(flags, result, latentLabel.c_str(), latentID);
 }
+       
+
+void PolicyEngine::adjustValidation(SecStaticCodeRef code)
+{
+       CFRef<CFDictionaryRef> conditions = mOpaqueWhitelist.validationConditionsFor(code);
+       SecStaticCodeSetValidationConditions(code, conditions);
+}
 
 
 bool PolicyEngine::temporarySigning(SecStaticCodeRef code, AuthorityType type, CFURLRef path, SecAssessmentFlags matchFlags)
@@ -334,10 +306,11 @@ bool PolicyEngine::temporarySigning(SecStaticCodeRef code, AuthorityType type, C
 
 //
 // Executable code.
-// Read from disk, evaluate properly, cache as indicated. The whole thing, so far.
+// Read from disk, evaluate properly, cache as indicated.
 //
 void PolicyEngine::evaluateCode(CFURLRef path, AuthorityType type, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result, bool handleUnsigned)
 {
+       // not really a Gatekeeper function... but reject all "hard quarantined" files because they were made from sandboxed sources without download privilege
        FileQuarantine qtn(cfString(path).c_str());
        if (qtn.flag(QTN_FLAG_HARD))
                MacOSError::throwMe(errSecCSFileHardQuarantined);
@@ -345,7 +318,10 @@ void PolicyEngine::evaluateCode(CFURLRef path, AuthorityType type, SecAssessment
        CFCopyRef<SecStaticCodeRef> code;
        MacOSError::check(SecStaticCodeCreateWithPath(path, kSecCSDefaultFlags, &code.aref()));
        
-       SecCSFlags validationFlags = kSecCSEnforceRevocationChecks;
+       SecCSFlags validationFlags = kSecCSEnforceRevocationChecks | kSecCSCheckAllArchitectures;
+       if (!(flags & kSecAssessmentFlagAllowWeak))
+               validationFlags |= kSecCSStrictValidate;
+       adjustValidation(code);
        
        // first, perform a shallow check
        OSStatus rc = SecStaticCodeCheckValidity(code, validationFlags, NULL);
@@ -369,12 +345,18 @@ void PolicyEngine::evaluateCode(CFURLRef path, AuthorityType type, SecAssessment
                }
        }
        
-       MacOSError::check(SecStaticCodeSetCallback(code, kSecCSDefaultFlags, NULL, ^CFTypeRef (SecStaticCodeRef item, CFStringRef stage, CFDictionaryRef info) {
-               SecStaticCodeSetCallback(item, kSecCSDefaultFlags, NULL, NULL);         // clear callback to avoid unwanted recursion
-               evaluateCodeItem(item, path, type, flags, item != code, result);
-               if (CFTypeRef verdict = CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict))
-                       if (CFEqual(verdict, kCFBooleanFalse))
-                               return makeCFNumber(OSStatus(errSecCSVetoed));  // (signal nested-code policy failure, picked up below)
+       MacOSError::check(SecStaticCodeSetCallback(code, kSecCSDefaultFlags, NULL, ^CFTypeRef (SecStaticCodeRef item, CFStringRef cfStage, CFDictionaryRef info) {
+               string stage = cfString(cfStage);
+               if (stage == "prepared") {
+                       if (!CFEqual(item, code))       // genuine nested (not top) code
+                               adjustValidation(item);
+               } else if (stage == "validated") {
+                       SecStaticCodeSetCallback(item, kSecCSDefaultFlags, NULL, NULL);         // clear callback to avoid unwanted recursion
+                       evaluateCodeItem(item, path, type, flags, item != code, result);
+                       if (CFTypeRef verdict = CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict))
+                               if (CFEqual(verdict, kCFBooleanFalse))
+                                       return makeCFNumber(OSStatus(errSecCSVetoed));  // (signal nested-code policy failure, picked up below)
+               }
                return NULL;
        }));
        switch (rc = SecStaticCodeCheckValidity(code, validationFlags | kSecCSCheckNestedCode, NULL)) {
@@ -386,6 +368,42 @@ void PolicyEngine::evaluateCode(CFURLRef path, AuthorityType type, SecAssessment
                return;
        case errSecCSVetoed:            // nested code rejected by rule book; result was filled out there
                return;
+       case errSecCSWeakResourceRules:
+       case errSecCSResourceNotSupported:
+       case errSecCSAmbiguousBundleFormat:
+       case errSecCSSignatureNotVerifiable:
+       case errSecCSRegularFile:
+       case errSecCSBadMainExecutable:
+       case errSecCSBadFrameworkVersion:
+       case errSecCSUnsealedAppRoot:
+       case errSecCSUnsealedFrameworkRoot:
+       {
+               // consult the whitelist
+               bool allow = false;
+               const char *label;
+               // we've bypassed evaluateCodeItem before we failed validation. Explicitly apply it now
+               SecStaticCodeSetCallback(code, kSecCSDefaultFlags, NULL, NULL);
+               evaluateCodeItem(code, path, type, flags | kSecAssessmentFlagNoCache, false, result);
+               if (CFTypeRef verdict = CFDictionaryGetValue(result, kSecAssessmentAssessmentVerdict)) {
+                       // verdict rendered from a nested component - signature not acceptable to Gatekeeper
+                       if (CFEqual(verdict, kCFBooleanFalse))  // nested code rejected by rule book; result was filled out there
+                               return;
+                       if (CFEqual(verdict, kCFBooleanTrue) && !(flags & kSecAssessmentFlagIgnoreWhitelist)) {
+                               bool trace = CFDictionaryContainsKey(context, kSecAssessmentContextQuarantineFlags);
+                               if (mOpaqueWhitelist.contains(code, rc, trace))
+                                       allow = true;
+                       }
+               }
+               if (allow) {
+                       label = "allowed cdhash";
+               } else {
+                       CFDictionaryReplaceValue(result, kSecAssessmentAssessmentVerdict, kCFBooleanFalse);
+                       label = "obsolete resource envelope";
+               }
+               cfadd(result, "{%O=%d}", kSecAssessmentAssessmentCodeSigningError, rc);
+               addAuthority(flags, result, label, 0, NULL, true);
+               return;
+       }
        default:
                MacOSError::throwMe(rc);
        }
@@ -602,7 +620,7 @@ void PolicyEngine::evaluateDocOpen(CFURLRef path, SecAssessmentFlags flags, CFDi
 //
 // Result-creation helpers
 //
-void PolicyEngine::addAuthority(SecAssessmentFlags flags, CFMutableDictionaryRef parent, const char *label, SQLite::int64 row, CFTypeRef cacheInfo)
+void PolicyEngine::addAuthority(SecAssessmentFlags flags, CFMutableDictionaryRef parent, const char *label, SQLite::int64 row, CFTypeRef cacheInfo, bool weak)
 {
        CFRef<CFMutableDictionaryRef> auth = makeCFMutableDictionary();
        if (label && label[0])
@@ -613,7 +631,12 @@ void PolicyEngine::addAuthority(SecAssessmentFlags flags, CFMutableDictionaryRef
                CFDictionaryAddValue(auth, kSecAssessmentAssessmentAuthorityOverride, kDisabledOverride);
        if (cacheInfo)
                CFDictionaryAddValue(auth, kSecAssessmentAssessmentFromCache, cacheInfo);
-       CFDictionaryAddValue(parent, kSecAssessmentAssessmentAuthority, auth);
+       if (weak) {
+               CFDictionaryAddValue(auth, kSecAssessmentAssessmentWeakSignature, kCFBooleanTrue);
+               CFDictionaryReplaceValue(parent, kSecAssessmentAssessmentAuthority, auth);
+       } else {
+               CFDictionaryAddValue(parent, kSecAssessmentAssessmentAuthority, auth);
+       }
 }
 
 void PolicyEngine::addToAuthority(CFMutableDictionaryRef parent, CFStringRef key, CFTypeRef value)
@@ -1035,6 +1058,11 @@ void PolicyEngine::normalizeTarget(CFRef<CFTypeRef> &target, AuthorityType type,
                        CFDictionaryAddValue(dict, kSecAssessmentUpdateKeyRemarks, CFTempString(cfString(path)));
                        context.take(dict);
                }
+               CFStringRef edit = CFStringRef(context.get(kSecAssessmentContextKeyUpdate));
+               if (type == kAuthorityExecute && CFEqual(edit, kSecAssessmentUpdateOperationAdd)) {
+                       // implicitly whitelist the code
+                       mOpaqueWhitelist.add(code);
+               }
        }
 }
 
index af06f66049daa93f067a7af22f8dc65b5be412dc..8f4d7a17dbb9e283525299a96092346284f0c95c 100644 (file)
@@ -24,6 +24,7 @@
 #define _H_POLICYENGINE
 
 #include "SecAssessment.h"
+#include "opaquewhitelist.h"
 #include "policydb.h"
 #include <security_utilities/globalizer.h>
 #include <security_utilities/cfutilities.h>
@@ -63,7 +64,7 @@ public:
        void recordFailure(CFDictionaryRef info);
 
 public:
-       static void addAuthority(SecAssessmentFlags flags, CFMutableDictionaryRef parent, const char *label, SQLite::int64 row = 0, CFTypeRef cacheInfo = NULL);
+       static void addAuthority(SecAssessmentFlags flags, CFMutableDictionaryRef parent, const char *label, SQLite::int64 row = 0, CFTypeRef cacheInfo = NULL, bool weak = false);
        static void addToAuthority(CFMutableDictionaryRef parent, CFStringRef key, CFTypeRef value);
 
 private:
@@ -72,6 +73,7 @@ private:
        void evaluateDocOpen(CFURLRef path, SecAssessmentFlags flags, CFDictionaryRef context, CFMutableDictionaryRef result);
        
        void evaluateCodeItem(SecStaticCodeRef code, CFURLRef path, AuthorityType type, SecAssessmentFlags flags, bool nested, CFMutableDictionaryRef result);
+       void adjustValidation(SecStaticCodeRef code);
        bool temporarySigning(SecStaticCodeRef code, AuthorityType type, CFURLRef path, SecAssessmentFlags matchFlags);
        void normalizeTarget(CFRef<CFTypeRef> &target, AuthorityType type, CFDictionary &context, std::string *signUnsigned);
        
@@ -83,6 +85,9 @@ private:
        void setOrigin(CFArrayRef chain, CFMutableDictionaryRef result);
 
        void recordOutcome(SecStaticCodeRef code, bool allow, AuthorityType type, double expires, SQLite::int64 authority);
+
+private:
+       OpaqueWhitelist mOpaqueWhitelist;
 };
 
 
index 0ac68ecb7be5abeca10f313a359e3eb8493e7e62..1a4d1e2a5323c07380296161716c182ce0879e31 100644 (file)
@@ -47,15 +47,30 @@ namespace Security {
 namespace CodeSigning {
 
 
+static string removeTrailingSlash(string path)
+{
+       if (path.substr(path.length()-2, 2) == "/.")
+               return path.substr(0, path.length()-2);
+       else if (path.substr(path.length()-1, 1) == "/")
+               return path.substr(0, path.length()-1);
+       else
+               return path;
+}
+
 //
 // Construction and maintainance
 //
-ResourceBuilder::ResourceBuilder(const std::string &root, CFDictionaryRef rulesDict, CodeDirectory::HashAlgorithm hashType)
-       : mRoot(root), mHashType(hashType)
+ResourceBuilder::ResourceBuilder(const std::string &root, const std::string &relBase,
+       CFDictionaryRef rulesDict, CodeDirectory::HashAlgorithm hashType, bool strict, const MacOSErrorSet& toleratedErrors)
+       : mHashType(hashType),
+         mCheckUnreadable(strict && toleratedErrors.find(errSecCSSignatureNotVerifiable) == toleratedErrors.end()),
+         mCheckUnknownType(strict && toleratedErrors.find(errSecCSResourceNotSupported) == toleratedErrors.end())
 {
-       assert(!mRoot.empty());
-    if (mRoot.substr(mRoot.length()-2, 2) == "/.")  // produced by versioned bundle implicit "Current" case
-        mRoot = mRoot.substr(0, mRoot.length()-2);  // ... so take it off for this
+       assert(!root.empty());
+       mRoot = removeTrailingSlash(root);
+       mRelBase = removeTrailingSlash(relBase);
+       if (mRoot != mRelBase && mRelBase != mRoot + "/Contents")
+               MacOSError::throwMe(errSecCSInternalError);
        const char * paths[2] = { mRoot.c_str(), NULL };
        mFTS = fts_open((char * const *)paths, FTS_PHYSICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
        if (!mFTS)
@@ -125,6 +140,14 @@ void ResourceBuilder::scan(Scanner next)
     
        while (FTSENT *ent = fts_read(mFTS)) {
                const char *relpath = ent->fts_path + mRoot.size() + 1; // skip prefix + "/"
+               std::string rp;
+               if (mRelBase != mRoot) {
+                       assert(mRelBase == mRoot + "/Contents");
+                       rp = "../" + string(relpath);
+                       if (rp.substr(0, 12) == "../Contents/")
+                               rp = rp.substr(12);
+                       relpath = rp.c_str();
+               }
                switch (ent->fts_info) {
                case FTS_F:
                        secdebug("rdirenum", "file %s", ent->fts_path);
@@ -178,9 +201,16 @@ void ResourceBuilder::scan(Scanner next)
                case FTS_DP:
                        secdebug("rdirenum", "leaving %s", ent->fts_path);
                        break;
+               case FTS_DNR:
+                       secdebug("rdirenum", "cannot read directory %s", ent->fts_path);
+                       if (mCheckUnreadable)
+                               MacOSError::throwMe(errSecCSSignatureNotVerifiable);
+                       break;
                default:
                        secdebug("rdirenum", "type %d (errno %d): %s",
                                ent->fts_info, ent->fts_errno, ent->fts_path);
+                       if (mCheckUnknownType)
+                               MacOSError::throwMe(errSecCSResourceNotSupported);
                        break;
                }
        }
index 749939da9ff4b6d118359ba21ed6fe1537bcb4bc..3bdd8e8b3b7e844ecac1a917052858bd7fc50435 100644 (file)
@@ -49,7 +49,8 @@ namespace CodeSigning {
 class ResourceBuilder {
        NOCOPY(ResourceBuilder)
 public:
-       ResourceBuilder(const std::string &root, CFDictionaryRef rulesDict, CodeDirectory::HashAlgorithm hashType);
+       ResourceBuilder(const std::string &root, const std::string &relBase,
+               CFDictionaryRef rulesDict, CodeDirectory::HashAlgorithm hashType, bool strict, const MacOSErrorSet& toleratedErrors);
        ~ResourceBuilder();
 
        enum {
@@ -93,12 +94,14 @@ protected:
        void addRule(CFTypeRef key, CFTypeRef value);
        
 private:
-       std::string mRoot;
+       std::string mRoot, mRelBase;
        FTS *mFTS;
        CFCopyRef<CFDictionaryRef> mRawRules;
        typedef std::vector<Rule *> Rules;
        Rules mRules;
        CodeDirectory::HashAlgorithm mHashType;
+       bool mCheckUnreadable;
+       bool mCheckUnknownType;
 };
 
 
index 1bb8bfdf2fc7a4901c4cf3b7401c1111cc3f983c..b4e83480b9c2f2ea67ace2aeaf60060721ccf8c6 100644 (file)
@@ -162,6 +162,8 @@ _kSecAssessmentAssessmentAuthorityOverride
 _kSecAssessmentAssessmentOriginalVerdict
 _kSecAssessmentAssessmentSource
 _kSecAssessmentAssessmentVerdict
+_kSecAssessmentAssessmentWeakSignature
+_kSecAssessmentAssessmentCodeSigningError
 
 # gatekeeper logging
 
index 9b676c339b9d9b5c26c65ae0b0a06f34695d4807..c11ce0c7fa8c8fa9208a9019308c32e3d9dda723 100644 (file)
@@ -117,6 +117,10 @@ void SecCodeSigner::Signer::remove(SecCSFlags flags)
 //
 void SecCodeSigner::Signer::prepare(SecCSFlags flags)
 {
+       // make sure the rep passes strict validation
+       if (strict)
+               rep->strictValidate(MacOSErrorSet());
+
        // get the Info.plist out of the rep for some creative defaulting
        CFRef<CFDictionaryRef> infoDict;
        if (CFRef<CFDataRef> infoData = rep->component(cdInfoSlot))
@@ -232,9 +236,15 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags)
                // finally, ask the DiskRep for its default
                if (!resourceRules)
                        resourceRules.take(rep->defaultResourceRules(state));
-               
+
+               // resource root can optionally be the canonical bundle path,
+               // but sealed resource paths are always relative to rpath
+               string root = rpath;
+               if (state.signingFlags() & kSecCSSignBundleRoot)
+                       root = cfStringRelease(rep->copyCanonicalPath());
+
                // build the resource directory
-               buildResources(rpath, resourceRules);
+               buildResources(root, rpath, resourceRules);
        }
        
        // screen and set the signing time
@@ -261,7 +271,7 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags)
 // Collect the resource seal for a program.
 // This includes both sealed resources and information about nested code.
 //
-void SecCodeSigner::Signer::buildResources(std::string root, CFDictionaryRef rulesDict)
+void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase, CFDictionaryRef rulesDict)
 {
        typedef ResourceBuilder::Rule Rule;
        
@@ -284,7 +294,7 @@ void SecCodeSigner::Signer::buildResources(std::string root, CFDictionaryRef rul
                }
                // build the modern (V2) resource seal
                __block CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
-               ResourceBuilder resourceBuilder(root, rules2, digestAlgorithm());
+               ResourceBuilder resourceBuilder(root, relBase, rules2, digestAlgorithm(), strict, MacOSErrorSet());
                ResourceBuilder &resources = resourceBuilder;   // (into block)
                rep->adjustResources(resources);
                resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, Rule *rule) {
@@ -319,7 +329,7 @@ void SecCodeSigner::Signer::buildResources(std::string root, CFDictionaryRef rul
        if (!(state.signingFlags() & kSecCSSignNoV1)) {
                // build the legacy (V1) resource seal
                __block CFRef<CFMutableDictionaryRef> files = makeCFMutableDictionary();
-               ResourceBuilder resourceBuilder(root, rules, digestAlgorithm());
+               ResourceBuilder resourceBuilder(root, relBase, rules, digestAlgorithm(), strict, MacOSErrorSet());
                ResourceBuilder &resources = resourceBuilder;
                rep->adjustResources(resources);        // DiskRep-specific adjustments
                resources.scan(^(FTSENT *ent, uint32_t ruleFlags, const char *relpath, Rule *rule) {
index 495cc00c93ca66ee9687f4a85f4233c76379dab0..d27abcb2abc279f6457dd549ff24384d2a6e702a 100644 (file)
@@ -45,7 +45,8 @@ namespace CodeSigning {
 //
 class SecCodeSigner::Signer {
 public:
-       Signer(SecCodeSigner &s, SecStaticCode *c) : state(s), code(c), requirements(NULL) { }
+       Signer(SecCodeSigner &s, SecStaticCode *c) : state(s), code(c), requirements(NULL)
+       { strict = state.signingFlags() & kSecCSSignStrictPreflight; }
        ~Signer() { ::free((Requirements *)requirements); }
 
        void sign(SecCSFlags flags);
@@ -56,7 +57,7 @@ public:
        
        CodeDirectory::HashAlgorithm digestAlgorithm() const { return state.mDigestAlgorithm; }
        
-       std::string path() const { return cfString(rep->canonicalPath()); }
+       std::string path() const { return cfString(rep->copyCanonicalPath()); }
        SecIdentityRef signingIdentity() const { return state.mSigner; }
        std::string signingIdentifier() const { return identifier; }
        
@@ -74,7 +75,7 @@ protected:
        std::string uniqueName() const;                         // derive unique string from rep
 
 protected:
-       void buildResources(std::string root, CFDictionaryRef rules);
+       void buildResources(std::string root, std::string relBase, CFDictionaryRef rules);
        CFMutableDictionaryRef signNested(FTSENT *ent, const char *relpath);
        CFDataRef hashFile(const char *path);
 
@@ -89,6 +90,7 @@ private:
        const Requirements *requirements; // internal requirements ready-to-use
        size_t pagesize;                                // size of main executable pages
        CFAbsoluteTime signingTime;             // signing time for CMS signature (0 => none)
+       bool strict;                                    // strict validation
 };
 
 
index 154ed2e927e9bc5f278e3efd6b27e2cb9b9c571a..c3ba5207f7caaca5c7e9a0b2269b624456e9c04b 100644 (file)
@@ -61,7 +61,7 @@ CFDataRef SingleDiskRep::identification()
 //
 // Both the canonical and main executable path of a SingleDiskRep is, well, its path.
 //
-CFURLRef SingleDiskRep::canonicalPath()
+CFURLRef SingleDiskRep::copyCanonicalPath()
 {
        return makeCFURL(mPath);
 }
index 2ff73e10787a298e530e2e991dc887597c114050..c8e94c60099bac497c368d27913288ed7c353799 100644 (file)
@@ -48,7 +48,7 @@ public:
 
        CFDataRef identification();                                                             // partial file hash
        std::string mainExecutablePath();                                               // base path
-       CFURLRef canonicalPath();                                                               // base path
+       CFURLRef copyCanonicalPath();                                                   // base path
        size_t signingLimit();                                                                  // size of file
        UnixPlusPlus::FileDesc &fd();                                                   // readable fd for this file
        void flush();                                                                                   // close cached fd
index 468ff3025976cf2f39a4ca69bc4df23da7ebb575..fa010c9a796441932ecad56d21d1ddfff1fdc663 100644 (file)
                18B9658B1472FC5B005A4D2E /* reqparser.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383340A237F47005C63A2 /* reqparser.h */; settings = {ATTRIBUTES = (Public, ); }; };
                18B9658C1472FC9E005A4D2E /* codedirectory.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383170A237F47005C63A2 /* codedirectory.h */; settings = {ATTRIBUTES = (Public, ); }; };
                18B965951472FE30005A4D2E /* cdbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383150A237F47005C63A2 /* cdbuilder.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               7A078F651996C1C2003D68DA /* dirscanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A078F631996C1C2003D68DA /* dirscanner.cpp */; };
+               7A078F661996C1C2003D68DA /* dirscanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A078F641996C1C2003D68DA /* dirscanner.h */; };
+               7A9DA65C1948D1BA004635E6 /* opaquewhitelist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */; };
+               7A9DA65D1948D1BA004635E6 /* opaquewhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */; };
+               7ACF261219958B6F00849B25 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2CC30A00B8519CC005FA59D /* CoreFoundation.framework */; };
                BEC3A75C16F78D21003E5634 /* SecTaskPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = BEC3A75B16F78D21003E5634 /* SecTaskPriv.h */; };
                C200424D15D425D9004AE0A1 /* libsecurity_codesigning.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */; };
                C200424E15D425D9004AE0A1 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */; };
                184461A1146E9AD100B12992 /* lib.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = lib.xcconfig; sourceTree = "<group>"; };
                184461A2146E9AD100B12992 /* release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = "<group>"; };
                4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurity_codesigning.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               7A078F631996C1C2003D68DA /* dirscanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dirscanner.cpp; sourceTree = "<group>"; };
+               7A078F641996C1C2003D68DA /* dirscanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirscanner.h; sourceTree = "<group>"; };
+               7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaquewhitelist.cpp; sourceTree = "<group>"; };
+               7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = opaquewhitelist.h; sourceTree = "<group>"; };
                BEC3A75B16F78D21003E5634 /* SecTaskPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTaskPriv.h; sourceTree = "<group>"; };
                C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_codesigning.a; path = ../../../usr/local/lib/libsecurity_codesigning.a; sourceTree = "<group>"; };
                C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_utilities.a; path = ../../../usr/local/lib/libsecurity_utilities.a; sourceTree = "<group>"; };
                C2093AA70BB0948000EB8599 /* reqreader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqreader.h; sourceTree = "<group>"; };
                C209696015BF52040093035F /* gkunpack */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gkunpack; sourceTree = BUILT_PRODUCTS_DIR; };
                C209696315BF52040093035F /* gkunpack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = gkunpack.cpp; sourceTree = "<group>"; };
-               C209697215BF57EB0093035F /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecurity_utilities.a; sourceTree = "<group>"; };
+               C209697215BF57EB0093035F /* libsecurity_utilities.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libsecurity_utilities.a; sourceTree = "<group>"; };
                C2110704158BF5C8001D7F76 /* gkmerge */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = gkmerge; sourceTree = "<group>"; };
                C21CFC5D0A250D1C006CD5B1 /* reqdumper.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = reqdumper.cpp; sourceTree = "<group>"; };
                C21CFC5E0A250D1C006CD5B1 /* reqdumper.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = reqdumper.h; sourceTree = "<group>"; };
                        files = (
                                C200424D15D425D9004AE0A1 /* libsecurity_codesigning.a in Frameworks */,
                                C200424E15D425D9004AE0A1 /* libsecurity_utilities.a in Frameworks */,
+                               7ACF261219958B6F00849B25 /* CoreFoundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        children = (
                                C273606D1433F09000A9A5FF /* SecAssessment.h */,
                                C273606C1433F09000A9A5FF /* SecAssessment.cpp */,
+                               7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */,
+                               7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */,
                                C24EABAA1421432800C16AA9 /* policydb.h */,
                                C24EABAC1421433700C16AA9 /* policydb.cpp */,
                                C273601D1432A60B00A9A5FF /* policyengine.h */,
                                C2353410145F1B110073F964 /* xar++.cpp */,
                                C2F4439914C626D4000A01E6 /* quarantine++.h */,
                                C2F4439814C626D4000A01E6 /* quarantine++.cpp */,
+                               7A078F641996C1C2003D68DA /* dirscanner.h */,
+                               7A078F631996C1C2003D68DA /* dirscanner.cpp */,
                        );
                        name = "Local Utilities";
                        sourceTree = "<group>";
                                18B965861472FBF6005A4D2E /* reqdumper.h in Headers */,
                                18B965871472FC5B005A4D2E /* requirement.h in Headers */,
                                18B965881472FC5B005A4D2E /* reqmaker.h in Headers */,
+                               7A9DA65D1948D1BA004635E6 /* opaquewhitelist.h in Headers */,
                                18B965891472FC5B005A4D2E /* reqreader.h in Headers */,
                                18B9658A1472FC5B005A4D2E /* reqinterp.h in Headers */,
                                18B9658B1472FC5B005A4D2E /* reqparser.h in Headers */,
                                C2A436160F2133B2007A41A6 /* slcrep.h in Headers */,
                                C24EABAB1421432800C16AA9 /* policydb.h in Headers */,
                                C2F4439B14C626D4000A01E6 /* quarantine++.h in Headers */,
+                               7A078F661996C1C2003D68DA /* dirscanner.h in Headers */,
                                C26763D814FD9EBE00A46EDF /* drmaker.h in Headers */,
                                EBDAF050166D65FA0042CDCE /* piddiskrep.h in Headers */,
                        );
                                C2D3834F0A237F47005C63A2 /* SecRequirement.cpp in Sources */,
                                C2D383510A237F47005C63A2 /* diskrep.cpp in Sources */,
                                C2D383550A237F47005C63A2 /* filediskrep.cpp in Sources */,
+                               7A078F651996C1C2003D68DA /* dirscanner.cpp in Sources */,
                                C2D383570A237F47005C63A2 /* Code.cpp in Sources */,
                                C2D383590A237F47005C63A2 /* kerneldiskrep.cpp in Sources */,
                                C2D3835B0A237F47005C63A2 /* StaticCode.cpp in Sources */,
                                C2A436150F2133B2007A41A6 /* slcrep.cpp in Sources */,
                                FEB30C9310DAC89D00557BA2 /* SecTask.c in Sources */,
                                C24EABAD1421433700C16AA9 /* policydb.cpp in Sources */,
+                               7A9DA65C1948D1BA004635E6 /* opaquewhitelist.cpp in Sources */,
                                C273606E1433F09000A9A5FF /* SecAssessment.cpp in Sources */,
                                C27360D51436866D00A9A5FF /* xpcengine.cpp in Sources */,
                                C2DC2DCA145F594000AD2A3A /* xar++.cpp in Sources */,
diff --git a/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..4770090
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C209695F15BF52040093035F</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C26AC0EB143BCF01001C98CE</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C26AC7090DAEB3A7005BFB40</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C2BC1F250B580D3A003EC9DC</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C2BC1F2E0B580D4B003EC9DC</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C2D383B80A23A8C4005C63A2</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C2E2873F0B5D8F8F009336A0</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>EBB9FF6E1682E51300FF9774</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_comcryption/libsecurity_comcryption.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_comcryption/libsecurity_comcryption.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..2adfe6f
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>7264321D00A8AD0A7F000001</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_cryptkit/libsecurity_cryptkit.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_cryptkit/libsecurity_cryptkit.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..43c0bd9
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0535DCBD074A944D00805B04</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>0536B294074BC91A00F9F1AD</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>7264322800A8AD0A7F000001</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_cssm/libsecurity_cssm.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_cssm/libsecurity_cssm.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_filedb/libsecurity_filedb.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_filedb/libsecurity_filedb.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
index 297b76d7809df5cb4df25e7f3355c4bcdbdeb23a..efdb501f6be45d232d9fd436c4286c84a1644069 100644 (file)
@@ -402,10 +402,22 @@ SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
        OSStatus __secapiresult = errSecSuccess;
        try {
                Trust *trustObj = Trust::required(trust);
-               if (trustObj->result() == kSecTrustResultInvalid)
-                       MacOSError::throwMe(errSecTrustNotAvailable);
-               if (trustObj->evidence() == nil)
+               if (trustObj->result() == kSecTrustResultInvalid) {
+                       // Trust hasn't been evaluated; attempt to retrieve public key from leaf.
+                       SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, 0);
+                       __secapiresult = SecCertificateCopyPublicKey(cert, &pubKey);
+                       if (pubKey) {
+                               return pubKey;
+                       }
+                       // Otherwise, we must evaluate first.
+                       trustObj->evaluate();
+                       if (trustObj->result() == kSecTrustResultInvalid) {
+                               MacOSError::throwMe(errSecTrustNotAvailable);
+                       }
+               }
+               if (trustObj->evidence() == nil) {
                        trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
+               }
                evidenceChain = trustObj->evidence();
        }
        catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
@@ -470,12 +482,27 @@ SecCertificateRef SecTrustGetCertificateAtIndex(SecTrustRef trust, CFIndex ix)
        try {
                Trust *trustObj = Trust::required(trust);
                if (trustObj->result() == kSecTrustResultInvalid) {
+                       // If caller is asking for the leaf, we can return it without
+                       // having to evaluate the entire chain. Note that we don't retain
+                       // the cert as it's owned by the trust and this is a 'Get' API.
+                       if (ix == 0) {
+                               CFArrayRef certs = trustObj->certificates();
+                               if (certs && (CFArrayGetCount(certs) > 0)) {
+                                       certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certs, 0);
+                                       if (certificate) {
+                                               return certificate;
+                                       }
+                               }
+                       }
+                       // Otherwise, we must evaluate first.
                        trustObj->evaluate();
-                       if (trustObj->result() == kSecTrustResultInvalid)
+                       if (trustObj->result() == kSecTrustResultInvalid) {
                                MacOSError::throwMe(errSecTrustNotAvailable);
+                       }
                }
-               if (trustObj->evidence() == nil)
+               if (trustObj->evidence() == nil) {
                        trustObj->buildEvidence(certChain, TPEvidenceInfo::overlayVar(statusChain));
+               }
                evidenceChain = trustObj->evidence();
        }
        catch (const MacOSError &err) { __secapiresult=err.osStatus(); }
index e22acfbac4b770b6384f3862ffc2c09b798ffee9..49f2323671e69c88b97e8d3809e5674d4abf91d5 100644 (file)
@@ -327,6 +327,7 @@ void Trust::evaluate(bool disableEV)
        CFMutableArrayRef allPolicies = NULL;
        uint32 numRevocationAdded = 0;
        bool requirePerCert = (actionDataP->ActionFlags & CSSM_TP_ACTION_REQUIRE_REV_PER_CERT);
+       bool avoidRevChecks = (policySpecified(mPolicies, CSSMOID_APPLE_TP_EAP));
 
        // If a new unified revocation policy was explicitly specified,
        // convert into old-style individual OCSP and CRL policies.
@@ -350,13 +351,13 @@ void Trust::evaluate(bool disableEV)
                allPolicies = NULL; // use only mPolicies
                isEVCandidate = false;
        }
-       else if (isEVCandidate || requirePerCert) {
+       else if ((isEVCandidate && !avoidRevChecks) || requirePerCert) {
                // force revocation checking for this evaluation
                secdebug("evTrust", "Trust::evaluate() forcing OCSP/CRL revocation check");
                allPolicies = forceRevocationPolicies(numRevocationAdded,
                        context.allocator, requirePerCert);
        }
-       else if(!(revocationPolicySpecified(mPolicies))) {
+       else if(!(revocationPolicySpecified(mPolicies)) && !avoidRevChecks) {
                // none specified in mPolicies; try preferences
                allPolicies = addPreferenceRevocationPolicies(numRevocationAdded,
                        context.allocator);
index 344f81f4a355edecc9eb0d3c586fe65b74a35be4..77f8aac141f45b9f925ff257e1e54b4bb27f2596 100644 (file)
@@ -102,6 +102,7 @@ public:
        CFArrayRef evidence() const                                     { return mEvidenceReturned; }
        CFArrayRef policies() const                                     { return mPolicies; }
        CFArrayRef anchors() const                                      { return mAnchors; }
+       CFArrayRef certificates() const                         { return mCerts; }
        CFDateRef time() const                                          { return mVerifyTime; }
        AnchorPolicy anchorPolicy() const                       { return mAnchorPolicy; }
        NetworkPolicy networkPolicy() const                     { return mNetworkPolicy; }
diff --git a/libsecurity_keychain/libDER/libDER.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_keychain/libDER/libDER.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..6ace9d5
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>053BA30F091C00B100A7007A</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>053BA313091C00BF00A7007A</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>053BA444091FE58C00A7007A</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>053BA46A091FE63E00A7007A</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>058F16530925135E009FA1C5</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4C96C8CD113F4132005483E8</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_keychain/libsecurity_keychain.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_keychain/libsecurity_keychain.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..2c7d8fe
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0CBD500016C3242200713B6C</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4C5719C712FB5E9E00B31F85</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>52200F8714F2B87F00F7F6E7</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_manifest/libsecurity_manifest.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_manifest/libsecurity_manifest.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..ab80c26
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>D6C8AFAD05DD2430003DB724</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_mds/libsecurity_mds.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_mds/libsecurity_mds.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_ocspd/libsecurity_ocspd.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_ocspd/libsecurity_ocspd.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..fb66b79
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>051BDB75069B372600F9D07E</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_pkcs12/libsecurity_pkcs12.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_pkcs12/libsecurity_pkcs12.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..ee70f1d
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0592AC8B0415523C00003D05</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_sd_cspdl/libsecurity_sd_cspdl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_sd_cspdl/libsecurity_sd_cspdl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..988e9b5
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_smime/libsecurity_smime.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_smime/libsecurity_smime.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..c131493
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0540498B0A37699A0035F195</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4C2741ED03E9FBF700A80181</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>AC62F5EF18B4356A00704BBD</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
index f3a9216b00c409b75e8fdf10aca33663f07d3000..b6ad13efa9dc801a1ccf4591f8f1c47f8701a86a 100644 (file)
@@ -875,16 +875,6 @@ extern OSStatus sslCopyPeerPubKey(
     check(pubKey);
     check(ctx->peerSecTrust);
 
-#if !TARGET_OS_IPHONE
-    /* This is not required on iOS, but still required on osx */
-    if (!ctx->enableCertVerify) {
-        OSStatus status;
-        SecTrustResultType result;
-        verify_noerr_action(status = SecTrustEvaluate(ctx->peerSecTrust, &result),
-            return status);
-       }
-#endif
-
     SecKeyRef key = SecTrustCopyPublicKey(ctx->peerSecTrust);
     if (!key) {
                sslErrorLog("sslCopyPeerPubKey: %s, ctx->peerSecTrust=%p\n",
diff --git a/libsecurity_ssl/libsecurity_ssl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_ssl/libsecurity_ssl.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..48b06b6
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0C1C92EF15C8AC81007D377B</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>0C6C633A15D1BD4800BC68CD</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>0CCA415815C89E8B002AEC4C</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>0CCA42C815C8A387002AEC4C</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>0CCA42D615C8A395002AEC4C</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurity_transform/libsecurity_transform.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_transform/libsecurity_transform.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..dee7a39
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4C010B86121AE8DF0094CB72</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4C738256112DF65200EA003B</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CBCBEB51130A2D700CC18E9</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
index 13d5b59987ea0117816187a2a50ebc9c625ca5c2..478835fe6e435d647f272e72185d9708e7400e2d 100644 (file)
@@ -127,10 +127,9 @@ CFTypeRef CFMake::make()
                return makespecial();
        case ']':
        case '}':
-               assert(false);  // unexpected
                return NULL;    // error
        default:
-               if (isdigit(*format))
+               if (isdigit(*format) || *format == '-')
                        return makenumber();
                else if (isalpha(*format))
                        return makestring();
index 942f5ec81df73898db1832224ec3cda19f9d9be0..5bc5378d251786a4b0426ba2c750c7d1040196f5 100644 (file)
@@ -249,6 +249,28 @@ CFDataRef cfLoadFile(CFURLRef url)
        }
 }
 
+CFDataRef cfLoadFile(int fd, size_t bytes)
+{
+       uint8_t *buffer = (uint8_t *) malloc(bytes);
+
+       if (buffer == NULL)
+               return NULL;
+
+       if (read(fd, buffer, bytes) != bytes) {
+               free(buffer);
+               return NULL;
+       }
+
+       CFDataRef result = CFDataCreateWithBytesNoCopy(kCFAllocatorMalloc, buffer, bytes, kCFAllocatorMalloc);
+
+       // If CFDataCreateWithBytesNoCopy fails, the buffer is not free()-ed
+       if (result == NULL) {
+               free(buffer);
+               return NULL;
+       }
+
+       return result;
+}
 
 //
 // CFArray creators
index dd1a7e8bcef94dcf06fba039dbe7b1a447e980fd..4481f170457bb948e12bc93472a16b050098a46a 100644 (file)
@@ -499,12 +499,23 @@ private:
                void (T::*func)(CFTypeRef key, CFTypeRef value);
                static void apply(CFTypeRef key, CFTypeRef value, void *context)
                { Applier *me = (Applier *)context; return ((me->object)->*(me->func))(key, value); }
-       };              
+       };
+       
+       template <class Key, class Value>
+       struct BlockApplier {
+               void (^action)(Key key, Value value);
+               static void apply(CFTypeRef key, CFTypeRef value, void* context)
+               { BlockApplier *me = (BlockApplier *)context; return me->action(Key(key), Value(value)); }
+       };
 
 public:        
        template <class T>
        void apply(T *object, void (T::*func)(CFTypeRef key, CFTypeRef value))
        { Applier<T> app; app.object = object; app.func = func; return apply(app.apply, &app); }
+       
+       template <class Key = CFTypeRef, class Value = CFTypeRef>
+       void apply(void (^action)(Key key, Value value))
+       { BlockApplier<Key, Value> app; app.action = action; return apply(app.apply, &app); }
 
 private:
        OSStatus mDefaultError;
@@ -515,6 +526,7 @@ private:
 // CFURLAccess wrappers for specific purposes
 //
 CFDataRef cfLoadFile(CFURLRef url);
+CFDataRef cfLoadFile(int fd, size_t bytes);
 inline CFDataRef cfLoadFile(CFStringRef path) { return cfLoadFile(CFTempURL(path)); }
 inline CFDataRef cfLoadFile(const std::string &path) { return cfLoadFile(CFTempURL(path)); }
 inline CFDataRef cfLoadFile(const char *path) { return cfLoadFile(CFTempURL(path)); }
index dfc686d5c76ef9c33bd2077a5cbb682d729ee443..9208379ac16b17b9653179e4b3c3f6db4404bb30 100644 (file)
@@ -32,6 +32,7 @@
 #include <exception>
 #include <errno.h>
 #include <Security/SecBase.h>
+#include <set>
 #undef check
 
 
@@ -94,6 +95,8 @@ public:
     static void check(OSStatus status) { if (status != errSecSuccess) throwMe(status); }
     static void throwMe(int err) __attribute__((noreturn));
 };
+       
+typedef std::set<OSStatus> MacOSErrorSet;
 
 
 //
index e6f39de314088bf6d4c90ec8bd9822c7a44340d2..ff26e5943ac56a3b33d1cee0bd0df5b3a4318a39 100644 (file)
 // macho++ - Mach-O object file helpers
 //
 #include "macho++.h"
+#include <security_utilities/alloc.h>
 #include <security_utilities/memutils.h>
 #include <security_utilities/endian.h>
 #include <mach-o/dyld.h>
+#include <list>
+#include <algorithm>
+#include <iterator>
 
 namespace Security {
 
+/* Maximum number of archs a fat binary can have */
+static const int MAX_ARCH_COUNT = 100;
+/* Maximum power of 2 that a mach-o can be aligned by */
+static const int MAX_ALIGN = 30;
 
 //
 // Architecture values
@@ -132,6 +140,7 @@ void MachOBase::initHeader(const mach_header *header)
                m64 = true;
                break;
        default:
+               secdebug("macho", "%p: unrecognized header magic (%x)", this, mHeader->magic);
                UnixError::throwMe(ENOEXEC);
        }
 }
@@ -164,8 +173,10 @@ size_t MachOBase::commandSize() const
 // (not relative to some intermediate container).
 //
 MachO::MachO(FileDesc fd, size_t offset, size_t length)
-       : FileDesc(fd), mOffset(offset), mLength(length ? length : (fd.fileSize() - offset))
+       : FileDesc(fd), mOffset(offset), mLength(length), mSuspicious(false)
 {
+       if (mOffset == 0)
+               mLength = fd.fileSize();
        size_t size = fd.read(&mHeaderBuffer, sizeof(mHeaderBuffer), mOffset);
        if (size != sizeof(mHeaderBuffer))
                UnixError::throwMe(ENOEXEC);
@@ -177,6 +188,45 @@ MachO::MachO(FileDesc fd, size_t offset, size_t length)
        if (fd.read(mCommandBuffer, cmdSize, this->headerSize() + mOffset) != cmdSize)
                UnixError::throwMe(ENOEXEC);
        this->initCommands(mCommandBuffer);
+       /* If we do not know the length, we cannot do a verification of the mach-o structure */
+       if (mLength != 0)
+               this->validateStructure();
+}
+
+void MachO::validateStructure()
+{
+       bool isValid = false;
+
+       /* There should be either an LC_SEGMENT, an LC_SEGMENT_64, or an LC_SYMTAB
+        load_command and that + size must be equal to the end of the arch */
+       for (const struct load_command *cmd = loadCommands(); cmd != NULL; cmd = nextCommand(cmd)) {
+               uint32_t cmd_type = flip(cmd->cmd);
+               struct segment_command *seg = NULL;
+               struct segment_command_64 *seg64 = NULL;
+               struct symtab_command *symtab = NULL;
+
+               if (cmd_type ==  LC_SEGMENT) {
+                       seg = (struct segment_command *)cmd;
+                       if (strcmp(seg->segname, SEG_LINKEDIT) == 0) {
+                               isValid = flip(seg->fileoff) + flip(seg->filesize) == this->length();
+                               break;
+                       }
+               } else if (cmd_type == LC_SEGMENT_64) {
+                       seg64 = (struct segment_command_64 *)cmd;
+                       if (strcmp(seg64->segname, SEG_LINKEDIT) == 0) {
+                               isValid = flip(seg64->fileoff) + flip(seg64->filesize) == this->length();
+                               break;
+                       }
+               /* PPC binaries have a SYMTAB section */
+               } else if (cmd_type == LC_SYMTAB) {
+                       symtab = (struct symtab_command *)cmd;
+                       isValid = flip(symtab->stroff) + flip(symtab->strsize) == this->length();
+                       break;
+               }
+       }
+
+       if (!isValid)
+               mSuspicious = true;
 }
 
 MachO::~MachO()
@@ -386,13 +436,12 @@ CFDataRef MachO::dataAt(size_t offset, size_t size)
        return buffer;
 }
 
-
 //
 // Fat (aka universal) file wrappers.
 // The offset is relative to the start of the containing file.
 //
-Universal::Universal(FileDesc fd, size_t offset /* = 0 */)
-       : FileDesc(fd), mBase(offset)
+Universal::Universal(FileDesc fd, size_t offset /* = 0 */, size_t length /* = 0 */)
+       : FileDesc(fd), mBase(offset), mLength(length), mSuspicious(false)
 {
        union {
                fat_header header;              // if this is a fat file
@@ -434,6 +483,67 @@ Universal::Universal(FileDesc fd, size_t offset /* = 0 */)
                        }
                        secdebug("macho", "%p is a fat file with %d architectures",
                                this, mArchCount);
+
+                       /* A Mach-O universal file has padding of no more than "page size"
+                        * between the header and slices. This padding must be zeroed out or the file
+                          is not valid */
+                       std::list<struct fat_arch *> sortedList;
+                       for (unsigned i = 0; i < mArchCount; i++)
+                               sortedList.push_back(mArchList + i);
+
+                       sortedList.sort(^ bool (const struct fat_arch *arch1, const struct fat_arch *arch2) { return arch1->offset < arch2->offset; });
+
+                       const size_t universalHeaderEnd = mBase + sizeof(header) + (sizeof(fat_arch) * mArchCount);
+                       size_t prevHeaderEnd = universalHeaderEnd;
+                       size_t prevArchSize = 0, prevArchStart = 0;
+
+                       for (auto iterator = sortedList.begin(); iterator != sortedList.end(); ++iterator) {
+                               auto ret = mSizes.insert(std::pair<size_t, size_t>((*iterator)->offset, (*iterator)->size));
+                               if (ret.second == false) {
+                                       ::free(mArchList);
+                                       MacOSError::throwMe(errSecInternalError); // Something is wrong if the same size was encountered twice
+                               }
+
+                               size_t gapSize = (*iterator)->offset - prevHeaderEnd;
+
+                               /* The size of the padding after the universal cannot be calculated to a fixed size */
+                               if (prevHeaderEnd != universalHeaderEnd) {
+                                       if (((*iterator)->align > MAX_ALIGN) || gapSize >= (1 << (*iterator)->align)) {
+                                               mSuspicious = true;
+                                               break;
+                                       }
+                               }
+
+                               // validate gap bytes in tasty page-sized chunks
+                               CssmAutoPtr<uint8_t> gapBytes(Allocator::standard().malloc<uint8_t>(PAGE_SIZE));
+                               size_t off = 0;
+                               while (off < gapSize) {
+                                       size_t want = min(gapSize - off, (size_t)PAGE_SIZE);
+                                       size_t got = fd.read(gapBytes, want, prevHeaderEnd + off);
+                                       off += got;
+                                       for (size_t x = 0; x < got; x++) {
+                                               if (gapBytes[x] != 0) {
+                                                       mSuspicious = true;
+                                                       break;
+                                               }
+                                       }
+                                       if (mSuspicious)
+                                               break;
+                               }
+                               if (off != gapSize)
+                                       mSuspicious = true;
+                               if (mSuspicious)
+                                       break;
+
+                               prevHeaderEnd = (*iterator)->offset + (*iterator)->size;
+                               prevArchSize = (*iterator)->size;
+                               prevArchStart = (*iterator)->offset;
+                       }
+
+                       /* If there is anything extra at the end of the file, reject this */
+                       if (!mSuspicious && (prevArchStart + prevArchSize != fd.fileSize()))
+                               mSuspicious = true;
+
                        break;
                }
        case MH_MAGIC:
@@ -460,6 +570,13 @@ Universal::~Universal()
        ::free(mArchList);
 }
 
+const size_t Universal::lengthOfSlice(size_t offset) const
+{
+       auto ret = mSizes.find(offset);
+       if (ret == mSizes.end())
+               MacOSError::throwMe(errSecInternalError);
+       return ret->second;
+}
 
 //
 // Get the "local" architecture from the fat file
@@ -470,7 +587,7 @@ MachO *Universal::architecture() const
        if (isUniversal())
                return findImage(bestNativeArch());
        else
-               return new MachO(*this, mBase);
+               return new MachO(*this, mBase, mLength);
 }
 
 size_t Universal::archOffset() const
@@ -506,6 +623,15 @@ size_t Universal::archOffset(const Architecture &arch) const
                UnixError::throwMe(ENOEXEC);
 }
 
+size_t Universal::archLength(const Architecture &arch) const
+{
+       if (isUniversal())
+               return mBase + findArch(arch)->size;
+       else if (mThinArch.matches(arch))
+               return this->fileSize();
+       else
+               UnixError::throwMe(ENOEXEC);
+}
 
 //
 // Get the architecture at a specified offset from the fat file.
@@ -573,11 +699,10 @@ Architecture Universal::bestNativeArch() const
                return mThinArch;
 }
 
-
 //
 // List all architectures from the fat file's list.
 //
-void Universal::architectures(Architectures &archs)
+void Universal::architectures(Architectures &archs) const
 {
        if (isUniversal()) {
                for (unsigned n = 0; n < mArchCount; n++)
@@ -588,7 +713,6 @@ void Universal::architectures(Architectures &archs)
        }
 }
 
-
 //
 // Quickly guess the Mach-O type of a file.
 // Returns type zero if the file isn't Mach-O or Universal.
@@ -627,5 +751,22 @@ uint32_t Universal::typeOf(FileDesc fd)
     return 0;
 }
 
+//
+// Strict validation
+//
+bool Universal::isSuspicious() const
+{
+       if (mSuspicious)
+               return true;
+       Universal::Architectures archList;
+       architectures(archList);
+       for (Universal::Architectures::const_iterator it = archList.begin(); it != archList.end(); ++it) {
+               auto_ptr<MachO> macho(architecture(*it));
+               if (macho->isSuspicious())
+                       return true;
+       }
+       return false;
+}
+
 
 } // Security
index 54fb4abb3808e2e46ef5f9d502c3eee4b6c85369..4cfc6ba13031d5018c51b78a3833caaa86fc2957 100644 (file)
@@ -34,6 +34,7 @@
 #include <security_utilities/endian.h>
 #include <security_utilities/unix++.h>
 #include <security_utilities/cfutilities.h>
+#include <map>
 
 namespace Security {
 
@@ -143,6 +144,9 @@ public:
 
        void seek(size_t offset);       // relative to start of image
        CFDataRef dataAt(size_t offset, size_t size);
+       void validateStructure();       // is the structure of the mach-o sane
+
+       bool isSuspicious() const { return mSuspicious; }
 
 private:
        size_t mOffset;                 // starting file offset
@@ -150,6 +154,8 @@ private:
        
        mach_header mHeaderBuffer; // read-in Mach-O header
        load_command *mCommandBuffer; // read-in (malloc'ed) Mach-O load commands
+
+       bool mSuspicious;               // strict validation failed
 };
 
 
@@ -182,7 +188,7 @@ public:
 //
 class Universal : public UnixPlusPlus::FileDesc {
 public:
-       Universal(FileDesc fd, size_t offset = 0);
+       Universal(FileDesc fd, size_t offset = 0, size_t length = 0);
        ~Universal();
        
        // return a genuine MachO object for the given architecture
@@ -193,16 +199,21 @@ public:
        // return (just) the starting offset of an architecture
        size_t archOffset() const;                      // native
        size_t archOffset(const Architecture &arch) const; // given
+       size_t archLength(const Architecture &arch) const; // given
        bool narrowed() const { return mBase != 0; }    // part of a fat file
        
        // return a set of architectures contained
        typedef std::set<Architecture> Architectures;
-       void architectures(Architectures &archs);
+       void architectures(Architectures &archs) const;
        
        bool isUniversal() const { return mArchList != NULL; }
        Architecture bestNativeArch() const;
+       const size_t lengthOfSlice(size_t offset) const;
        
        size_t offset() const { return mBase; }
+       size_t length() const { return mLength; }
+       
+       bool isSuspicious() const;
        
 public:
        static uint32_t typeOf(FileDesc fd);
@@ -216,6 +227,10 @@ private:
        unsigned mArchCount;            // number of architectures (if fat)
        Architecture mThinArch;         // single architecture (if thin)
        size_t mBase;                           // overriding offset in file (all types)
+       size_t mLength;                         // length of the architecture if thin file
+       typedef std::map<size_t, size_t> OffsetsToLength;
+       OffsetsToLength mSizes; // the length for the slice at a given offset
+       bool mSuspicious;                       // strict validation failed
 };
 
 
index 9e9643ac7c1f6d1130caef54331edbfd06830677..57bc9c9dc569f3feccd53014b594591a4abb684c 100644 (file)
@@ -342,6 +342,16 @@ std::string FileDesc::getAttr(const std::string &name, int options /* = 0 */)
                return string();
 }
 
+bool FileDesc::isPlainFile(const std::string &path)
+{
+       UnixStat st1, st2;
+       this->fstat(st1);
+       if (::lstat(path.c_str(), &st2))
+               UnixError::throwMe();
+
+       return (st1.st_ino == st2.st_ino && S_ISREG(st2.st_mode));
+}
+
 
 //
 // Stat support
index 03895d085cbd29cb9ea1224f080385d08427091b..f9dbe92f2d8eba58e16b26028d4cfca71846b9e8 100644 (file)
@@ -231,6 +231,9 @@ public:
     // stdio interactions
     FILE *fdopen(const char *mode = NULL);     // fdopen(3)
 
+       // Is this a regular file? (not a symlink, fifo, etc.)
+       bool isPlainFile(const std::string &path);
+
 private:
     int mFd;                           // UNIX file descriptor
 
diff --git a/libsecurity_utilities/libsecurity_utilities.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurity_utilities/libsecurity_utilities.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..a78d8bc
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4CA2A5390523D32800978A7B</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C2C9C69D0CECBE8400B3FE07</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/libsecurityd/libsecurityd.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/libsecurityd/libsecurityd.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..c9daec4
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>4C09A2920557240300FED7A3</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4C31C2D9055341AA006D00BD</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEBD052A3C8100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CA1FEC8052A44A100F22E42</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>C2A788530B7AA65B00CFF85C</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/sec/sec.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist b/sec/sec.xcodeproj/xcuserdata/jkauth.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644 (file)
index 0000000..c028ee7
--- /dev/null
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>SuppressBuildableAutocreation</key>
+       <dict>
+               <key>0C0BDB55175687EC00BC1A7E</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>18270F5414CF651900B05E7F</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>186CDD0E14CA116C00AF9171</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>18D4043414CE0CF300A2BE4E</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>18D4056114CE53C200A2BE4E</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4A5CCA4E15ACEFA500702357</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4A824AFB158FF07000F932C0</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>4CC92AC215A3BC6B00C6D578</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>5284029F164445760035F320</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>BEF963FE18B4171200813FA3</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>E702E73514E1F3EA00CDE635</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>E702E75714E1F48800CDE635</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>E71049F1169E023B00DB0045</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>E7104A12169E216E00DB0045</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>E76079971951FD2800F69731</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+               <key>E7FEFB82169E363300E18152</key>
+               <dict>
+                       <key>primary</key>
+                       <true/>
+               </dict>
+       </dict>
+</dict>
+</plist>
index fc4f83488857a31ca49282aa948642ce389e2a3d..271a8f15e1e2d7f262138d9a04696462e2045275 100644 (file)
@@ -213,7 +213,7 @@ static void tests(void)
 
     // Both in circle.
 
-    // Emulation of <rdar://problem/13919554> Innsbruck11A368 +Roots: Device A was removed when Device B joined.
+    // Emulation of <rdar://problem/13919554>
 
     // 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
index 29485ea852175cc9fd09b0dc17a19331adf6ce5a..c6dec55c939ba1f7b966555260c6ab3c223913ac 100644 (file)
@@ -611,7 +611,7 @@ struct sql_stages {
    the script in the main table.
     {pre,main,post, reencode} */
 static struct sql_stages s3dl_upgrade_script[] = {
-    { -1, 0, 1, false },/* 0->current: Create version 6 (Innsbruck) database. */
+    { -1, 0, 1, false },/* 0->current: Create version 6 database. */
     {},                 /* 1->current: Upgrade to version 6 from version 1 (LittleBear) -- Unsupported. */
     {},                 /* 2->current: Upgrade to version 6 from version 2 (BigBearBeta) -- Unsupported */
     {},                 /* 3->current: Upgrade to version 6 from version 3 (Apex) -- Unsupported */