From 1c2f211c7e5671dc9869f425bd06f5d4a7824b23 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 15:36:21 -0700 Subject: [PATCH 001/118] Update project files to Xcode 7 recommended settings --- TrustKit.xcodeproj/project.pbxproj | 7 ++++- .../xcshareddata/TrustKit.xcscmblueprint | 30 +++++++++++++++++++ .../xcshareddata/xcschemes/TrustKit.xcscheme | 13 ++++---- .../xcschemes/TrustKit_Static.xcscheme | 13 ++++---- TrustKit/Info.plist | 2 +- TrustKitTests/Info.plist | 2 +- 6 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 TrustKit.xcodeproj/project.xcworkspace/xcshareddata/TrustKit.xcscmblueprint diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 98c099ee..779e6c95 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -414,7 +414,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = TSK; - LastUpgradeCheck = 0640; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = TrustKit; TargetAttributes = { 8C8480461A896EE30017C155 = { @@ -554,6 +554,7 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -640,6 +641,7 @@ "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", ); ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; SDKROOT = "$(inherited)"; @@ -668,6 +670,7 @@ "$(PROJECT_DIR)/TrustKit", "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", ); + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; SDKROOT = "$(inherited)"; @@ -693,6 +696,7 @@ GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = TrustKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @loader_path/../Frameworks @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = "$(inherited)"; SUPPORTED_PLATFORMS = "$(inherited)"; @@ -712,6 +716,7 @@ GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = TrustKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @loader_path/../Frameworks @executable_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = "$(inherited)"; SUPPORTED_PLATFORMS = "$(inherited)"; diff --git a/TrustKit.xcodeproj/project.xcworkspace/xcshareddata/TrustKit.xcscmblueprint b/TrustKit.xcodeproj/project.xcworkspace/xcshareddata/TrustKit.xcscmblueprint new file mode 100644 index 00000000..86042de7 --- /dev/null +++ b/TrustKit.xcodeproj/project.xcworkspace/xcshareddata/TrustKit.xcscmblueprint @@ -0,0 +1,30 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "E302059AEA03412BDA59789695F25F6B3B3F4EE6", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "E302059AEA03412BDA59789695F25F6B3B3F4EE6" : 0, + "2B8D60F823B54095FDE698DB84D10E9A0B2DB18B" : 0 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "FEA687C9-BCA7-46D9-BC27-A17B542FAC0A", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "E302059AEA03412BDA59789695F25F6B3B3F4EE6" : "TrustKit", + "2B8D60F823B54095FDE698DB84D10E9A0B2DB18B" : "github\/PLPatchMaster" + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "TrustKit", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "TrustKit.xcodeproj", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/plausiblelabs\/PLPatchMaster.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "2B8D60F823B54095FDE698DB84D10E9A0B2DB18B" + }, + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:datatheorem\/TrustKit.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "E302059AEA03412BDA59789695F25F6B3B3F4EE6" + } + ] +} \ No newline at end of file diff --git a/TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit.xcscheme b/TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit.xcscheme index d2a9444f..2cae9d5d 100644 --- a/TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit.xcscheme +++ b/TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:TrustKit.xcodeproj"> + + + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:TrustKit.xcodeproj"> + + CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.datatheorem.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/TrustKitTests/Info.plist b/TrustKitTests/Info.plist index eeb14bac..ba72822e 100644 --- a/TrustKitTests/Info.plist +++ b/TrustKitTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.datatheorem.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName From ebfaf3d503cb561c294416816c6cfb3cead706fa Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 15:51:03 -0700 Subject: [PATCH 002/118] Enable bitcode in build settings except for the tests --- TrustKit.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 779e6c95..c8447c0e 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -553,6 +553,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -601,6 +602,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; + ENABLE_BITCODE = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -632,6 +634,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = YES; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -662,6 +665,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_BITCODE = YES; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -730,6 +734,7 @@ APPLICATION_EXTENSION_API_ONLY = "$(inherited)"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_BITCODE = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -756,6 +761,7 @@ COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_BITCODE = YES; GCC_NO_COMMON_BLOCKS = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LIBRARY_SEARCH_PATHS = ( From 24b89b02a00d4ed148ca01bb5b6e12d48342b146 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 16:00:04 -0700 Subject: [PATCH 003/118] Fix bitcode settings --- TrustKit.xcodeproj/project.pbxproj | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index c8447c0e..f5ae1173 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -553,7 +553,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; - ENABLE_BITCODE = NO; + ENABLE_BITCODE = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -602,7 +602,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 1; - ENABLE_BITCODE = NO; + ENABLE_BITCODE = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -634,7 +634,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = YES; + ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -665,7 +665,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_BITCODE = YES; + ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; @@ -689,6 +689,7 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; + ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)", "$(inherited)", @@ -713,6 +714,7 @@ buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; COMBINE_HIDPI_IMAGES = YES; + ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(SDKROOT)", "$(inherited)", @@ -734,7 +736,7 @@ APPLICATION_EXTENSION_API_ONLY = "$(inherited)"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_BITCODE = YES; + ENABLE_BITCODE = "$(inherited)"; GCC_NO_COMMON_BLOCKS = YES; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -761,7 +763,7 @@ COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_BITCODE = YES; + ENABLE_BITCODE = "$(inherited)"; GCC_NO_COMMON_BLOCKS = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.3; LIBRARY_SEARCH_PATHS = ( From 96b0a240f2409b6ddce58c3762b27f04b609eb01 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 16:09:46 -0700 Subject: [PATCH 004/118] Do not build for armv7s --- TrustKit.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index f5ae1173..3ca23794 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -575,7 +575,7 @@ SDKROOT = macosx; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx"; TARGETED_DEVICE_FAMILY = "1,2"; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; + VALID_ARCHS = "arm64 armv7 x86_64"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; @@ -617,7 +617,7 @@ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos macosx"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; + VALID_ARCHS = "arm64 armv7 x86_64"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; From 84373e66217e7fd2a04421a2db650f706cd5ab5e Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 16:12:06 -0700 Subject: [PATCH 005/118] Inherit architectures --- TrustKit.xcodeproj/project.pbxproj | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 3ca23794..aa8e1861 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -650,7 +650,7 @@ SDKROOT = "$(inherited)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; + VALID_ARCHS = "$(inherited)"; }; name = Debug; }; @@ -680,7 +680,7 @@ SDKROOT = "$(inherited)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; + VALID_ARCHS = "$(inherited)"; }; name = Release; }; @@ -705,7 +705,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = "$(inherited)"; SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; + VALID_ARCHS = "$(inherited)"; }; name = Debug; }; @@ -726,7 +726,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = "$(inherited)"; SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; + VALID_ARCHS = "$(inherited)"; }; name = Release; }; @@ -753,6 +753,7 @@ SDKROOT = "$(inherited)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "$(inherited)"; + VALID_ARCHS = "$(inherited)"; }; name = Debug; }; @@ -775,6 +776,7 @@ SDKROOT = "$(inherited)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "$(inherited)"; + VALID_ARCHS = "$(inherited)"; }; name = Release; }; From 51e7fd2c093b37fa72e0daa70320c790e6723e07 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 17:28:01 -0700 Subject: [PATCH 006/118] Split project targets in two ,OS X and IOS, and add pre-built libs for each target --- TrustKit.xcodeproj/project.pbxproj | 339 ++++++++++++++++-- .../domain_registry/ios/libassert_lib.a | Bin 0 -> 19512 bytes .../ios/libdomain_registry_lib.a | Bin 0 -> 119608 bytes .../ios/libinit_registry_tables_lib.a | Bin 0 -> 479104 bytes .../domain_registry/libassert_lib.a | Bin 14672 -> 0 bytes .../domain_registry/libdomain_registry_lib.a | Bin 87752 -> 0 bytes .../libinit_registry_tables_lib.a | Bin 427064 -> 0 bytes .../domain_registry/osx/libassert_lib.a | Bin 0 -> 2984 bytes .../osx/libdomain_registry_lib.a | Bin 0 -> 16704 bytes .../osx/libinit_registry_tables_lib.a | Bin 0 -> 129088 bytes 10 files changed, 319 insertions(+), 20 deletions(-) create mode 100644 TrustKit/Dependencies/domain_registry/ios/libassert_lib.a create mode 100644 TrustKit/Dependencies/domain_registry/ios/libdomain_registry_lib.a create mode 100644 TrustKit/Dependencies/domain_registry/ios/libinit_registry_tables_lib.a delete mode 100644 TrustKit/Dependencies/domain_registry/libassert_lib.a delete mode 100644 TrustKit/Dependencies/domain_registry/libdomain_registry_lib.a delete mode 100644 TrustKit/Dependencies/domain_registry/libinit_registry_tables_lib.a create mode 100644 TrustKit/Dependencies/domain_registry/osx/libassert_lib.a create mode 100644 TrustKit/Dependencies/domain_registry/osx/libdomain_registry_lib.a create mode 100644 TrustKit/Dependencies/domain_registry/osx/libinit_registry_tables_lib.a diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index aa8e1861..d465b9e2 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -28,9 +28,6 @@ 8C8480531A896EE30017C155 /* TrustKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C8480471A896EE30017C155 /* TrustKit.framework */; }; 8C84806D1A896F660017C155 /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C84806C1A896F660017C155 /* TrustKit.m */; }; 8C8716AD1B23A9D200267E1D /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919311AEA0F8B002B29AE /* fishhook.c */; }; - 8C8716AE1B23A9DD00267E1D /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CE9192A1AEA0F7E002B29AE /* libassert_lib.a */; }; - 8C8716AF1B23A9DD00267E1D /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CE9192B1AEA0F7E002B29AE /* libdomain_registry_lib.a */; }; - 8C8716B01B23A9DD00267E1D /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CE9192C1AEA0F7E002B29AE /* libinit_registry_tables_lib.a */; }; 8C8716B11B23A9F000267E1D /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; }; 8C8716B21B23A9F400267E1D /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */; }; 8C8716B31B23A9F700267E1D /* TSKPinFailureReport.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F99F1B16094D00F06C0E /* TSKPinFailureReport.m */; }; @@ -42,6 +39,49 @@ 8C9492F61B2379A100F5DF38 /* reporting_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C9492F51B2379A100F5DF38 /* reporting_utils.h */; }; 8C9EBE021B619BBE00CA7EE0 /* TSKReportsRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C9EBE001B619BBE00CA7EE0 /* TSKReportsRateLimiter.h */; }; 8C9EBE031B619BBE00CA7EE0 /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */; }; + 8CA6CC071BAE2ADD00BDA419 /* TrustKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CBFD1BAE2ADD00BDA419 /* TrustKit.framework */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC141BAE2B6600BDA419 /* TSKReportsRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C9EBE001B619BBE00CA7EE0 /* TSKReportsRateLimiter.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC151BAE2B6600BDA419 /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC161BAE2B6600BDA419 /* TSKReporterDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919261AEA0991002B29AE /* TSKReporterDelegate.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC171BAE2B6600BDA419 /* TSKSimpleReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B032D3D1AF1A4AC00EAFA69 /* TSKSimpleReporter.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC181BAE2B6600BDA419 /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC191BAE2B6600BDA419 /* TSKBackgroundReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B2B06AC1B05154A00FC749E /* TSKBackgroundReporter.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC1A1BAE2B6600BDA419 /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC1B1BAE2B6600BDA419 /* TSKPinFailureReport.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F99E1B16094D00F06C0E /* TSKPinFailureReport.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC1C1BAE2B6600BDA419 /* TSKPinFailureReport.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F99F1B16094D00F06C0E /* TSKPinFailureReport.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC1D1BAE2B6600BDA419 /* reporting_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C9492F51B2379A100F5DF38 /* reporting_utils.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC1E1BAE2B6600BDA419 /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCBD15A1B186D1100CB88AF /* reporting_utils.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC1F1BAE2B6A00BDA419 /* public_key_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE9191C1AEA073C002B29AE /* public_key_utils.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC201BAE2B6A00BDA419 /* public_key_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE9191D1AEA073C002B29AE /* public_key_utils.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC211BAE2B6A00BDA419 /* ssl_pin_verifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919241AEA07C5002B29AE /* ssl_pin_verifier.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC221BAE2B6A00BDA419 /* ssl_pin_verifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC231BAE2B6A00BDA419 /* TSKPinningValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F9911B132F9200F06C0E /* TSKPinningValidator.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC241BAE2B6A00BDA419 /* TSKPinningValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F9921B132F9200F06C0E /* TSKPinningValidator.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C84804C1A896EE30017C155 /* TrustKit.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C84806C1A896F660017C155 /* TrustKit.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC271BAE2B7000BDA419 /* domain_registry.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919291AEA0F7E002B29AE /* domain_registry.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC281BAE2B7500BDA419 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919311AEA0F8B002B29AE /* fishhook.c */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC291BAE2B7500BDA419 /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919321AEA0F8B002B29AE /* fishhook.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC2F1BAE2C0700BDA419 /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC2C1BAE2C0700BDA419 /* libassert_lib.a */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC301BAE2C0700BDA419 /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC2D1BAE2C0700BDA419 /* libdomain_registry_lib.a */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC311BAE2C0700BDA419 /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC2E1BAE2C0700BDA419 /* libinit_registry_tables_lib.a */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC351BAE2C1100BDA419 /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC321BAE2C1100BDA419 /* libassert_lib.a */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC361BAE2C1100BDA419 /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC331BAE2C1100BDA419 /* libdomain_registry_lib.a */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC371BAE2C1100BDA419 /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC341BAE2C1100BDA419 /* libinit_registry_tables_lib.a */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC381BAE2C7200BDA419 /* TSKPinValidationOnlineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0710306B1AA88A510028092C /* TSKPinValidationOnlineTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC3A1BAE2C7C00BDA419 /* TSKReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC3B1BAE2C7E00BDA419 /* TSKPinConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F9A31B17564400F06C0E /* TSKPinConfigurationTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC3C1BAE2C8100BDA419 /* TSKPublicKeyAlgorithmTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC78B241B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC3D1BAE2C8500BDA419 /* TSKCertificateUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC78B1F1B1B586F00523A25 /* TSKCertificateUtils.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC3E1BAE2E8300BDA419 /* www.good.com.selfsigned.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868BA1AE1672D00E5AFDC /* www.good.com.selfsigned.der */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC3F1BAE2E8300BDA419 /* GoodRootCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868B41ADFF6B000E5AFDC /* GoodRootCA.der */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC401BAE2E8300BDA419 /* GoodIntermediateCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868B11ADFF67200E5AFDC /* GoodIntermediateCA.der */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC411BAE2E8300BDA419 /* www.good.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868B21ADFF67200E5AFDC /* www.good.com.der */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC421BAE2E8600BDA419 /* ThawteSSLCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B211B1B604A00523A25 /* ThawteSSLCA.der */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC431BAE2E8600BDA419 /* www.datatheorem.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B221B1B604A00523A25 /* www.datatheorem.com.der */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC441BAE2E8800BDA419 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1C1B1B55EC00523A25 /* COMODOECCDomainValidationSecureServerCA2.der */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC451BAE2E8800BDA419 /* sni41871.cloudflaressl.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1D1B1B55EC00523A25 /* sni41871.cloudflaressl.com.der */; settings = {ASSET_TAGS = (); }; }; 8CC78B201B1B586F00523A25 /* TSKCertificateUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC78B1F1B1B586F00523A25 /* TSKCertificateUtils.m */; }; 8CC78B251B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC78B241B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m */; }; 8CC78B261B1B696500523A25 /* ThawteSSLCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B211B1B604A00523A25 /* ThawteSSLCA.der */; }; @@ -55,9 +95,6 @@ 8CE919251AEA07C5002B29AE /* ssl_pin_verifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919241AEA07C5002B29AE /* ssl_pin_verifier.h */; }; 8CE919271AEA0991002B29AE /* TSKReporterDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919261AEA0991002B29AE /* TSKReporterDelegate.h */; }; 8CE9192D1AEA0F7E002B29AE /* domain_registry.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919291AEA0F7E002B29AE /* domain_registry.h */; }; - 8CE9192E1AEA0F7E002B29AE /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CE9192A1AEA0F7E002B29AE /* libassert_lib.a */; }; - 8CE9192F1AEA0F7E002B29AE /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CE9192B1AEA0F7E002B29AE /* libdomain_registry_lib.a */; }; - 8CE919301AEA0F7E002B29AE /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CE9192C1AEA0F7E002B29AE /* libinit_registry_tables_lib.a */; }; 8CE919351AEA0F8B002B29AE /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919311AEA0F8B002B29AE /* fishhook.c */; }; 8CE919361AEA0F8B002B29AE /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919321AEA0F8B002B29AE /* fishhook.h */; }; /* End PBXBuildFile section */ @@ -70,6 +107,13 @@ remoteGlobalIDString = 8C8480461A896EE30017C155; remoteInfo = TrustKit; }; + 8CA6CC081BAE2ADD00BDA419 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8C84803E1A896EE30017C155 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8CA6CBFC1BAE2ADD00BDA419; + remoteInfo = "TrustKit OS X"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -112,6 +156,14 @@ 8C9492F51B2379A100F5DF38 /* reporting_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = reporting_utils.h; path = Reporting/reporting_utils.h; sourceTree = ""; }; 8C9EBE001B619BBE00CA7EE0 /* TSKReportsRateLimiter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKReportsRateLimiter.h; path = Reporting/TSKReportsRateLimiter.h; sourceTree = ""; }; 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKReportsRateLimiter.m; path = Reporting/TSKReportsRateLimiter.m; sourceTree = ""; }; + 8CA6CBFD1BAE2ADD00BDA419 /* TrustKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TrustKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8CA6CC061BAE2ADD00BDA419 /* TrustKit OS XTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "TrustKit OS XTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 8CA6CC2C1BAE2C0700BDA419 /* libassert_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libassert_lib.a; path = Dependencies/domain_registry/osx/libassert_lib.a; sourceTree = ""; }; + 8CA6CC2D1BAE2C0700BDA419 /* libdomain_registry_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdomain_registry_lib.a; path = Dependencies/domain_registry/osx/libdomain_registry_lib.a; sourceTree = ""; }; + 8CA6CC2E1BAE2C0700BDA419 /* libinit_registry_tables_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libinit_registry_tables_lib.a; path = Dependencies/domain_registry/osx/libinit_registry_tables_lib.a; sourceTree = ""; }; + 8CA6CC321BAE2C1100BDA419 /* libassert_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libassert_lib.a; path = Dependencies/domain_registry/ios/libassert_lib.a; sourceTree = ""; }; + 8CA6CC331BAE2C1100BDA419 /* libdomain_registry_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdomain_registry_lib.a; path = Dependencies/domain_registry/ios/libdomain_registry_lib.a; sourceTree = ""; }; + 8CA6CC341BAE2C1100BDA419 /* libinit_registry_tables_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libinit_registry_tables_lib.a; path = Dependencies/domain_registry/ios/libinit_registry_tables_lib.a; sourceTree = ""; }; 8CC78B1C1B1B55EC00523A25 /* COMODOECCDomainValidationSecureServerCA2.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = COMODOECCDomainValidationSecureServerCA2.der; sourceTree = ""; }; 8CC78B1D1B1B55EC00523A25 /* sni41871.cloudflaressl.com.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = sni41871.cloudflaressl.com.der; sourceTree = ""; }; 8CC78B1E1B1B586F00523A25 /* TSKCertificateUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSKCertificateUtils.h; sourceTree = ""; }; @@ -126,9 +178,6 @@ 8CE919241AEA07C5002B29AE /* ssl_pin_verifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ssl_pin_verifier.h; path = Pinning/ssl_pin_verifier.h; sourceTree = ""; }; 8CE919261AEA0991002B29AE /* TSKReporterDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKReporterDelegate.h; path = Reporting/TSKReporterDelegate.h; sourceTree = ""; }; 8CE919291AEA0F7E002B29AE /* domain_registry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = domain_registry.h; path = Dependencies/domain_registry/domain_registry.h; sourceTree = ""; }; - 8CE9192A1AEA0F7E002B29AE /* libassert_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libassert_lib.a; path = Dependencies/domain_registry/libassert_lib.a; sourceTree = ""; }; - 8CE9192B1AEA0F7E002B29AE /* libdomain_registry_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdomain_registry_lib.a; path = Dependencies/domain_registry/libdomain_registry_lib.a; sourceTree = ""; }; - 8CE9192C1AEA0F7E002B29AE /* libinit_registry_tables_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libinit_registry_tables_lib.a; path = Dependencies/domain_registry/libinit_registry_tables_lib.a; sourceTree = ""; }; 8CE919311AEA0F8B002B29AE /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fishhook.c; path = Dependencies/fishhook/fishhook.c; sourceTree = ""; }; 8CE919321AEA0F8B002B29AE /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fishhook.h; path = Dependencies/fishhook/fishhook.h; sourceTree = ""; }; /* End PBXFileReference section */ @@ -138,9 +187,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8CE9192F1AEA0F7E002B29AE /* libdomain_registry_lib.a in Frameworks */, - 8CE9192E1AEA0F7E002B29AE /* libassert_lib.a in Frameworks */, - 8CE919301AEA0F7E002B29AE /* libinit_registry_tables_lib.a in Frameworks */, + 8CA6CC361BAE2C1100BDA419 /* libdomain_registry_lib.a in Frameworks */, + 8CA6CC351BAE2C1100BDA419 /* libassert_lib.a in Frameworks */, + 8CA6CC371BAE2C1100BDA419 /* libinit_registry_tables_lib.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -156,9 +205,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 8C8716AF1B23A9DD00267E1D /* libdomain_registry_lib.a in Frameworks */, - 8C8716AE1B23A9DD00267E1D /* libassert_lib.a in Frameworks */, - 8C8716B01B23A9DD00267E1D /* libinit_registry_tables_lib.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8CA6CBF91BAE2ADD00BDA419 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8CA6CC301BAE2C0700BDA419 /* libdomain_registry_lib.a in Frameworks */, + 8CA6CC2F1BAE2C0700BDA419 /* libassert_lib.a in Frameworks */, + 8CA6CC311BAE2C0700BDA419 /* libinit_registry_tables_lib.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8CA6CC031BAE2ADD00BDA419 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8CA6CC071BAE2ADD00BDA419 /* TrustKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -178,10 +242,9 @@ 8C3492901ADCA059001849FD /* domain_registry */ = { isa = PBXGroup; children = ( + 8CA6CC2B1BAE2BF000BDA419 /* OS X */, + 8CA6CC2A1BAE2BEA00BDA419 /* iOS */, 8CE919291AEA0F7E002B29AE /* domain_registry.h */, - 8CE9192A1AEA0F7E002B29AE /* libassert_lib.a */, - 8CE9192B1AEA0F7E002B29AE /* libdomain_registry_lib.a */, - 8CE9192C1AEA0F7E002B29AE /* libinit_registry_tables_lib.a */, ); name = domain_registry; sourceTree = ""; @@ -201,6 +264,8 @@ 8C8480471A896EE30017C155 /* TrustKit.framework */, 8C8480521A896EE30017C155 /* TrustKitTests.xctest */, 8C8716961B23A91D00267E1D /* libTrustKit_Static.a */, + 8CA6CBFD1BAE2ADD00BDA419 /* TrustKit.framework */, + 8CA6CC061BAE2ADD00BDA419 /* TrustKit OS XTests.xctest */, ); name = Products; sourceTree = ""; @@ -260,6 +325,26 @@ name = fishhook; sourceTree = ""; }; + 8CA6CC2A1BAE2BEA00BDA419 /* iOS */ = { + isa = PBXGroup; + children = ( + 8CA6CC321BAE2C1100BDA419 /* libassert_lib.a */, + 8CA6CC331BAE2C1100BDA419 /* libdomain_registry_lib.a */, + 8CA6CC341BAE2C1100BDA419 /* libinit_registry_tables_lib.a */, + ); + name = iOS; + sourceTree = ""; + }; + 8CA6CC2B1BAE2BF000BDA419 /* OS X */ = { + isa = PBXGroup; + children = ( + 8CA6CC2C1BAE2C0700BDA419 /* libassert_lib.a */, + 8CA6CC2D1BAE2C0700BDA419 /* libdomain_registry_lib.a */, + 8CA6CC2E1BAE2C0700BDA419 /* libinit_registry_tables_lib.a */, + ); + name = "OS X"; + sourceTree = ""; + }; 8CC78B191B1B54F700523A25 /* ECDSA sec256r1 */ = { isa = PBXGroup; children = ( @@ -351,6 +436,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8CA6CBFA1BAE2ADD00BDA419 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8CA6CC171BAE2B6600BDA419 /* TSKSimpleReporter.h in Headers */, + 8CA6CC1B1BAE2B6600BDA419 /* TSKPinFailureReport.h in Headers */, + 8CA6CC141BAE2B6600BDA419 /* TSKReportsRateLimiter.h in Headers */, + 8CA6CC211BAE2B6A00BDA419 /* ssl_pin_verifier.h in Headers */, + 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */, + 8CA6CC191BAE2B6600BDA419 /* TSKBackgroundReporter.h in Headers */, + 8CA6CC271BAE2B7000BDA419 /* domain_registry.h in Headers */, + 8CA6CC161BAE2B6600BDA419 /* TSKReporterDelegate.h in Headers */, + 8CA6CC231BAE2B6A00BDA419 /* TSKPinningValidator.h in Headers */, + 8CA6CC1D1BAE2B6600BDA419 /* reporting_utils.h in Headers */, + 8CA6CC1F1BAE2B6A00BDA419 /* public_key_utils.h in Headers */, + 8CA6CC291BAE2B7500BDA419 /* fishhook.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -407,6 +511,42 @@ productReference = 8C8716961B23A91D00267E1D /* libTrustKit_Static.a */; productType = "com.apple.product-type.library.static"; }; + 8CA6CBFC1BAE2ADD00BDA419 /* TrustKit OS X */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8CA6CC121BAE2ADD00BDA419 /* Build configuration list for PBXNativeTarget "TrustKit OS X" */; + buildPhases = ( + 8CA6CBF81BAE2ADD00BDA419 /* Sources */, + 8CA6CBF91BAE2ADD00BDA419 /* Frameworks */, + 8CA6CBFA1BAE2ADD00BDA419 /* Headers */, + 8CA6CBFB1BAE2ADD00BDA419 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "TrustKit OS X"; + productName = "TrustKit OS X"; + productReference = 8CA6CBFD1BAE2ADD00BDA419 /* TrustKit.framework */; + productType = "com.apple.product-type.framework"; + }; + 8CA6CC051BAE2ADD00BDA419 /* TrustKit OS XTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8CA6CC131BAE2ADD00BDA419 /* Build configuration list for PBXNativeTarget "TrustKit OS XTests" */; + buildPhases = ( + 8CA6CC021BAE2ADD00BDA419 /* Sources */, + 8CA6CC031BAE2ADD00BDA419 /* Frameworks */, + 8CA6CC041BAE2ADD00BDA419 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 8CA6CC091BAE2ADD00BDA419 /* PBXTargetDependency */, + ); + name = "TrustKit OS XTests"; + productName = "TrustKit OS XTests"; + productReference = 8CA6CC061BAE2ADD00BDA419 /* TrustKit OS XTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -427,6 +567,12 @@ 8C8716951B23A91D00267E1D = { CreatedOnToolsVersion = 6.3.2; }; + 8CA6CBFC1BAE2ADD00BDA419 = { + CreatedOnToolsVersion = 7.0; + }; + 8CA6CC051BAE2ADD00BDA419 = { + CreatedOnToolsVersion = 7.0; + }; }; }; buildConfigurationList = 8C8480411A896EE30017C155 /* Build configuration list for PBXProject "TrustKit" */; @@ -444,6 +590,8 @@ 8C8480461A896EE30017C155 /* TrustKit */, 8C8716951B23A91D00267E1D /* TrustKit_Static */, 8C8480511A896EE30017C155 /* TrustKitTests */, + 8CA6CBFC1BAE2ADD00BDA419 /* TrustKit OS X */, + 8CA6CC051BAE2ADD00BDA419 /* TrustKit OS XTests */, ); }; /* End PBXProject section */ @@ -471,6 +619,28 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8CA6CBFB1BAE2ADD00BDA419 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8CA6CC041BAE2ADD00BDA419 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8CA6CC421BAE2E8600BDA419 /* ThawteSSLCA.der in Resources */, + 8CA6CC3F1BAE2E8300BDA419 /* GoodRootCA.der in Resources */, + 8CA6CC401BAE2E8300BDA419 /* GoodIntermediateCA.der in Resources */, + 8CA6CC411BAE2E8300BDA419 /* www.good.com.der in Resources */, + 8CA6CC451BAE2E8800BDA419 /* sni41871.cloudflaressl.com.der in Resources */, + 8CA6CC431BAE2E8600BDA419 /* www.datatheorem.com.der in Resources */, + 8CA6CC441BAE2E8800BDA419 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */, + 8CA6CC3E1BAE2E8300BDA419 /* www.good.com.selfsigned.der in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -521,6 +691,36 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 8CA6CBF81BAE2ADD00BDA419 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8CA6CC201BAE2B6A00BDA419 /* public_key_utils.m in Sources */, + 8CA6CC1A1BAE2B6600BDA419 /* TSKBackgroundReporter.m in Sources */, + 8CA6CC1C1BAE2B6600BDA419 /* TSKPinFailureReport.m in Sources */, + 8CA6CC241BAE2B6A00BDA419 /* TSKPinningValidator.m in Sources */, + 8CA6CC1E1BAE2B6600BDA419 /* reporting_utils.m in Sources */, + 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */, + 8CA6CC281BAE2B7500BDA419 /* fishhook.c in Sources */, + 8CA6CC151BAE2B6600BDA419 /* TSKReportsRateLimiter.m in Sources */, + 8CA6CC181BAE2B6600BDA419 /* TSKSimpleReporter.m in Sources */, + 8CA6CC221BAE2B6A00BDA419 /* ssl_pin_verifier.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8CA6CC021BAE2ADD00BDA419 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8CA6CC381BAE2C7200BDA419 /* TSKPinValidationOnlineTests.m in Sources */, + 8CA6CC3A1BAE2C7C00BDA419 /* TSKReporterTests.m in Sources */, + 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */, + 8CA6CC3C1BAE2C8100BDA419 /* TSKPublicKeyAlgorithmTests.m in Sources */, + 8CA6CC3B1BAE2C7E00BDA419 /* TSKPinConfigurationTests.m in Sources */, + 8CA6CC3D1BAE2C8500BDA419 /* TSKCertificateUtils.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -529,6 +729,11 @@ target = 8C8480461A896EE30017C155 /* TrustKit */; targetProxy = 8C8480541A896EE30017C155 /* PBXContainerItemProxy */; }; + 8CA6CC091BAE2ADD00BDA419 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8CA6CBFC1BAE2ADD00BDA419 /* TrustKit OS X */; + targetProxy = 8CA6CC081BAE2ADD00BDA419 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -641,7 +846,7 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/TrustKit", - "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", + "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/ios", ); ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; @@ -672,7 +877,7 @@ LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/TrustKit", - "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", + "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/ios", ); PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -688,6 +893,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COMBINE_HIDPI_IMAGES = YES; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -713,6 +919,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = NO; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COMBINE_HIDPI_IMAGES = YES; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( @@ -780,6 +987,80 @@ }; name = Release; }; + 8CA6CC0E1BAE2ADD00BDA419 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "$(SRCROOT)/TrustKit/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/osx"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = com.datatheorem.TrustKit; + PRODUCT_NAME = TrustKit; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 8CA6CC0F1BAE2ADD00BDA419 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "$(SRCROOT)/TrustKit/Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/osx"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = com.datatheorem.TrustKit; + PRODUCT_NAME = TrustKit; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 8CA6CC101BAE2ADD00BDA419 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = TrustKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.TrustKit-OS-XTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 8CA6CC111BAE2ADD00BDA419 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = TrustKitTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.TrustKit-OS-XTests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -819,6 +1100,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 8CA6CC121BAE2ADD00BDA419 /* Build configuration list for PBXNativeTarget "TrustKit OS X" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8CA6CC0E1BAE2ADD00BDA419 /* Debug */, + 8CA6CC0F1BAE2ADD00BDA419 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8CA6CC131BAE2ADD00BDA419 /* Build configuration list for PBXNativeTarget "TrustKit OS XTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8CA6CC101BAE2ADD00BDA419 /* Debug */, + 8CA6CC111BAE2ADD00BDA419 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 8C84803E1A896EE30017C155 /* Project object */; diff --git a/TrustKit/Dependencies/domain_registry/ios/libassert_lib.a b/TrustKit/Dependencies/domain_registry/ios/libassert_lib.a new file mode 100644 index 0000000000000000000000000000000000000000..3eeecd9ef3ca8f3bc7f85e4bbee0f1e4700e29c8 GIT binary patch literal 19512 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 Ca}`$r literal 0 HcmV?d00001 diff --git a/TrustKit/Dependencies/domain_registry/ios/libdomain_registry_lib.a b/TrustKit/Dependencies/domain_registry/ios/libdomain_registry_lib.a new file mode 100644 index 0000000000000000000000000000000000000000..b5fe84f9c6c3411d814b2f373f53e1714293d1f5 GIT binary patch literal 119608 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

`yGJ{(eF{EGQl#8=FS;PpSyA{3_c5 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 z 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ð)Qn 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⪼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 I=tsCWnQZ2ss>BQ4;KXE z1r|g?z(s0Vjssm1H76ce0(Izv28TF|jzlfgWT?QVsUsCewFN3&N5KZr=gJI?AQv11 zW$|*WFjDtpfD8m;@>01G5t{g{ld~fGiJ12RgR@24*ueNz3$62gfkKjO*;qB|ZEOj) z1Ax(Uk*S_73NNy&)nc2L8+l3l4YXSpK#Ec$`x`h*yc;SLDXlkvLma|R+ENtdL==g& zxmu#$n+l~6L(g6Usy4rQH>XYj=VG-DmRoMr7GNo1B*xjN?qffA{HIS&BzlPqx+6~3 z6(Vpr>hdIaB!+dGStBvMFr+M-L^^=)2D4Bgz?a&@`5+*_c|!g~aJ{xI71)SUNSQMO z@*+W9Q_D3Y>62V4%S9%nfydF_8G?v#)8#s5t{ZDc)(V3d-hq|0nZOle!t{Dl!5jv- z2w@6BfvqSf6zx=6K#-?4Q>g(i-W(0(0_`XYlXX$iHV03lDWDAvHWPzV#WIDu4y3pVLVF!S3n5{!cG1KN z+Grz$OQ^gxq}6VO_$D`TYCVV~&4ma$%hkHIz*g91?ZV2sfq&2tPPp8+mNFqJST12L zY#xVu1CxM%_M{6SWe7Doa6X|etR;|v>d*|LY~o=wbGK|4@=f}Ns#}uuGL0WCwhX&! zu(WDoLTE&cV-t6on)aqtaUx<(YC%klEnBxGn-wnxY1SkJMeuUe0=bNRih6*3Dus>v zwlzt+4IorNOynqZXc0ytIU*&Ps0F*rDX3g|d~QiDfKUp8CbO~2bCgY6yfEO1@xa!z zvd94zBFl~2%Jo#hT`^g(h&UisgBEm<;Wpwz@M()!u0+TxmYv149%JH3hQyykd{bG* z_8_AeWn0UPgqo$Sb8LfolzR+DW<;2Pg=AJ=xYrdK>jZV#L|7vtvahWImw1HAk_2xEUu3vm!s33>1}988 z#|K<_q=jgR;3LowQK*GLpgt0LBJJ94370i{dBLL0WO>6P;ODX#aDv?srxJ>vCSd+h zW}*|eVoM}XYpNK@)d<@Q0Os6l1IAXJj@STUA;wh=v^bZ@nn*ckd*}(ql_7S4UEqeR z$K{vwCdOeC5t5wg!Yh$LG{y^{h3rkrCXm2Okw5W-NReRAz=jRl+9rW>DC0M@lnOjR z1y{5^+47koi{XvLXo#UiGMB)$D-1y8ad@(;4tN>4EC*aX9oCzdd|2y{1>uu`Oq7>6FfA1JP7mk0@5ssRvYxQ19kPR`23U~46s z?Ab7V395nY5((U*Axj!*l5ncQ%jnE(=P-W`;^+uQ%K}S4FSM^snX|hI0sxob30`Z` ziQE|)<{{Y=FvFSBRfCO4Cn$>97ILA!ocSTw+5nc>xwg(Fk#v1oV1Z>ybYoSxuZ?eJ zWC$}Xq3edtjcS196$Z*Y;B^ati9{|p)LO2AVT~@!2}?s=qDdJcIuo?))u31b+>B#_I-=2;M zs1wMP0xz^K&sLBLC=0K&O6M+pq2eJpdJl5_b?jYN4nSXo?LI?Cpr%ku%f^ z9*Mw-{A(Y~Sg3$QFIldK8t!XRDXV~|2S##GjOL(QI3*Cp$7o%atweP|V>1^pOz^Zt z!Vze?aR(KFGFu?ta&+7sLtfE3DIf-yMX0kFr8xqRI3O;a2#G`T1x2B8D8%=*)YDOf z&`K;QHDU2&AY_6%guP;omK^j zDhrvATvJSrqPMiwMKq8?VD|zSu!D#V1$f)l=Bx-K3|M8dFUOl(Atvzj2tK+o{AC(Ffp7%^LVYg~1+}(BwYS6# zX!2IE4!CLzq9(9Nys2&PDOBljyU2vbA@)S88|O=q9YG8*2Aa4&+{X_aN_Pq+p*cA6 z9Ubsvq#Uy$1Ko%KR0$1`&6s|T1VO#rF><8}V|D}so|q-5Cg8Sh)vLi4+5Zr4vQ#&T28?lTHqvtlfZ?tk17)UL@c|6OfhLh=e8rNALejrv*dwup`ouDmWl)%84LygWaK;k{hy$C@CFw#^HF~wVAYnL2_ zDlRcd{JZR@Q5td;l)yr?VG7VfU5WKqqR3aS1FPIfvS}(hTP#&M*Tc5;+RsDiuWbnm zVl*MjMFm7B;1~;tp90=h2}{QhIO?O>`ExZ7VI)Ko?YLJ91A!^!M^a+kIz(8u4i;76r zqQxvzJc`#fW~@d;Q9>wa3f(p|YHcwQTA)@$uZ)j{78N0RD&#bzmaa_%kYX#fl~zKr ztK!pZLEWgc3|fFg*moSJ4c4L4lypv%05a;$?J|#WA&h>O0BP|RIeVjg8zO=m^6-m| zp*fFZJW1(tR{-6Nx(w7zKy+bw+eh@cp-sG~o|0;g>WDGo4Q!E2VF*%+UB;ke)A|S* zBbJEMxoQilDZn~yrPV13D89#v!fu2yuRk1G3YYt*Wv?$gvgvg10GOUGwxC`qd zu{C0eRA@B8r4Vv#U@tv*ZS$x@KXGC*vM=wAm=I(cvSc8HP(^|dfevTXOn~DN#DV3T zP}YshDhU`e!wH?v%^At|&`cyGhm_-(4=x(g$vzUk24is8%q+1XLSuFpYbauhs%f@>e!-Iph@<6xtBo+ABqE!@Rs$B)1FTt^LTS*1YgiJY z0~hT}3ETY~iVT#e8Wh|%ITF+({xNzb@vx}4u|MPvsWws@(1L>{K>;2Mx){g+ZK*AS zm^_cx86MsQX@Mq70X8!SMi38pBqw?i0SjawyaqIIp`uIT5n7_A!mxCAV%00ub7Vyb z!AK-RG*_R3Zi1XAhHYRo@LR%p*HBEmvC3pHP&B}i00kR!;b(7NWhAh$ygn00^l@>m zt@@#>)(~JSfI-HMN>#Xa6!vz`&cd*uBp?nusxlV^d8Q|rS}5VNbjj4|wpUrocr%KL z%gnDVQLd|ZangvEfwDE! zj=jocM7GJ>Px3px#E(;;qvi#!%`fewB3FMAR@;i7%)n<`EdoHDZ$GHSS6QeM75nrj ziE5HLk0`h0+B{BH?i#lusW2@{T$_wAl2zd%7k+{v1x`j2V7nIb8ydBJ=UFX7_NWy@ zcJsSA_~6AX3C|jZF8!Dfw#r{*p!D)Y^<1zXaSPk`_*IttJ%+xLfdMbV>T;3a&hg8Y z5fvwXl!YKrZQ+`%nx3o#(fT5I)Ntrp4r+E1HFN#*p_-lYw!I%JtA@ztJ7tnsI{P(Q;-Qor@Zw1BQv5V z)Z*(U?qY;QxG`;h_LEw~xX)>b7ICu~@bjQrZV8n`1tD{{!r&4%euu78fSjLQ^oWt_ zb@C3M*A75Uh$t=gzy`Q(k%P3hIZm=&@f6#;*n)a#jcQR8u98$`?c9}*Iw}sg+%@_vKFBhz_>4$IiQV@c zRi)z9^JW0<!I3ufz2-GC(sSA%PlfJ5J%G!xF8AcV63TrYE%D5=4>A9f=qtGIV81w5u$c6J;7MzT=$%H62Kk zL@m=0oP&dUq1H{KRq(L@ejn*%o{b^YwQf^YS&Y6;jGM^d*0dX-5njQWozx>&G=^VQ zy1A(op+qLW?L|2*jtJd}Dsz~}W}Kl2bIK4$%>0}(cvJGNOB-*e`0XO9BLYAuh5Mdk zXWwJ=V2TTBd~mCbAC97}oPQ-f-$fL^_gb(IIsMjsbQl(ncVsGgm{bM7u-4a7ld_?J@j zP@^XREoFX$G@62lNH=Y(z$6hI_=qP0A@*enu_G#4S9vpK!m`9W^en4p6A{ogiF^{3 z(ia8^tfUlYVG5C;W%$`gBfTD-4J5*rGQyCq0}yo)dyUVsikk$tkeo~-f>Y!WXp+9x zoit5UKa{)z(e3*_KUNO;6oS0#RFNxs$zC@>6kqzTioQl+>%+g#An?<8J5QV3>wJCJEXP;FuFGALs6Iu+5Yt$Ny+Y}!pH zk+hO{X3dtUR!lTX<1$f&E06#KK&_|Rv6o99UaBEIF&}jxh*wr!k$$?fdD4{k^MqtHO0%i~3Pz%TsoihZq^O(z>`sfWv7K$&R%}_~^#D#n)ak66wm88-z%NDTw%^ z#M;6_6*Y}mvM#%5F&#fYl}FrMA8 zp=^0Kz!~gV%vHu`lXk>O?$;|jkT)gJsUE+;Mr(}W&{ci6;}9db4JaywmQGzskT;(X z*#+LVE0RX+W4HMxUq^Y|)n6><=f%~W@DMa5bkr5G>LZNC^^3t7iIKbxkVtqnQVdjw zT32kz2mxkH6vcBCe?3<*k%^OZOss{0j})Y1*&(WR>F(!rheR$|`D2;){-R zb*mCTfphG_>MkW>Tw5as=hzj0kx3~&R=(G+Z4=GLqG#hxB1B2ILR=v<3LLaXVkS01 z2wWQjMy1pRxgoZ#MpTi?HBxR*BB)xUBEg9MGdR-UXkhpSY>3Qy=q~xEw`dE%LA8oL z)@J$ce;~X=ts(cgq=Mr?qPiv~?P_mIPuuY-TpKayj4vvP8gxV37RPaAp=of?(CWcQXwjR?_{2U||FCpcuoq*&V6p+p2 z_nyc1yKOfKoBN3*XpZG3N>_Z>X?EB(KM@?u`3_^0^LeUt0@4t!t3IBUG4pNDJu$3j z9<_&6*w)oE8K2r($JJxkjALBlJdb0ffG#oa%Y}}iBoZmBl_6OfFT#h^Va~`?>G>?xpR}waQkB5%jm02cL!C4vHTf!5)2~#9uoxKlz#38=j39AHvqPIh z4}=hD80sP~i{x%Y-3$dPy3l2)>jtEenKhKyZ3M8RDnl@X=!BjSIj6v|wQbenJS&kI zNwWcohteeClKYh*j`4W(k58qhT&3+)9!adC2f9HjYQ$%27|28q&5&Y^*o7-2xi*n+ z`uYN#GwTYcasLK!)*(k^)QD9X(?1Arry-XDxR#@Xvv*CENkT7Eujj{zn$MYuK z8F!r&11=>%3LN8Z;o4mWlXg}n0bB#R0NElE!^k(1Da3)Bnn<%E0h2`SW~k(uLgUGd zgN<&Nk~<<#@^@@xhskD;*~EIf0{teND`<*HhT9iQ{=j$Rat|mW)*#H}s+mK{_R@^Fsv<%~DwG})Z%s$*UG~>IMFb~8ia9$f z<$4Y=<;>kqn{k&S3+-kcb#1C@9W*KGdP1byzQY_C&CMwB6`=$R$yU}}N2NkJO1B}j zmr7j-Ld9&@$@K;Zj)bXmIa9$*Uzkso97IZA$S1Wp)fAm`gMcJ=UHVjk0U?!({7hm0 z+!Q)5*uEE#LDKK$dd7kca3rQ0F{~sGT{7L2%B-@5PSQ{`@a+q>)r({mx>mZTsE(2Z84$zuaH#TRCLaObCn6g#3@I6C%s$IcbVOOoyrem~_ zN}|b5C6(@swW0GWk_UM}PHI_ObC0S|P>;!xS{jrrF#78p-d3(pEMPpht$zS9boU}ZE4&`v9F zMegb4C39EA4A$u=Nfb^vg;Bch30Y2yumB4M-#tbxPv<$z2(p|K`%989%s(CVL*c%ZAh%&-<}m80j?@Lr4aATE8z=^oDf&pi?l4YJ z&*Bt1o#F2nbpU2VX|IXxNKI2|YSygimq6w0Cq`n+_sQM6T98QOwKE6$Evq8qDT2@@*xPc~ zjBHbp?YCSZl@twPXm35|QsC1m%5}ZQENqfCJf0{-1h<+Tv)gitwMB4HQfn(h0=MMM ztO2pMBBHe*9b1o}r)1+e%Mh9lYP!QB`mlI#O zP;*jk%v>Eomr+LzWJJo#vaV$x_tdZ@0|02Q9hT&ZU|6*nPe!C#>;dLmV= zCQ{K_qI(?I(XvBBiy|e7rNF@Hf=(K!2$Yo-m2?S=y7C9f8ZaCQA?s(d6rjvy5%TF~ zvs|=6xI`E)=K-OBLz#6U1EW_UxKOpM$Ps`S$dCe&l)~*znPf@o@J6nB0+1SRHL9@J zhI{M!BEnb;`i3$=wQuW=Svjka`LpE9a@DrF7O!=q^(GsRV?s3r#siMAC8!yXv#=@g zG!^cHx35j{_)4BCP8E{S=9(FwJ&yK?sLFTR=;n&yk^;3uzOgfr+$=(^Wm@73X>&*< zF$NzWtH16>($IcHGM3I@~oXW~#Fg+?re$_V7Bl z?Y3-r^(b};g&o_%fl=~ogDb$xg}~VfMT@7MuJ#Pmj__{UaT~c@TOqndDILVp&oo9ci6FpkC@eG zNdF*eIe132Fg;U_o=MUN<8oM%^M&U@KQ3!~w;8w3)+MYnZp??%%VG1ONxIUbCmjEX z`S#U(LSd0GW#W|1duFGjXF^f|ed_m)j5+ zUbLx6RxV79#Iz~|V82=GI4vY}ASw^)grhfFO3s62!jTS!pR(QF1xB3G3X&dIX6sWp zw%&lqr--QKtV+;TC0$SHM4~reu1-@Y80lz9=2LFNWDz1{nn0(_IafMSVt2~bSxG&1^xjk{9H*MvNT=rpGbDw$fZ(ZSUpw*iRJrGwba%E-&rm9 z%5B%zf8$kD^o*FcbZl_X4Ro%s&4n|5?@TmU)DN<4F+Za&QlqmfxnPLSDoGA{r%J%i zcEnqO%Sg{}DU`MrEVvABoM;Fn{-dWecGa7qNig`BkVy}8(b2HS%+4G4G8(rBym}9-f-Zs!kmTDbmuNVu&RUBi>BZc2OJt}=&{F-8BUBf zR*YJgB2u=?05lydRbxz2EFGbw57y156Dz6OrpH8I2Y}mK>d)A3`^JfCO9B}ZbYnm# z2uHUa--P5ny$4GsPsH_EC{P-iseZ@BSC5u_ogr%LZM#x}vvj+GX6bXPvC@Lh5Nge~ zP?)yUd`dHOrj;I#OJ2^jY%FHUgP9h3FAZb4XTVfv<-JoSOJ=IAkU#b05Q>S4&4@YM z*81ZC-o0<+<#>zO8o}l-De95OFUm~QsTD)FnRPg)_tr;lHDp}r(WB{98Ce_^?{^$| z;{1b$@);SxqV07vMPlK`)?D7?1qeH*y2IfE?VM8ZG)X|i1jgy^I$0!-`grIZaOR)* zNz}?w;VcgqmCFfxv)bTsO-RUU5 zSIxXxVrAVNLu(@6W((6)i646xZlB5``TKeL9!^Cq_NF++FzuZVahX|XCYKW?MxBxU zD96Z=bjOUgr92m>Q`e`OakAZ*&+`j+&hcPt`_5P^fJ_^llH^%ak$y@(n|LvAw=YV@ zQj&1pq00F~K~^3qvUus?$f(}ISXZFEBn6E0=x&5Kq>#L>$;6c- zfN3JJka&L1xACnMQ9q)^I|aOHLYaqoSeZ*BQh~WFQk{Md+z5c&be)b03u{ROv22Hh zyTa{dg+Cpju^b9At3WJ&bHjEkj@Oa05v;_N-U=T~qVx;B-KyP*(@421y@@=@xS=c- zTvdKm;9li5iOw2r9)L0?t}CiUy6#F4Qp=)DuHq<)#O5g0=>j@$; zI(_tD2OhLt4&|ZzieS5=3Lzz%<~0!!A&#j0JmnNBl)pTI6vb6}hhbzT@Kz93tOx>J z3py~Wwgwn-uHr$R3I{9DwYIJ*tW_(l0vl3zeYS%{98(}vgu}ul8XVx4fJmc-Xs~9> zNxG56A3XOptEj*`tq@c*e&gcRL9K>t2Oiv#N-TV?fe6cvvrr`0ekmQ}Ev!^!9EIe) zGiyAk23@)GN1kGMN>1O7cmbh7eU8%#k*zj0LVW3P>nrlBqB-n6$jxy?#j(@edhWqV z)|o2+Omwa?hc2Nh{86XE;}Zm4+Y&BRmL19Vmk~$H$rKe?W*LYaORg({NRA+1c#T$J zO;)%)*{Y0-mh$SKjYd^@7Mj?qGUP`s74cA+$1{;NlyXBZka@^mYuj0<5K?Oh!Ew4Y zdBn?Ue?sArTf4E1JxS2W!snrD>|~4`fh3O4omyLQdc!4h+(_RFpUR5Co*On=C7Xe~sNA#{#S*vn7vI3tQ8*)%K*4zv z+IX=W2~5+CT&D5%S*G8Y+j8R~LEjN#+-zcJHmaCmly>0ptsTNBxW~j1JlIH3_3N4x zBe5e?stM1NNGhp~aMjQ)AF9;i)NEJl<(OtRtOdOF!#hCnN|kxzPU-^SxZ^`8&F8w~ z#(o`xbXs$CJU|FJA#*wX3VJHzWGj__oNGdZ$#nvosfOZ@gW5jg)?C9@=z1EtrUJ%| zqAR`zvj|Ys+#*vQUQ*`Iuug*)G+yGsTGm?v`h+X$ux>Zk`MFRRm+!`gMEnM6G0O=O z4Xz-w+|nzG5ael-*K#aM9_-nPG{o0Sf3R3NZD-H{uJ}Q<>IQ2bu^N_;m@bwV?)=#t zB2V@sCR-X3Ps zj`5rR>q}qx-q-w5u^Hd_A?Mc)J#x*N7vA+k|5EkL&98X!&g0JfJv$yf_J+H!xZ=?F zYLAWtci(!&m%jJq-V--p`jIP6=i~oy_?El>@`{<_x|5Gzk-YGZOYw|aO zSN`@hlaEgS=S%BXp7wtED|_$0d-BR#ezo@G;d?KA%ayl(|Mfpy{>Y_Yz4VdEx4(Jj zqnEzR`O)`l-+tnuyYIX5uYd6SzxB3Scq%T@k|#{cZlRbTzX@nY}S?mFmv z>)+n~{?TvU{h_N4{`mA)Ccbm&?tk~CAJ?9GFgW(!OW$|>f4J=x&I{B(KDPX=OZL5T z{vN5^`Da(@%Hzib-|0)<^zVQCycW+(whPm;d9Q(JsZ?qrx zwtjN#(t|_Se`ZrPhc4TH=8}8%yzrKrt$SV#85bTt^mG4o#WOd*&A;SId+N~K_aFGy zod;j}zM+TTe00yVh&-BZT)Xmu56|2=7_Uh^wEvaw`q^K)dhEqle0Auq{h#=EFM93O zxBO&d|4l!-^vbJ$H1xb{p8p@8{|hhs@`(F4=i+ZY*qK{#AOGxCqpNQ{G5`8IZ@TgC z{@-_`{tF*DrZ-x6>HIw#*Szwj_q^xor(bm0wKrYvp_ulcq2zy6P3bZ*xl z{`}R=hwhxZ`s$Becg-i>e9v32dHabM2e16$wI5{np=%y^eAkC&e*J@YU-GV>|FuIS ziw9r%tv#O)UU~D2e(CD#J|p{19hwGl;l%^Dzv!b{{C2$Wo*V7vZ*CseQunt@k6bhJ z^<6){W^U?DzkcU0?)l-H4<5MdH!gYYz0RB8^P9Krzv+Yb{^vbczv)k}ecnTlyzP=> zhK3(_dQkv=@uTPBOJ01%dtdX*Z+o)6=hf;<*FAjrk`LYcmlv>}I;3SFP|rBu{`GHF z?=jOg9pWJ}K&R@O`rKUGG=Z|F;pg55MU%PlEm%-|~Sk?*H7+o>bvmzJKl2m1BRRrl0-~ zzw^33-t#}ydtWp8&WC>P5}5MV%YOIHzudF$mCwBORkuF0_<|P)-`aEAV@DIc{sm<` za_1gV(o&dTFWZ&yzq>LP%-{3KMZA0F+D`}=*ZrQxS7@TuT&RTDKfdeHtG0%(H3D$m z0|CN6{j~HSyV2e__?hoN@NP}d@t++1!k%9ZuD;;|*MI!6dk+TR`G?vKAN<;$_XJPh z@T%J`&+h$bP>PeW9uEe)J{8RT&6A6*e>AkcuKq{Gj`zK&dv)_Szx>0Gi#mMu&}VLb zNZs}6AV2h`{m*}T&x@~^Y<>7M3s>w?wL3ody*>B;`*+-UeeuDo{@}7b@44|+@4xfk z?)^dV_-&8;5VifmRr!q{XwCfVp5cT4@~-L6Jo)B7c=5rxxmP_odhAtd$7e5jXzI|< zfW;%vd&8wazGnLAXKn_C+RMk!CiuGyIT{>{(3>K+Z}7e}1CUUd1F=brbuYn*%D za`3&k{>u8DFMH8#2i5L-uD$yC2pe|B){$hYtQ%E5OX`M}?Q?rP^{H@xfWH#)Dq;n&{% z>BsK;gF^xCH~~0e|+yZ|M|{O#bYo1(a~F9_sOd_z2E=tllLBb$&G(|`@_Y;-^Fjb@jJIKU;lwLK6vAy zcW-|0ny)$UzVVi+w-*mR?!0)-XILzFU9zLm{y}!NZvbmeScF(7uIQQmVx8L-mdtUeO@tfXv{p9QemtS_@O&iB=z3mmhc-bBH z#EBPt;T5krdFY1biEsWV_m2o(JoS4choAS(lWR9;(HGxpz3Z~x&5y))-I%@qKe}@AW6g~}yz6)T|90}Pnv=h`^*_J)=XX8YoVo86ZysH{EWZ4&?|b;`5B~XO zdGqo6?)mf&n=^Mj@aWrq?nn3CdaL_?IX^$U`M>|$-CI|0y?3ecy7muV_je~ZUidE` zx&AY!|NgQAv%h)&$#=JVm(9-}{MEO&+{aJeK0E%=SKrqB(OoyXw-5i;XD52^`RK!+ zpSk~M*Ji)<(FgYY#q1kDcJhwqkB%L9`P=>Cb~IX4_fzr_?@?Ozw#CT9WVLQcZPrTyZ3$Roo`>e z_0cC=_kHi3=ht5SO}G7$m*4WGKfUX*%Nzglr{8@dyYmkwZ<%}Dy)OxF`Rz|X(0U+# z$&p(g|MXX$IP=k$9KU7ee|-Mi?tgvBsayVW>{tG|V+`QyZ^HnJ!P)WXXMf>6PrZ1y za{tR(;Xi%lE3=hP-2b8Q&{rS$t;Lo5KN)`Ot6%(`#;0EPSa{PveCD0~wfmn6zx)p; zf4A{hFZ<-|_}4ygYi0fZm$$z3wOfx=9=hxQZ2jPCcU_x2cK=&jXTE-ItMd5$x3~Pq ze=B(YlP|mX4-?5nA|Mk}2edE^mSDyd! z;oJY_&mZ{AdgbN&ZvXPydp^7J(z{-J`^0zO_PJU6V~1{k{L$Or^3=&Mtk*ww{`N0Fb0Tdli*>7v$R+oPjg3MIJDXd4T}BfU zYg^Y?m*4r+=l$;Yc#TKD|f9_J$|*FSx%F+Sv6l@k1)%ip0D&JR+q{x|!d%jcZGriA~u z>|f){Mb4`mKc~KV_Gi(@l!!0u-d(=!Y_&T1%cu{=6W6U+{rQXU$7fHAidN70eei#K z|0X`feLekO)_lu9RtJ9z{9^pD_np=AzCHhv_1XE|>XvVReH&>|Vw)cK?r310vCF{p zd!qgFI*XDC=`og{E$=DD27=&+4=rmNcaS4LFNtv{DhE)Oy;^bDHT zy2{0O!RMZ?)9W%y95ZX}Mo(1IE<-cJ?B~qLE-d*uQ+Iaym+9L}mSncs-1x5o9UrpVo!eGt8%S*Pl|HUD*_32ReprFFCfiywF+a|?{$iM; zrel@XH}`V3vu1sMv~<^%GB?ffSr??y4Q2f`6`3899qxo(bY4PVUsrHP>0h#f zmVF;|*L|jBCtdq}Z+zIt*7h*HojJTl6%;cMs3t>e;)GOv2XImm*d<1*Xmrl zVdK<@v^VZPi|5~HBPJh$JwE9QIu)?D7vph z#>1%k_)!~6BMTFzoS89uUf+dbqp+@|X*^g07Z+%W8~S|7*@H zXT@g4&p}^C-Y%WG`TEc6mp(VLOxYYfHF}xJlO5YO&$;@n^w{QyQ_rk0dE57|6xrRu ztFF8&y}NnIG}F}{!F@k&em!m1i%@T4%k7gA_n#kS?ABv@ePVQtiMiX*?XrcRKDgQJ zoxDA9q3LChl_gfIo;pQeo_(#?^6l>zx?Uk$lWp6VCrKM}h8I}o*X^N;+WyN5aa)!#bJ4xOJjU(~*ztA|@0Q0zx2PRSi+OiU zes){7BQCM=j!DAajXPqO9J@RFu>FU=bEJ)LGH2~Qx}#~y`u~kuuy;hE;$M#kR~GO6 zYr&GGpC07=Tw=RYyL9=ZeJOh%6;56F>Cu(+y|z1lN&fWsO8(wKJKK|aPo8hu8@+SM zGS_GOslKrg$_nvUOy>sS@=D%~Q+&=8AJ!`+h?T@|RcDC6{|J`?S@7tZqmC?6GU3c~= zy1H`Cn^AwdjW4P#3V65g*52r%mn%mve12!|uSM6-PXCbeaPO+3u#~iq&!4(&DoXfb zIm6@S-YxxRhWxp<_j~Ubz3+YD#dn|Gj-)qEk$yAzy7zNY zf|Y5Yr;&%_?&SqRa#QntKkN=#HzdUK%if)C(d*8H)c5pQv^)60vXQ2%a+dG@yiPi5 zPG66$yOY-E-V*fNcYJrPFK?k+|9xk7*IIqLJL7DxzjjA#XdAn4v-6$Z?=N{9-^iG= z;q}%t?=KgC0l z5nmSs{rUR_?RmAOEk1YSzDaxL{q||b=yR)_hcEA}<*x&HP1{I)^%?R#!++qz&* zRjWpDI3-*=gJ_601sv?F3^{X>tP zt70}=Eo+63 zdyhwZzdrO>y?>;$V#&>-{i}1oc~~91Fn-s0Ph&5igOODMHEopF(1W2zcYS>N%6Za3 z#e;PhJ$rg39=v)q?!2j!*O{g5N84sUcRuiXMA)&dSLV1KICAj*v11MO1H5h?{3R)3 zf#>SJcMm3g{Og+MP_K_Owa3p~_89K<-@%UKu78aV@p34yJu&*m==sir%3q%_y_LJx zZA9j{ie0zn^gXcBCg$AZTccwREG}=WxVJQW+JSZDQ%^SE&7J2}QU3H~{r~nq+omo5 zrEu_r(c639E>AdB|DZm`!*6BnsnL&2Q@p;E2UqUD>zQ%j*n-%~GmrOYc?~?&QdzIB zU+cAEN#gOKC#Ho5q7SV+>hs^F&0a}|Zl7*kFmvaDm4`l`_IzGn>b3Py^%?1lw(4j&7SJR>P*U$f+Q+1$Xf$sMU|BMblAUYgg75(r2O9vFIA1>7WTYuH-`@^kO z_ulNkdEoo>=(D@tjlSdMyI@hW-3QMHUN_uyXB$6wKJohP@RD;wes%lX>qyAwvq}He zzdEq3sN>x0z__n`2OJePXKiOyJzB2R84h)=K4Glbn|y zZqt5}o7t34J~8h8yiZmolnnk7rdzQR-}jhZ}x(QbLC%72HzjD z(Ckuq?^D|QNxvSr?mhg}^??qH58Nt`K9%xd$WpVE%}Y+TKlrqC%pbkipZeS*_hQ{% zuT7_BK5Smr@Ur~WsYN!Xt6sb<@3Hyy%{i+Y-j|O6m>(Wd^>w1>#XOtC!!qVYUkJ&u9Wb@3{@=9A zX3hf&suZu+U-6opx3j9z-l5@u_kiE4KEDpS_QHR_{i>C3M*lf?_~D;3KfM|9ms#lH zUT3S{ro9oI%6haw`*!&a;{4mqK|S`}81v(R@n<97?Z1^bdBBpL*WWF_lQ;G7%CoZf zo_EL09I*Xt^5o(hqvjp9TGYB#JZkRz0l%O9^gigD(c%Gj&MH5AdXVS1cjX?%?;ej1 zR5@2Jz5U_XqcPvP*e!kkA@_|@`r#hu;yTj4&CD9GXisfNgnsUt!;dOHb-13--gr1_ zReMa_UtyaDM4e0gX!^{nkISNSS9?Y4jf)PiKKIM-LC?MR45%V&l*5a;<%dt7`}FDc zkIEAR?wq^rc;Ro-{h|s}{*(UGaPIKJy|T|k{`I;v;4fil)!-GEt{xur$1ju5yfM3Z zIP#C!FOBaSUiEVRqxws<{__39zuP?ga^^$BqXABP!f!NwyY#-ue)sirR*SPjB4{%IeKh;~@TouEf0cg8dw2NmA4%UneR;8`=*=HZ-&_M{eLWnty2a++ zH!p*uHnp*$7f-^BkN%c^N#ym98|8cRpsx2;`N4i(!)qVD5rl->9Gy}tyKi!F)-TQu z8Otqy7}@X3UYkYtEVqpezu9|bZIG4xx$JA{rrIRC`e|3bJ9>A`!;hw8UiR~?ti4cm zbWC`E{-z>Xj~~Xq^gnv9Hn~TS8~ca)zE64Bqvpq}BaT{Kl-*r8{$;4I&&Ak5(q*$x z7Db$^x1KxU<+!86FNRjROcYK!`qRagHe*&~4PE=|#khAmUIX7 zI^%?&Co{1%{%sQaiyhOl+3?e(h^apEv_Ce*^y%oSUKlcU-DGcN3==8pjO(&dH4-qK z9)5K*iLTpUO0+YJ&$qd0r;Zo?+-@iLP+U^jZ!f@vGL^ z`Kv7-xh?mv`=((+d{g^$h4)$CrY8KemN};jZg9ib=G%0|$#W+6O|e>b%QZfOiJW)b z*~5gwTEDSbm?FFOB!SAQ73?QrtJ#P*6B1N;lZY-8B@3Fmj>&!`(6whyK8X*LxLk{2 zQe8-z+1!_zIVUf@ba*rO;EAKBhsE`}F+acR=%-7~HH*hN<}DOn_I-az=h*P;yqmsL zF0btUVoaZt>O^5&k1HQy6AX9ux!t>AX?Tn8mdkM;Dwp+pdGy3(ozsmK;aO`NFNcfH zKheEA`Zhu7{HFJ#%h#RfuAcYR_siulpAF~d86Wq(8k9pFUy@rRv^ZWBoV>BMCfxdX z(9~$z94ototHDtma)im{v>$iv0ybx9l zY`VVWhadhCo*Ve(x?<>tr7tfIoHQb7Xpc7s4;~%%r)+T8yQ{a3NB_C}8|TB-hsRg{ zIcfN|k1tQExBq!z_=Nw$7a5=V^V9I(O&b5~7?$`Y{KLRomm9a+f4lnS_~$>v6~6|0 z8&^ngYL6u@ZT_kraWi7PI%IxN|77df5u%Y}d;2fH`F4D-QDfaQ3UAJdcr)r+zlu{g z-#7R7Z@l?7GI1<5$p7D)4=4QZM>@E|_EtjV50lR)7;dpy64`4)`Phn~w}K{)ndm*q z|EtZsiTa7u&lO8KlS#_DS5NJi~I*Wg-5S2^!sf#wb%dX?VHh>xz`T+-?$z9 z)4(4epY;Ft_RXJ;FYvDQ?{O#cn{uIdso62dgqWIz*REC!x${1z$KtWKDx&Ws|7^C@ z`$5I}-fcfOtVn(2zv<5PC6&v@zN|QLr)BDm73FU$eyx0z`mW;Mo$6`w)$$vlJ zT95Pd4F@^gCwEV$o$o(Q9P>QTVo=2W=!FdzuQ{Gte7|L3!{zyXPMy6uDQUx%zt3iE zyI-C3Q^VgEjnCZwnk2tQ-OgybpZM#4*XUuV7SCETt@Tgur4_d>#VpdiD;as}`v)me znj6%_Q&A6oSv=+&C+5_W2d@^J-5pC#r4Qnk)ZC@!4YKKTb&2|a*NjZgKKQz1?t}8B zrxblIE&b`y{FFgo9)u@*O-RicpYrT|EN9M?A^iZgGM|`92oG9zCCE#qpPd7eV`tlTK6b6MgNhyY;xk! ztL>`)sJDaeKB`~6?b}#`!O{nD1rqro>hzEn*}5?yuWSbY+)}&l&E?0AgRO7hTX$gO znm&VnYl%BjJtfWU^wE~a^&7^Re^W30vtzwv>^T3yJ$r^9EgL&-=-~G)PdD(#zX~2~ z_oVq)<@i@))gAqkH@cU zKc8Omm>Hr<>)J?UxU zZ}E5O?Sq#-ef8UmS>~muS20(9%pC`r>g{cq3$?)e#+#ix?`S6F2=|bSmCj{?+!?Jk zT-fZ$p1+MJ^XiVLE&fwJ$b^<(Lr^(t1v@QQzg7KJ zb3cl^*Ko(PMVBU?z30f^Vfm-8>`&in?|&Wn9~}9g9r=^rB{mGZ%<1}X#O31eFBb=2 z7RPw>?9FGcO_{ah{a4Y4&gEv#CYi_a&|kcmMTcA`1AbOGuUV(rwzx8%kMrzlvZamDeDCu`zvFUs%Am=%DGQmax6XA_H?3vj^=)>mcTr|3 z-|_$FeRY-3Y-!YNX>8|u)Opt?+`|-8yeVbMmhsc~T&eDgHkVBd`Z;IijUA`QCiOT! zTdMqP`ahj@&MZA-2~%tgyvylo1*TmXTc7Jg(pLA}`5k|fD1=)|*4*X(u@5>6+jU)- zQxweHj#UdycJ^WZhul}%+gvTssbl)w9ww5vOf=gRBAwLP4I=78TzkxwD&|U6bERc- zrMkIN*?eiid}-Z$soespZZ$X5;{A90Pv7x>Zd)J~EtHncx_t49ti@!B^K$>ng;LJ1 zQrWLkB6aNw=~O?s@rT=f-YyK^A&l7}oVP=G?~H!2RJK%_y;Q1QDith~MlF+WSte~? z?DFi2?B$i>zpvH4szGJmz_Dl$TQ}&e8#uNN5!mlfYPmc)O zNphXwiZtMgRCz^Od_}6gBJBulS(I1Qk6+P`f2tq9s-OCge*ByL)OY%+|JRS--jCnA zPw=;b8HS7U-uB~n^i%)WkN>S7fAe?h2TuIK{rJ}2{PAvlM{o5P@8u_iwI_s)CxrJ- z2w$EMHWQ;Kgp(?S$_in1g|Kyn@MeYZX@&4rh46EQF#M!2>ZEYqNnzbd;meakX=nfB zpA1f!!rmjZL*VR)&fB_~CO&WnYH#!YYiIw_dRM#lXcC036yz|C3{2RGj z^v}w-A@{ja+|tpr%gG%|oeR0;WCkFA<0q!mvNOg=(gS0*3OjnjJ`gX^FXT5APv#Hm z&;Ox6-|EtZsU6Jir@c)?h4xnQTGF`0lY3K5o=C+LgN;nu`|>~ceb4=W^Ht{?2HC>c zzyJS)cEUU6v~ZE-Ur(g&&!noqfQ$3!3Nphlx(ss40|Ly)Sz3#KV$Ry zj8O5r@R#3(DZdM^|1M-6RB+R?A|n2gHeC+> zc2o)5eiOWtir-0-#|Jw_oE0XV5bBm@zms;nIDeZd@3aBxpZlgH27Zu|>K&Q0bb#79 z_|;kAr?bMD)+Gz#S{kaKG!(x#Np@EDeb!L@&G_g5b;SVn=>h63{Xd-(t}N>HMVkCY zs{0~!|0YfRCe5yKi6?t+Mcbu1atkjt@AyMF&Q~`hWBaBF!n!Hv0|&MS4&?m$#Jcl+ zf>=I~ZRoD6_M~;XQOuhVnS5a9{rHU$%na7qtW4)2j~{%4KONIeV;)rKW|T6GCGDCj zr;!(l+X!ihtISktk>x(-R{DECa{W!-Y{&=d1GwmT)A;h>01&?YjU7^@gMfL!%<|2-^0Til&eCTNdzr&1EM)!nH= zZh}_Zoh&0sU3c;VNw#+Yysyvc>XRlCk`vx1)P5~U}c9k>vXp=o5#7NjMNf%7M z8)-zlV(M0?5iKF9WR8I3Tuf4Z@NbJljOf0Y+C*%8hpCBjBigMy6=X!aW9nU?5$%Dg z#l*U2fJ)TmTVImmSEezQNbH3WvR`+KsCaj$Ce)IeXif8K=MLy>_93J()Lx7((+MII zw4&}*G-;XcRN^})MFGj|qxPyx9Vp`ydi>1M=6qB&mnLa%ekrKclzeZ(>EO_7bEH z^WhuFY79{0FXNlbIre^^b*4!=i&zdNh-RN72Hy$>x5ROIVue-Np;_HAhkadU0lp0!!UV^=_jKq(?m)G3#KnH z$j}=hKt`JvyqMQu~_-Q#dYy)ka zOByJdYZDqMrvKu7IlhR#0R7^1qVw?apXsxpdH zsg)gE0~y~EsSuFky<=K)4kjy@_MVH$cXlK>k0iTholQ(~KK#`$2wV}|>}~H?#kC2F zwGGyB1d)#Re$`y4rbq{SzuN9pS{l&B4b%s zpOR_Jo_6&cmCSx!V7xP%;!wU@vbuVaU%yxIWfXyaWEF;xof-}e(QoLdl!)$IgGb|)_ z)-aE|Fyr?-6tzOpa1@PYd34A6pIumfM#t`#4KtA3?GPX(SBWk%?#hN$|Of~v-fRaMC-W;XG_xJ1ks>oXfaABHILR?&x?O;31Mb^ zrXiF;CRzIT?xZtGRzZ@i!Z0u+nI*fU8K#ipRJIai5@U3;oOr_b0VDKWlvxk?1UJbH zDbRz8C<|2ho~Sa6tUtaevIsVx@6Fof(P8pO0vnwJR_6a0!W`AU{`MrA$!Pc0U2F; zI=|b^)cOM1XaB!%6wsDzGssh zdL(+22Hps6PAB~!Q4cZ&IUplSDPd0b$c<4z@xm^w8=NRk7u2lsp78EPKl0nd#OIEX|bp~WBJUT&} zyarU{LRLj3TevPzJ_J+0ks?5fL-`X6#4f48CSsv;;UY&V5Rvo%S16kCt`ii-d9CDd zBgyQMjXv`cqz6_SJ9ik8jV4*$Kv9*AiUUw_Yh{)wF_r8$d7H@4q|Omf?A9icq(3uo zUxQ=3#bhf*zk#G*dK{>hWrAwF6&BBiY3N~KgqC2wV8|!1?q%<%VKE-om-d{>{%lb_84Ts2u8(&Vm1RZ2RE5U0wC>*;2KaA z+$6g;zXZspg96C(j%+rS>~Au(>jkepq8IF@4xetD7oEBTa6Nt4I~*42mIfGd!S4P%6yiAFG_O&e${>hT5_{=ruhIx)g)sXZC$7nYM!-Jp%c2Iv}g++ok+Y0pgeIXlVSqDLaQqq#1 zSJ;%_SBV+hcCBgs*tX*fk3rk5f^2@#eEsiH(>G+NoIE^|02mPkd)OJ9ji9(&tqE8u`W%t#n3WeGt`2oGz?*e7y zo4}KMo`N)5^x=u<5j$io!IcY-ZX_v zyWnATBbqMAWA_AN#h;|9>eiCQ;>S@U(*L-2)yDIRZAnvo#$geo2A6%(%VjDTvQ*3T zu6AOB%xWP41F&rMX#k1@kpgb7EhKEA_6L_K7X+h&4B}*#QnDfIz;KC1fZzhG1iy4v zQ4qP1%nck@vn0+WCZZ8(WAB%c0pevB%+7!@wl)ysHBDt?Z; zFFm;i6g;I2u(#)5RwBxZu45^;-TC!WlXWVJc)&;UVY>-|9BOEGz*~ zoCk_(UeXhG-km~rDp5%n*?H+XX6uLgKI#~gu5D?&Hv#>E4T&Sp2pYJ8egNo;6~(0C zl!a)HpVZg*7}qd{Pff*qqtUNyHGnleS-&{cUUHD?9E^Ui(10wJfW}N;RvRYu?Oeh* z^wT<<0B!a)($_AbV)6!1)C@(%U^Jc1D2{v2tSOdcNs&y}sr;)9NrZyY?_6i~mRLdl zWUnKSAq9xyhmwNdN0nUh1fX6_@K&Xrb)5uh`8#2lRAzzD$A>mt8eOzc!B}y4wkLI>j;s`=L}ISP6bc+eIs2A z52?6JjES5i=0R+dx`)|}Qn^7YABC=`wi0er$U+PHbQpr3E>L%MnV_#81|YSdZmpv% z!{q{$SQR+E#iY`>U-b$%TUgk^yNjUfqhymFC|0dRc0 z$~uha;$g;HOiqqxF`FZ{srx#}#utJ#yx3{DF6|K8RC1d$Y+!*>Dl$Y( zxg0X_p4$ardjY?Wd%A<{JtQX3ov5hJ_yQ9jNa5S)Vn>jYlIuB8)O%qi#~^qc6&0xf z@+mM)A4kw?w^x!(xSX_xPd0!O7XYaq2u5naM-lBM<5*UbZc$?aApI1k}EBz}@BzDENY=gGuM#I?in!`2U zZ(vV6HZIGsQ*rF=4E$0MtTThlBuxk?Qt!!1-D(;~TE4a$+zg7EsQ}W~%3xOiT56kA z>=i~@zBmU!xgUbkeTL3WJb%(ftagKs0upCtcZfX!q&6@U_tGd%O?Ac{-~ zc?9gRpon5KDh8~LR;ecyo0EvdggGvT(SZ!uyUfs8D`LWbP9>n|gViIMi>BiSt3(~S zs|dJ!4}ju)FfEq@NZaB@CRqbuSSo;e69B0VSQtkH-PZva??omt(q6>Jn7eqwjW=VP zP*C8_R*xnGK*|om#y9|D)d)HwXx;>hRtW%RBS=DVU|L3QbbYo3kWz=m0;tReMZO_` z)J{~Cl3j*MTE^#U6KMc7-s8Aj$5`h}d^!(7yJ9bMnUI+dic8DU5=OwT z&2I4;xWdv8Ced8xE|=U|lE9$~vQc`>_Ozrg+ibC_Lbln|(rB1Uk12E5O{G&QfMIz6 z^7#PLt7ijvX?I_p%$Au{%E<45@}*kUG?~N&VwRKxg0G4}u^mm<^h8A^ntrtlz{K3b zcCOucGM{O@$W0K5jF3K9g<#7b0Cn9yI-ueK1eF>9mAMcImsla_f?y(ot-p~{ckWAT zdacx2gs)Y!il4aN(Q88nvpAJBg z8rI(UfdEq9qhfzo=#U&56g5)-q=z8*3-0}Wa^aXJF-LF;f)34KIx!a%^*s?hjbMKS z1J-^EOI_|_OV+h<08%*!M(Ia%y>ZZT7{$($tHu~W+6BQ}D7D}wx%4k<9UyOz^FV_^p18hXiQ_`2wGJ1D`p>r zXhrm-I&O@T9F*eCL6O=@c7sj%KaeH0n0eaM888u~!=R}V14sv;;!G?I`FS(8FnoIe zDO&_z&4L@njtl_x768((l^JAs&mp~2h>BY_04Om=a1JV_?}k!0t>vrK6&<8{By$0z z7S4ux%q_NA$>F~z!KQ+oNdm4=W<=s#j?r9hq}ZGo-9r?WW(kR0zv5k>Sg>i5AoVy? zJ$&nE7o&QYKmsm8(`{JciTU88nyYXzc<4HsMBHM@v0g;Ak-~^2BZ6dpjA?-g_Aq+R zIk*<<*8#h(*Lp9AP^tOtsWU$^`#3WIsd@xcbOh||X2oj`vlU(=M9{w@*KP}+?2337 z$$@j+C(t)&hHP3DWQ#Y)Yz`j*42Fvi@~#j-wH<k(`5+C4X!?AgFO>{wy}fvO!Yjr`c;O<*{G1(08SaSGahi9E&^D9pg!d_pBo?} z8$Qa;7Zm&8C|6m4qMSn0HfUOlrUT3X)R+TEZ$mH~!B{SU@?QX?lnC~@06ubr0BR%v z(mT<|^{A-i0VuZykh+YD;u=t_Q=^dV%Z zNfC@w0Vw7ISYv^T{}zK{J^8|4*T6_NgEu64PXMV<1ec>?lMyKL9TA*@rc+SS#{@vN z3P5^7BFyM>&coDSz%gb^E${Eht`U?Of=$%`Ds2JO_#r4l@YMwX?JNM~8zI;W!B~vu z#8Loii~*#(6~pU5QON^PZVez6fr=|}9rG~$3g+DrcBr;IT8Z^=`jc<%K;4If}-3SK^=n8 zyKK8<JT?07^y!NYx>z;0jr=$-;-N9`Zm0s>hS7W@9Eo@_?!H{j4_1^cV~B#dw1l z2s?HXFM#F4#|6Ne&hf^aoGCjTGuO$=-=!FaiW> z?k;&OD2^khzl$W>&H(1VHI#|VN=6)F3q#e30pxUUI+*=wEGK|1jNC>CppgPhC*!kj za&%$Ac;_>4OssE$t-^ASIqTz=47e%PSfS#5m74W&xe_pHxZDyH>E+lT zo3K+P_kfm>i=nOQFF0HiFvdo1?xBZ=V-uRA>GT$;o+iAuRP%5GaKXYPVm%5{q12rb z8B!NyJL8LikTbZ%733DOrq%w?&FGVO#7Mxii1Ig3jQ4<2Q)Os68BMpR1E^m_!0kcg z^&;g!z_N4~auzYK{)ufF@~smn^@ysjOKJ{X*j~sE*E2jJ3(D{nx*E2Gr2{B;1(5EIrt{+fY|REx;sGFa0YSe60Ci|u z?unoXO}C-x%C(?a696DxUJT2}Yc;IbKD|t#hxc=bPGMUD;1G`yY^m#d0x0nYkP@Pz zG7S_(6o7gM912qryq*qVwE=)N2B#@BMK(%lu zoViXQXp66N+EW44dn0JD3>2-JK~X^i7%u{llA~fef*kZwBSBDuFKO23KvA3pit^zA z(pG4i=K>q{rcBsV$hl51Nli-L$d)=qH=ZqZS@**S9)jbR0~o9a@W{H6?A*gQ0Fau2 ziZQ4dU;)dpW+;O95UiR3K4zzbqCN#cx(c^kYfw=~16U&mkb2IvYUgh6RcEU*dow%q zQO}8Hk16yai<# zka9q<4}w13pa4L+6v1Q-D7vRXFj()1;9>+b5fo>D=^7zE0wY()Y^nDbgJP4#X_!)^ zEwCd^#q~Nnq(56~K{}JS^Et0KK67s?fX#3lz8ve|!&X5*4HRi(1g{5!B8Lm6`BJz% zqa}E#kYU&|mIK=vi5=c5N8)S4f_<@cfQK)JW3U-ES!B@ z?sXXY4dD$Bl1*wPU^Ugz&i%2K9DFo}Iz4Bcv1baG`o1eWsYgG9;VWgsmy^L2#p?** zh!&cXt5-*z#4y-}1Zyc#>ROTAnjb$J`t9Ki*Xf3f$u)j*4{X9r0t#A4sw}mmiU{oI2<{ltmc3Ov3Sji z0M6-lCaOEI(bX`4eE*F@uO?tYh9!x&KNNfGik-+2R9n36gi5`f+}X(_)5w=K+sIWP z`F18TU6y482no*1-U4_FxMobIRiH|4S z4al1)r$$#}SxsmRhf;>+@s)+6h>tOn5v*xDOFNU)!K!uBWOBmx!hhVk=f&u`k1qc=+sN@024+fC7lY)=0xINiX*lHTX z7DggVgdM5vdAQ&x;{#aD0Z`5dka9q3i6vL^nYkw@>Uqw$ufA*I@490Z2JF<=bu9;7ulg`so9c zWbQF!Tqmop)p4UfQly6u>ce5XSzJ?^sFHb@?Ux;BOTGwhN5Fu!%b*^O9oXfA4kOPH z$)^N-wbunq=VY>=Tn-?Wgy7KK01DOss8;|;FOy|DhLP7wWTxQQvx-f;1XfXFR=_qP zwIDE)HC>CK$`Zi%{&<-slmTeKgY$J%E}Y`je7KjUvx{v^48AO*kQ65N@!*vl8xn8SMhShgQ&*6e@G`XX-l5p2r+9opLF6?BSkm9SOlql48|hA;HgJOHV<(*VZcYi^Ya6eZpW3Q^IZ85Bh{ zfSPawd!b?#nvTi_P;Cex9f*n@s2H#o!S4a2iV^gD45r1!us7omLNF1*{s=15K(R&+ zAo-Ffl)6n1irMP{)H{ix9%E8raH+84CYw)z3g;pCOa)*9*OeVJ#pc;8$QL8H8Wpqq z!am%t2Y_-{7z(s8Dq0zUVm2Q@wE-wnGZ2j704TQgXM4DQEP{3_0o!qh8v3lnPrU`;OsZ4pf7gJJ=Knpw#(*;`_%o3VNVIJem9k(fo|M5>_KDdlRY zKWnMFNKIEdEN|#aX1fcUD*Q^^_HMWJ0X~fra2kV!_~t8q%I&>90Y|4=#7dd2yQ^| z4Ee5#&WTw*>?{E!PjuM|rwkP^H6N3~B-O;5!M02dcOy*p#}Ld80kF&%K>lz5>2VRD zXb=RTmII)^TQR(KH>_M}I!pjyjR7c9d(re(IVf&115h#!Kzi_aFr9>o98&<}1prd- zQL(VwM-hN(M*wMS1ZBZsy37K=8easH5fr130fyFWJ!-rZuqvFuFt;PeknQ0r1l2qM zDZ4;8&m?jIZ0CZaoDU#9nEWCVu|pOlC6C7{mhl0U7y(Fr2L(U{npThK?fq( zil$XY0II)7#cElqV`Ucee)$lBbqGof5L}3gNf&V_7=R-Al@i$FP9YCyyH;271vR$g zCi4K482$ps<_)N5ZV1(rZ3Q4-3W{{UM7Z&ZzTm-DPa@?Tpqjw!0OY*wFxih>2w+_` zfGUfxooLhE+NPTP(J|_se7oH zQVU?E0JjQO2;N7q5KFBz1;uz10BLIkZEHZW0I%3I!x8)s!9&#+(9Ntyu+^jY`V37N z&<;m{mJ0~>1W-)@NDo4AUM+yxd;sMZ2xcG{g{JKc0OT7XcmP2^G`*#V9UE$@aYxV- zcPW{u7-kBJY99cp9N)rGzwqh_HkERRIM}Yx=@gh_lhG26#D9RAz zPXdq%MbNcdaSg_MdI3njp#_BzU}2P|U|Q`6AZ3J45{IJc0#g{*@umRM$*7o*ij`Sa zY=vt^zlL!=sSb8~?&1M#$1PX`V2uz!@{L6RwFug608q_;%`+cY(w7|Vw;}izL3fKb z)->N06zLOnYuR!A+7(Q(h%$o`*5lZ!8-KOCtC`kcxzIau5+OU`gjjPyLGa#)XsHA6O5)O=-_em znKU=H!Udw8(0k02VTrRxun|E87eKu?f)04^8lVEjBbES4To8;$#e!4-1qJ|W%y2t% z8o^jpbTW(kmf7l{%2gtV769cRZrPkjW^p0M~wamrW6CHTnC`W2|%g?!6Ewql&JyK za{;7(KyVzMJCjv-3u}O&tqdkXTL~Pj#F?nrA3$mZDr!0AY&T9!1u)(MKssPHl=|sz z@Ub8pK(!@+lm-<&v3ja$1l_Q|d(HvH;$5hSZ*}>;sJIUmgHf?;Ehy@T14w%!XwB(- zRYcArbvy&MWi&P-Se{H|aAo3-pokA3`EE6UcW~+_fnK()qs#!*I08r;qhcBtz-j{k zB@PJ65Hv!tQUD;|5s7H|c5y2D$eM}Hk zpyG-Sh;Jr6fv{z9{xq03Y*S#O9{CZ#TnxdKWdSJf1MzlhAS&K&21Sl>0;{N>hKk1# ztZ(Vb_D4Y`DC)lhkQ#7ZhuHAn1W}&rtMHiS?+q29V-? zf(k!*0k%tJRz0B}N5nwK^+|+MyH^7!wgr$s96=idm8dA90F=lSuO+$-A|X!1E@3rMZPP5^q_^{9sp7$Wzc)pqiH1% z!2kg1Wc2aX^r39WEz9^9CIItGP?$D5Xu_4T0M?}gsQ(T?Is?J2@c`=b0OU^skjk_N z#o8GFwr2vUw?c3qDu%}an7tlA&1fTtCq>!8mhSZo*!xB01wzYsBWR9bRV;uC8o{v$ zmLO<16TrGm05ygPK15KK0AO|&fbm{W;pA|53mgcd6Ch4pw)r&pI1RyY1RbUWSeXZ4 zya+%l7{Mj62o?dTF+{Ky!C+L(UJqcrQw#g$4*FXGd=-1ZR#1#V{^_n&AlYlQ*yts_5pitdHWnL9CDR zArIkUM+Jh{5iC;=%1JF(nlQicjGzob;bTw~@eSFQkr)F=6(iWB2T+*{ruo(Y(r1@} zkAhYJ%htmUr^f6$JBQP@gCQbNriaVb_EZ47mhjH|pP2}zJqA$R4H}~2=>SlyZw4@y z2E}+Q1VsqeqM|GxKz=ZSc0)i>gztR=RKwWnk=wk71<9ldz=T)`!T6{F&##SZdIl3nj!)Yb?Zc7W-xdQdFL8v$+Y{S^wc z6~O?VMN+I66ZFnj1IV`rkRFDh^P6tpP10a=%U>$-{Spe4f0!Vx5V5T^eHo%-X zL`-w|=b*xc9dM@eNARHvz%UVj5*Gxs5p2l>(A^9`zA=I>kHIwgJv7#|Pp{>y>6!p| zrbeAEfOUqK4&P?1+%Sa&KD31YJA0BU9+NSy{yqzAAd7eR9fGEyQ0%`qC;v<<-caqxRZ zbTXP&ppRR!UbEFBF{_93wYNKL6&#CU2O!P^P!ob6`7J+dg&{?PI6!olDJlSl>nkq2K8xj$H(Z_X0{KSJgmknDjsT7v0E-b+3u9q^ zG(+$vg0Xy1)Hni2ha)Hsf(1!u2%y9W!B7OlP*EuWu*L(yX$W3N(A@$+z9oRvJp{jV znas{+0eKKH<@*3g+hUwJ-2h5$#{)%;06@w!4XURQO$YP_P(B<$T8F0N1fb|+j-Wv^ z>{1S8!&c#(>p0fO#Qbu$W%Lf&?0aA87=liH0W4S(0M`*bRQ%5cz8Ubn1iF4T>W8#XFgvLU1aA!V3U~2|!V90U(`;prCaq`vpCnnG`z3cle-H>kjL+ z48JAk&fG_Kj%&SlJuFChbuf`Cg5ZY_%J=~C`=+qtn)y*wQ8J%-krW*YrQX5|21R3> z!{vcck2(%~iO_ECs<6~S0`lXTB!qiUreKoLDe+3n<20jC1Kyq{m=ktYfjQGszF=bt=|a1hb}@pIBuT4Vq0? z#)e0epJ(yO2Giubf#9RODHlMV4QpDfUIwL3iG|_n=>ijgIL?d(Rk<;vSkpZ8@yiw% zTwx`nlVZ&snN1v*{H|Q5kD3|eA2aBxo@zw~YnuG79IHrvSB?ewgA`EelXYuZkZHoM zdejzpwWs>dX3jJ7o&tEh80s-V#bZIcG-p;(KjJAArV+vI%~0X)v^NXNE!?3Vw_(c! z>!ArdHb=8yyl@=2Eu4Gs=B2#HJ&i46{&XD~9kcBCpe zEZ<<%#@bQ4(?=gP7*kn0raCzMYVg=5gK;hC<6Z{;*irkV!9|5AWW1wcguCH{p&^ms zh7%(*CdP(LQW{Q9HjGNoh|15HQk)TeB;%**kQi;q&rOC?TQ5$1n=$QkNUY#etaave z$Iv);qj=)CFW;TD{NTtHm6uo4US6rqTBXZMX&YQJpt zP(gZdc6zuVBQiT9Mv$3MmzfxrwK6O_TadG*E~hvwx2!JrNOoRTSbkky{>?gC7q+Ig zZcTgG+73a1!Ic8hsC9N%)`>^0cfYdUXViv(D;s1v8^cXDMP1nxJE~B5r7&^S=Hx4z zRin0KoBX!LWb5vntp`oEoygf%owHp#YDbgF&X$~=FHMTx<`jK4DK^M07Mhk==az^^ z?{cr-_l+h ziEy)u$h?Xevy%yVC+C@+TGVh#HKsD(?DWRG)7#C??9MxL(CqgUdB0bgRn_KIT{Sz~ z)NodpckZRxA8+&i;DlETu2ze}&)fYUW#0l1)!O~PH#O6l=AzEb7`H+0bQy9PLdMZW zk-=avgpfN4O(pHI+oht^=`u=kza>f1a3teM)VLKInnX#Iq>gGT=|9!Ez3+Q|@BjDv zdKqq!PN#RxV!P*MbYpQn z#Ec$Q++FRAyGwEROf&9T<9Z!3dYy26tc*Smu0O1!KhF6+x8pwKEKchXXF3mL;|2>e z1}kt6YBC-);3O>_l5XdR;*N*I&O_t4M>83ZW^u#wjtpb*Bg7*ks`$s+M; z#2P>9aAed8|CDv)DF;6md}J&N|19Civt<1Ez9Zx5_=yuoCUQ4DFYSC@wdsYR^F`C9 z$+phP?oBVnoiB$sO^tU>O>cT7?R*8eOfTq~R&aSu>3Xf<@~_oKwIQWnwNWEWDbz@VWxFy&K!Z#0_-gMws}CZv1N|;X^k8 zbXEAFM`4lcBBh>1ny!ltdKMeI{%G0rBg2*G*hBOpQ0Qa1r(CG3v`j>Ti#!e_o_9|F{Nj zu_o!brrP2qI>(nRTdZYvT+3#$_L}3`&Wm+Cj_dd>)(ttX8@*U>=UqLXoBqMO`p4W1 zvhEt>xfzz-HN5O*RCm`%=(e=|?$RE&WdnDYjkqnJxV!wd+lmi&SAg!cAMVi>xf?6p zGuCuBF}P=9?7q_S-b#kMspCCUS9de-duD;|=Hd6ux4B#Fyk{ZX?Bw7*`Z0IQtb3Mu z?p9^@tS-B+s=K#J=x*J9&$`FmX5gO9h`a5?J=@prt3TXZ4YKTh=(StKVkq@8G+Fir zz4peepDcTSVz3+>dmUU^YrK2c1hUqK_paT>TDP-z9gnsCVDI{4EXS-~$2``Cvfd4s zSsUwmHwsx!?Y&MtEa!n<=MmPXiQY}GSuP)XT|f`!4}Hu<9V;_r$_Q-Sem`L~VBYB3L^o%BXC7$%!Lt-O+tb={*V;x7QxGlteHR<#=HN|+H`#Amk@y1@;E$?q{2#-!1e?ZdcqZQry#bde1|}l&7at zUMlW=dwTC@MQA=B!cll6K2MF3s>4rRMuE-vunlG38vZ_K3gW>>{3!cF`1_+N2V`4R z?V+S0{Im>8W+wY!miS;E`%szqP&@hXRsP}Yl=PeY^bSf!A3x(E<;YY1k(ZRCZ}~?* zQ!?jgW#W{Mk+P1dDIM3zI=)QlXS1xIZIn)|$vWYzBwLb`eoCi8vQ9-SoleX;y+?_U zWbreUvQB1Yol`nfly&B!(%Gw7XRj+|-^|MHP&(I_b?%{3&eJTPiGiHg-se9IoCke! ze;CYN{DPlSitZpbQ~;n^(pcmEDH1~4j(Mu=2NnBu!J}G)l`r{ zkAs7rA$_Gqr(_0Gmf`7n@=Vz|<#HRZa*xyH7nLtuJ#*o@azzolqJ6NU$LHd};KdQ2 z%89|s*FKj%3|<0#tA2P;waE9f(u2#I4+gZ)RxeYzveV;=<%25>-x|jUHLku_y&qf+ z^sNnlP`l0d+Rg{pc)o&z4+O`2>#`oy<@wf^J*dCz`%B$}UxdC5?GGAye6J5YxIW_B zIPswIweO7&4{m^*rXM6ti#S3hiBOZ%Y#?bi=KN|Y`IW(Gam?QCta{TU`=)I5{Uk|y z6k9{GTccHPC1&3O+i&qWZ3j7r>%@mMRNDvmNAtYfvn1_#oZByz&X-BfUsSz=^SPsQ z=FW9h(amg8hiXS(cE>~2&ZpU(FIBtVW_Nv7?Vf+G8>iMoI@hD7c30=z-DPU`%+B4j zQR`iEuGd+u&*NO5pIU#&x&COi`-$i7?@<#Y=foLm11HZ7oKqVtIyZPx?ZMS^53WDl zF7%VMKa}+NJsf!WaKvwD;^EM1zegUYAAMFEo}V*}qmGbrM%1W}b#fjrqdqaqd16By zU6V8FOnvH+^VE+z7Lqd-O?{S_^K1`w9LX8apiZ33nK(y%UX=6vBK5`9oEO)rlQ(lF zJE$-Fa$Y{9PCd<;dP#ltHs{r6>h%2c(>V3lr1P)U)Zgfwf3r;eH?#A<*{IK~IX~m9 z{?_Asr1zt@ft%ljKYF)q^ZT8T-t#s~4?dC}+x#Kx(TBXvAIlznyuA5S-J?&!&9m)~ zW_vb&9(eS5Wb@p_qq*0czkGP~1q=W%!@%MIPITG^sZraYQTa+!wZfF{BUOYhx`Cc`7owBU}636!sY<%?P2WQ0Nmg( z?r{MA`7r)X0O8{>K`u}MGor9KaFO!Jq9uWg4M!H61pa6>@}qqqal;7FEl~E=eWaj3 zaztKdl%`@*o??n7Wq%&!h^Er1Jf$2><>EZ$N==p8Je5XG)z&=KPEED`JhdTB>R29i zN>lw^p8A}o1}a|zzeJOquSs39L^prQ@+Dg4`C7J1wAbcqZ(5?`nXlu&L^m{FH)e@m zQodfw68-&;y$(LsKOSUo=CMJ3kYV{_!|EWT`o~7iK}&BhS=OJwY-q{yvHayzOIEzg zUop3YhAN=pwT#IH##Aj6-2#*4S}V;9R@!Qrt}QU#q-Ew=VCJu79$H`?qh*m)V3DFl z-(NsKqGfriz%ob6s<^(&D6PA!}M0-GT%+pz-MDXrD-3Rcf)*`W&U z@Y)P=A%m)IuUlxpT>B^U!k=ul9o7~)Y|>uiS-8eudu?dp+8FJ1NrmfDwAb%1Tz^E{ z@l>H>j`oJ)!VQ($8*2+UHflSy7CLomJNFkl4{2{2E8H}t?eebBWlo!kDq`YwT**bQ zR2?_nBDdu_?&d}AwmPh}MXXIa9-c)W{yLtaMV>J_UP(n>DLU-^MeHLw-lvMZb98)) zi+n0|d~1t*8+ACXMVw9@zy2b>Aszp*BL69!&F_jf&*=o9iUaVvf#l*qs&0^OanN$z zE#}2rY;}Xz76)(A4e=}v@z)IvEe?&*-I`RqHAOdUe{t9m-SAVz;W@ey#l;box{d$x_b|m${ktzM7?@Eu(>1U$KGVun-$YsZ<;a-~I#|}6X}ho31g>#Q(1>*H~D|CzIm2HCA; z*_{UG`X@XFCeA$$&v`zP^CtZK$BFZD5xJP>xhbSPa(N!rFkiPkf4O0Sd3k|t`Fuu1 z;fCjhZV^R3&x?X0iX)yE$48XxdR~$mQF`ck>G6oNGlm-H49knl%PS2p)RtdpG^}VX zujn+q*k68e$gpy(ymHF$QZf0=xGbOXxb*S)CAkZp&K^~%XkNaf*AFkMo?|bQFL?N! zyqww-rWPs7cB=iIs(nsY`}b9wL|(Caam7BeX2Xjbx5%qLFRlhf)<(RjjgP#x>&3Oy zNWq~Og5!~OXI|9hN7k3WsIQLvrT)b)&5;eaUo_l}ygvBi`s2vP=Pw%HMBe!L;)YyQ zQ%-3UeyNaLA*3#C)~#q>zVuh~ieDEm?MO@Y$n%*O(w5cW&6ERnQUIU?1OR1ur_8l- zKei-r%gz}6e0KM?g+FdtxLb3V%7sXy?FDCdTW&1)>B5h@HFrlY+_*jRn9-_@XA6G5 z6UqB|_mz!WMnCV)`dQ`oo1c#VeseeP=Z#ku78vbz+`h5k&#RyEWs;4~ZdWQWY+!Yq zZ11=(Kn`9;t}9&6=(~EduBYRAc2Q4W-@)sd*RLW)bywR?o-69;X@7dPsr~vu(Xo^5 z*G26azu(-`{`*awGGrH^JWnXRe3C~q_BP{*WrB;Y*YPBRCP5RFn|>LoJ9kymBs&pE z+6tq9G@ZJlo+9LO(ZtC`-}-UlE|qP0g!M zYg^Qt)YY0)*U;*#>rQLb8P}NpQvI(NO|O~Ouc)iOQe$aV*RY~qHiGK96}6_9zezCB zud}GGH?FrVrCHVdK7i`7YgToatLtQ^SE{Vc>lOd);Y(Lcu9?))>MiOnU9X&o&FYFp zU2WZIQ+-+M>JkG*`tO(iYIWKmzv#~fWvYsl)0Wj&PuE+@u3a;(wW_W@UDr@|dPTjp zK&GKfb*9&=S6F==%k%=%vAZ+38^^~9D;RNcQQ=zx6T)L-wy$7si46`}9vBz5;-}b{ zgpino?JFEYl0u?l<3i$BFrxw!LSy5jx336ihQ-E&xVSHm`~A}2TDd!H{HuZGa@z9k z!I3Kxx5uvtkJ%EH7#y-9Fg|+4=7gPbA={US!6>`M(&RnIkoJc~b$dEw##BiOo$0lefS;*+z)v*P&l(!Ca|L1`sfZXb_nYEs4NxH3`Ygfi?+xZ<6{&es^-9GQ9M4DYZPT7-n|X|I_`DFozcr*iY}&OwL3Cm zj)IvC6$qrrRFWGgZwA1t;$RFG0CIy*=~}FNZ?^yIe7`?X6IJf}s8Q-dy}t6HboCl?TLj z4GdKgL(M4_3di*Z$OE$Pziz_I=1(?;lw^M-GL!_WLV-9RzRj@ez`Ic#B=L*bkM~A3r;wlID>m;S8RAFfZ@S zw!mMzF;xl+f82Mdb-pgs@h1(ZuimAyU-s6ir&vM3Pb{7ssS;>bnO&GcoHQ8BlNF_-NYdVFhlx9zrMym;PK;9HC`k&S!h0!X!GL^YHM+NAwN z-}h^}J%rxLMQ`VC!;S%jmkRh92)`0*Pi+>eb>^vt(&m3_2CInVZQ6daNtd?~anlpx z(7P9)cdkDW7l+;zC!fSU5T|iKNwf$*nTa2v5n^bBC)4<8CVr(ti!Ae26>F+B2U0_6 z2Uj(~tGa)(tdX~FfUWn*uM$lYlLFAY!_XFC2jXSFp#yQ52jT+IN&4s{>3o^k9ngWz z3l40f9Ej&1*vaQDotnl^4ddT7;U|G@8UV0ZHlMW$ms@HUqn0=?>X#GRuO|=d>wv_P zl?uxgmhQs^1i?-Vsx*{(EU}QOQJ}_MVxVrW{_l4|8fMj+^;>G}s=h95piG{S1OPwI zV=Vo8zCiXfZyk_^3t0fLp2*2wHon?++w=<-P_37zCXp2yc+^Q*t%0XL3+nGn)lZi*kX074?fsW2$ZIH|@&Wm8T`NE1 zEeX#ze9>$Y{lx0k?y~t9g$45V#MW(Y3l+Z2u`?X}I!ArkNE|JfO@DiqhSzo_7jL8L zAOAjD^UB|(!}2gq0XEivO=$2+JNS>{1Z)Ap^vpks6HTynH*8Z{G(QCRrZ=AU?Pk+0 z!`4h~XI6+GyEvNjY)^m!DyVzyLdw@cGSlT9Z-)tgTp;gCY5LaKpazod1WHM>$IEV= zK*F=phYAmtS1i0!lkuWKrer&8D}=q>gzW@yckOWf5N@yuHw54x2ka%Y>@=_rfvW5C zm;QKAz{1h6>g|hXkOuLa6XuRAdt>dKeW8ptnsMEo5r` zA#FcV`I+&2nKbBsp1f=>KKU&g%4( z>Hlid>J^~M|76mWx8=~^98ErOaftWH`B;Sow`D%a(=M(Kko!}a`7#Gw<(>Pr)AfO> z@zoIVuhl^jvzc6(d+NKE{#VN(NQQC48u-xw{CF;Yau`4N=hSkY$=UyE2`72~;i1Be zrTo7-)s3gFUrTQI*Qfrpgq`Y?eLPA!sPczjs}%B-E5P)n-7*OaD*naeD#_pGr6DtB zqv|G5HsuqDfy^D8f*DKyQu4on252OcFKDJ@3XM+il(IqPZ}R_8GQ+4%sM^g?6ARUb z8Psthb(*0r6{RiP+^&W6H!5Zt6{moXr=b&==%hF_Hxs>!rvBaKY54h$En9eU^U}Ve zUvF#byaoG4G%#A`|D?M6$^lueD3$xaYmf1#_LNJ(h^1kW&hM5y8^kd9OEU%CU)}!? zAN)h}O8=mi{~1nuZ^{|VJQtAv?sxwRhK+S>4UqXamyf?}_q+Lh1RQ7WyeZ7EzX8`L zxbst!2DT*t+m?$J4P(1CWEmDtoQwN6^PAQn%mfgmxy#6q+&`hvpLziQV=g@PCWh*N zE^+D2RR6#5CobNV!Olh6~2xC0Q?pIgD*p0Z5Z=}ndz{U zO#g~n!fyb}UYho&`%sIwF@qTBzoJH`{2Dj&XqlPuLl-Y>{SyHHTnONgh!CJn=KdWC z6%@ZMeQn6#>ZO$L;Y_Cd|BPsjT(-i(KOel$t?+L+^RGF>-_{~__;;L%tJ3%$5xC!ivN1e=;%|vZr#pTu z4*xYW(pj=)9c)b;LZbpTP+RO!{}37fbxj{vp-2DcWqs0(shs|r>{rtk)-V^=#w`?N zF08Lw*wDSOaeCpf25MpN_gqmP_j|UmGVLGJnC$sa{{|!f5X8UZs!V1kY9tr+qzd)8 z31z1u5UTv$-{*Y=*eY~#H#%h+ovVP!r(p`2nBq80X(pz;3RCf4M%%Qs?e8hylq^U6 zD_#6oeE6r7Pd)_vg89#U>AxV=|0ao*Gb~IstdKLRk&$HNmbRoW70E5@l~HBnmXD?` zpOjlMle%J7j=m43r^{QOfGxA-tqNhQ3i(wv-{>(du(j-eo?h5SB5yki+fIJx$;hwY zx9=MhW}jpByba&UFg5!&Hq3Ks+20Q-x|cXVLqn?;fUt@^&)1QMf;%0u@=a z{|~wgD!O-nv;-CNmGOd#o!K8di{kD(z)eT*JaJ%WHhNdf#Z2n+%hbsp>eOrM^dj{) z#_BV!>hHFxOOL64ysSRkqdxaqU1RZ*B_>O>-InOaFVR1~#Bj;A=0jEM4-483H+^HU zbg$14|DD9rcJwPXrJbMYn8k0;%5^+b+J2_W@vNZzY?EVlTl+VTO8dEC$DHx@oN34N z()RQJ6Z52LLq*%4r@Zmi?qsmtA1UwWs$YU3}0JHIq- zY-qdF(7o{+t7K#2_?^b-jW?usZa_|LX`;4Fr*^)mJ=f`Wspxi<)BnH~aq5zay8fhp z@H+-_od-)h2CJMO2s$1#IZN99&H(8cns$C9?RW%j8c*vS&)hV@@BCkpI{yD8jjqqb zE_35ubJH$gq+MU2KX?~e-9O|pF=gGD%glv!-3x`xf2LmWTqy^8D92otvU-&AT$Rgu zlrOug)b*$cT~*tARC`?2271&+T&WX1)Yq=+A9~dPuk48bE8F4!%3k1ku)p&VWF&+< z51+C=pUWP;b$z}ekmfM<-1 zGw|9o_CtT{f2;oAPww&BGjM;;h*!$Q{gl^Udq3RY%VVb<6sH~gTPgoC`)k!$$WCt; zr}wZk2E-X7>?0H6Bd^&+(FG(u0Gg$9&4N2Fvn%%F71JFZ*1m8@wR&`R9`Q|Fu5;wahJPJI49F zx?Lu@eVKEoPI5=c5w%N1J)DjKNyiAMb3)Sjn$z_`(#7)=AABf2<~NY_a3Ifbu$N%NP(9043 zsfnSf*Z!|Q488ilR**X`0;%9bj3y;5fO)NX0V>HTGk}@O`vIj#kz9mQ85ooyr6Qmy zm9Y@TH4+3&r-E3NF{Lel27@@18ATir2ZMN&C1pII3I+)%8;Uew8U`t-KuTI5Z9k}l z3Zd`=$RfL5ppO6iuWBj763 zONwAi=C$TksA)>e7LB7qYt#&-cT2!gp$$q(8Qqe5RA`HurOa#@J}O*|(ootLtZ`hp z9;K~xA{b~)bwueY_r6E

3GIN(-f( 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%0D#cse0B&{riv? MIcn^v`2Rfr7m^=FE&u=k literal 0 HcmV?d00001 diff --git a/TrustKit/Dependencies/domain_registry/libassert_lib.a b/TrustKit/Dependencies/domain_registry/libassert_lib.a deleted file mode 100644 index 30099270b2229616268489fb9ea691e7426d89c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14672 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 O?A)99O}`=`!7=u>mpWe%^K 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 b-}}zgfB)N3|NAGWeNS5d)9+o;Bjf%TuL2U^ diff --git a/TrustKit/Dependencies/domain_registry/libinit_registry_tables_lib.a b/TrustKit/Dependencies/domain_registry/libinit_registry_tables_lib.a deleted file mode 100644 index 3db2637b57472021f4a739c57c2dc7c420c5fb78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 427064 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 jr7K`-D;kxa8$WGjju0Y$4CMfX6e`Zy(; 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 diff --git a/TrustKit/Dependencies/domain_registry/osx/libassert_lib.a b/TrustKit/Dependencies/domain_registry/osx/libassert_lib.a new file mode 100644 index 0000000000000000000000000000000000000000..a0254271bbecf93d245fb468b674346431067d3d GIT binary patch literal 2984 zcmd^BO>7%Q6n+UNHK~*OP$57REy6h<(cq2Tq^;VL5WCt!qDJ{CMQSo$>~$QJ*p|H( z1yK>HDq>|S<-nmr9H8RBkz>T6s+3bXK#o235-Eow!7b{c<@^JXc z-aNmVdC$K;{_T#4ba#my0=|He6zN&lb1m!H7Kz-2tozL~b~RT#*ZY?F?oiTbl9@^k zjU6#8((o&<@B`w;FKaY3 zjsjKMDcJR8cdS-(s;*_1^2<&Y(sCdWHRHJH@`}AwnsyeKYHs!O-Ij>g9BPJZbc{DO zq65zM+Www{WrQJrKKko1lG4RQA!ic7h-V1Qo5xKG7Cl-0T^t^tKS6V34=g&?I| z=c*gb1AaDhdA7-ivk&wn^!F!BN1`g^LFo6-r zki)(F%G(&^X?GBsv%IYf-lq4DTx{OOyA$z0G`w-o?VjJzX7f)T zP-b~&X*0huP&+-4A2i0T%=m{!!CqQ+@~4e~S`d~Tr4gv>i)rb)8t;n74n^0H1IEu# zcb){q_6za(;Y7>KMNOKW@`2q#yFIP;hh-~ti3=%*d^MBI~@72pC9@3((h>xmKQ zD*-MLqtF9P2fiO06@jD`4DzdFKy?iAzxbTUHO+5o{swsj z622cyMRp7bNoFGnrCsZ(F#dcN5&wGa9swX#Z8 z%D5d)wHD}{_`t*UYe$9MNIO|Q2RpVTZ|kXB z@0)ih?9iED0^)Mq$-YxSoJ-$vk=x82=qJ{8+=1IXN086YiTu2#`Dx&%Eqp$ZGj|cz sQ`SG)@(zTxFRXj-L&khkeg&Au2y@ssp^{g9sbKk0wexjhx^UzJU>0RR91 literal 0 HcmV?d00001 diff --git a/TrustKit/Dependencies/domain_registry/osx/libdomain_registry_lib.a b/TrustKit/Dependencies/domain_registry/osx/libdomain_registry_lib.a new file mode 100644 index 0000000000000000000000000000000000000000..b381d29889fa9673fd87b282ada9a0eae87d9f63 GIT binary patch literal 16704 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 literal 0 HcmV?d00001 diff --git a/TrustKit/Dependencies/domain_registry/osx/libinit_registry_tables_lib.a b/TrustKit/Dependencies/domain_registry/osx/libinit_registry_tables_lib.a new file mode 100644 index 0000000000000000000000000000000000000000..d534ccd19e463c8d00210118ed648bd7afb5f9fa GIT binary patch literal 129088 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 TkP-3bZ(I2L=l^BH&HVFURa-@X literal 0 HcmV?d00001 From 96daaf781138b1d18dec4af7d86515ef6cce3753 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 18:18:17 -0700 Subject: [PATCH 007/118] Tweak project file --- TrustKit.xcodeproj/project.pbxproj | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index d465b9e2..0cbcde77 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -852,10 +852,10 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; - SDKROOT = "$(inherited)"; + SDKROOT = iphoneos; SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "$(inherited)"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "armv7 arm64"; }; name = Debug; }; @@ -882,10 +882,10 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; - SDKROOT = "$(inherited)"; + SDKROOT = iphoneos; SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "$(inherited)"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "armv7 arm64"; }; name = Release; }; @@ -957,10 +957,10 @@ ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = "$(inherited)"; + SDKROOT = iphoneos; SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "$(inherited)"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "armv7 arm64"; }; name = Debug; }; @@ -980,16 +980,18 @@ ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = "$(inherited)"; + SDKROOT = iphoneos; SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "$(inherited)"; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "armv7 arm64"; }; name = Release; }; 8CA6CC0E1BAE2ADD00BDA419 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = ""; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; @@ -1012,6 +1014,7 @@ 8CA6CC0F1BAE2ADD00BDA419 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -1035,6 +1038,7 @@ 8CA6CC101BAE2ADD00BDA419 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_NO_COMMON_BLOCKS = YES; @@ -1049,6 +1053,7 @@ 8CA6CC111BAE2ADD00BDA419 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CODE_SIGN_IDENTITY = ""; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; From 39b13d1b45ecb6c47fcdede25aea31a7210b0f28 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 19 Sep 2015 18:20:29 -0700 Subject: [PATCH 008/118] Fix deployment targets --- TrustKit.xcodeproj/project.pbxproj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 0cbcde77..e818f764 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -842,6 +842,7 @@ ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -873,6 +874,7 @@ ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -949,7 +951,7 @@ "DEBUG=1", "$(inherited)", ); - IPHONEOS_DEPLOYMENT_TARGET = 8.3; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", @@ -973,7 +975,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_BITCODE = "$(inherited)"; GCC_NO_COMMON_BLOCKS = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.3; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", From 88569f7aa419add67d63a47bb69d5d00226d4fb1 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 7 Oct 2015 16:44:27 -0700 Subject: [PATCH 009/118] Put all the domains' pinning policies under a TSKPinnedDomains key and add new global TSKSwizzleNetworkDelegates key --- TrustKit/Pinning/ssl_pin_verifier.m | 7 +- TrustKit/TrustKit.h | 3 + TrustKit/TrustKit.m | 48 +++++-- TrustKitTests/TSKPinConfigurationTests.m | 129 +++++++++-------- TrustKitTests/TSKPinValidationOfflineTests.m | 140 ++++++++++++------- TrustKitTests/TSKPinValidationOnlineTests.m | 50 ++++--- TrustKitTests/TSKPublicKeyAlgorithmTests.m | 48 ++++--- 7 files changed, 257 insertions(+), 168 deletions(-) diff --git a/TrustKit/Pinning/ssl_pin_verifier.m b/TrustKit/Pinning/ssl_pin_verifier.m index 0619e0cc..1bfa9ef2 100644 --- a/TrustKit/Pinning/ssl_pin_verifier.m +++ b/TrustKit/Pinning/ssl_pin_verifier.m @@ -49,15 +49,16 @@ static BOOL isSubdomain(NSString *domain, NSString *subdomain) NSString *getPinningConfigurationKeyForDomain(NSString *hostname, NSDictionary *trustKitConfiguration) { NSString *configHostname = nil; + NSDictionary *domainsPinningPolicy = trustKitConfiguration[kTSKPinnedDomains]; - if (trustKitConfiguration[hostname] == nil) + if (domainsPinningPolicy[hostname] == nil) { // No pins explicitly configured for this domain // Look for an includeSubdomain pin that applies - for (NSString *pinnedServerName in trustKitConfiguration) + for (NSString *pinnedServerName in domainsPinningPolicy) { // Check each domain configured with the includeSubdomain flag - if ([trustKitConfiguration[pinnedServerName][kTSKIncludeSubdomains] boolValue]) + if ([domainsPinningPolicy[pinnedServerName][kTSKIncludeSubdomains] boolValue]) { // Is the server a subdomain of this pinned server? TSKLog(@"Checking includeSubdomains configuration for %@", pinnedServerName); diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 1d3c8b62..3e706b71 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -19,6 +19,9 @@ FOUNDATION_EXPORT const unsigned char TrustKitVersionString[]; #pragma mark TrustKit Configuration Keys + +FOUNDATION_EXPORT const NSString *kTSKSwizzleNetworkDelegates; +FOUNDATION_EXPORT const NSString *kTSKPinnedDomains; FOUNDATION_EXPORT const NSString *kTSKPublicKeyHashes; FOUNDATION_EXPORT const NSString *kTSKEnforcePinning; FOUNDATION_EXPORT const NSString *kTSKIncludeSubdomains; diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index e62a50fa..24fcfb78 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -22,10 +22,13 @@ #pragma mark Configuration Constants // Info.plist key we read the public key hashes from -static NSString * const kTSKConfiguration = @"TSKConfiguration"; +static const NSString *kTSKConfiguration = @"TSKConfiguration"; +// General keys +const NSString *kTSKSwizzleNetworkDelegates = @"TSKSwizzleNetworkDelegates"; +const NSString *kTSKPinnedDomains = @"TSKPinnedDomains"; -// Keys for each domain within the config dictionnary +// Keys for each domain within the TSKPinnedDomains entry const NSString *kTSKPublicKeyHashes = @"TSKPublicKeyHashes"; const NSString *kTSKEnforcePinning = @"TSKEnforcePinning"; const NSString *kTSKIncludeSubdomains = @"TSKIncludeSubdomains"; @@ -207,8 +210,31 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) InitializeDomainRegistry(); NSMutableDictionary *finalConfiguration = [[NSMutableDictionary alloc]init]; + finalConfiguration[kTSKPinnedDomains] = [[NSMutableDictionary alloc]init]; - for (NSString *domainName in TrustKitArguments) + + // Retrieve global settings + NSNumber *shouldSwizzleNetworkDelegates = TrustKitArguments[kTSKSwizzleNetworkDelegates]; + if (shouldSwizzleNetworkDelegates) + { + finalConfiguration[kTSKSwizzleNetworkDelegates] = shouldSwizzleNetworkDelegates; + } + else + { + // Default setting is YES + finalConfiguration[kTSKSwizzleNetworkDelegates] = [NSNumber numberWithBool:YES]; + } + + + if ((TrustKitArguments[kTSKPinnedDomains] == nil) || ([TrustKitArguments[kTSKPinnedDomains] count] < 1)) + { + [NSException raise:@"TrustKit configuration invalid" + format:@"TrustKit was initialized with zero pinned domains; ensure your domain pinning policies are under the TSKPinnedDomains key."]; + } + + + // Retrieve the pinning policy for each domains + for (NSString *domainName in TrustKitArguments[kTSKPinnedDomains]) { // Sanity checks on the domain name if (GetRegistryLength([domainName UTF8String]) == 0) @@ -219,12 +245,12 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) // Retrieve the supplied arguments for this domain - NSDictionary *domainTrustKitArguments = TrustKitArguments[domainName]; + NSDictionary *domainPinningPolicy = TrustKitArguments[kTSKPinnedDomains][domainName]; NSMutableDictionary *domainFinalConfiguration = [[NSMutableDictionary alloc]init]; // Extract the optional includeSubdomains setting - NSNumber *shouldIncludeSubdomains = domainTrustKitArguments[kTSKIncludeSubdomains]; + NSNumber *shouldIncludeSubdomains = domainPinningPolicy[kTSKIncludeSubdomains]; if (shouldIncludeSubdomains) { if ([shouldIncludeSubdomains boolValue] == YES) @@ -248,7 +274,7 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) // Extract the optional enforcePinning setting - NSNumber *shouldEnforcePinning = domainTrustKitArguments[kTSKEnforcePinning]; + NSNumber *shouldEnforcePinning = domainPinningPolicy[kTSKEnforcePinning]; if (shouldEnforcePinning) { domainFinalConfiguration[kTSKEnforcePinning] = shouldEnforcePinning; @@ -276,7 +302,7 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) // Extract the optional disableDefaultReportUri setting - NSNumber *shouldDisableDefaultReportUri = domainTrustKitArguments[kTSKDisableDefaultReportUri]; + NSNumber *shouldDisableDefaultReportUri = domainPinningPolicy[kTSKDisableDefaultReportUri]; if (shouldDisableDefaultReportUri) { domainFinalConfiguration[kTSKDisableDefaultReportUri] = shouldDisableDefaultReportUri; @@ -289,7 +315,7 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) // Extract the list of public key algorithms to support and convert them from string to the TSKPublicKeyAlgorithm type - NSArray *publicKeyAlgsStr = domainTrustKitArguments[kTSKPublicKeyAlgorithms]; + NSArray *publicKeyAlgsStr = domainPinningPolicy[kTSKPublicKeyAlgorithms]; if (publicKeyAlgsStr == nil) { [NSException raise:@"TrustKit configuration invalid" @@ -320,7 +346,7 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) // Extract and convert the report URIs if defined - NSArray *reportUriList = domainTrustKitArguments[kTSKReportUris]; + NSArray *reportUriList = domainPinningPolicy[kTSKReportUris]; if (reportUriList != nil) { NSMutableArray *reportUriListFinal = [NSMutableArray array]; @@ -340,7 +366,7 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) // Extract and convert the subject public key info hashes - NSArray *serverSslPinsBase64 = domainTrustKitArguments[kTSKPublicKeyHashes]; + NSArray *serverSslPinsBase64 = domainPinningPolicy[kTSKPublicKeyHashes]; if ([serverSslPinsBase64 count] < 2) { [NSException raise:@"TrustKit configuration invalid" @@ -366,7 +392,7 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) domainFinalConfiguration[kTSKPublicKeyHashes] = [NSSet setWithArray:serverSslPinsData]; // Store the whole configuration - finalConfiguration[domainName] = [NSDictionary dictionaryWithDictionary:domainFinalConfiguration]; + finalConfiguration[kTSKPinnedDomains][domainName] = [NSDictionary dictionaryWithDictionary:domainFinalConfiguration]; } return finalConfiguration; diff --git a/TrustKitTests/TSKPinConfigurationTests.m b/TrustKitTests/TSKPinConfigurationTests.m index 9f87bb45..b1165dd2 100644 --- a/TrustKitTests/TSKPinConfigurationTests.m +++ b/TrustKitTests/TSKPinConfigurationTests.m @@ -38,10 +38,11 @@ - (void)tearDown // Pin to only one key and ensure it fails; TrustKit requires at least two pins (which should include a backup pin) - (void)testPinOnePublicKey { - XCTAssertThrows(parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}), + XCTAssertThrows(parseTrustKitArguments(@{kTSKPinnedDomains : @{ + @"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}), @"Configuration with one pin only must be rejected"); } @@ -50,10 +51,11 @@ - (void)testPinOnePublicKey - (void)testGetConfigurationPinningEnabled { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY="]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : @{ + @"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY="]}}}); NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig); XCTAssert([serverConfigKey isEqualToString:@"www.good.com"], @"Did not receive a configuration for a pinned domain"); @@ -63,11 +65,12 @@ - (void)testGetConfigurationPinningEnabled - (void)testGetConfigurationPinningDisabled { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : @{ + @"good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}); // Ensure www.datatheorem.com gets no configuration NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.datatheorem.com", trustKitConfig); @@ -78,12 +81,13 @@ - (void)testGetConfigurationPinningDisabled - (void)testIncludeSubdomainsEnabled { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"good.com" : @{ - kTSKIncludeSubdomains : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : @{ + @"good.com" : @{ + kTSKIncludeSubdomains : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}); // Ensure www.good.com gets the configuration set for good.com as includeSubdomains is enabled NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig); @@ -94,12 +98,12 @@ - (void)testIncludeSubdomainsEnabled - (void)testIncludeSubdomainsEnabledSameDomain { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"good.com" : @{ - kTSKIncludeSubdomains : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : @{@"good.com" : @{ + kTSKIncludeSubdomains : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}); // Ensure good.com gets the configuration set for good.com as includeSubdomains is enabled NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"good.com", trustKitConfig); @@ -110,12 +114,13 @@ - (void)testIncludeSubdomainsEnabledSameDomain - (void)testIncludeSubdomainsEnabledSubSubDomain { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKIncludeSubdomains : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKIncludeSubdomains : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}); NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"sub.www.good.com.www.good.com", trustKitConfig); XCTAssert([serverConfigKey isEqualToString:@"www.good.com"], @"IncludeSubdomains did not work"); @@ -125,12 +130,13 @@ - (void)testIncludeSubdomainsEnabledSubSubDomain - (void)testIncludeSubdomainsEnabledNotSubdomain { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"good.com" : @{ - kTSKIncludeSubdomains : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"good.com" : @{ + kTSKIncludeSubdomains : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}); // Corner case to ensure two different domains with similar strings don't get returned as subdomains NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"good.com.otherdomain.com", trustKitConfig); @@ -140,12 +146,13 @@ - (void)testIncludeSubdomainsEnabledNotSubdomain - (void)testIncludeSubdomainsEnabledForSuffix { - XCTAssertThrows(parseTrustKitArguments(@{@"com" : @{ - kTSKIncludeSubdomains : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}), + XCTAssertThrows(parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"com" : @{ + kTSKIncludeSubdomains : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}), @"Configuration that pins *.com must be rejected"); } @@ -153,12 +160,13 @@ - (void)testIncludeSubdomainsEnabledForSuffix - (void)testIncludeSubdomainsDisabled { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"good.com" : @{ - kTSKIncludeSubdomains : @NO, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"good.com" : @{ + kTSKIncludeSubdomains : @NO, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}); // Ensure www.good.com does not get the configuration set for good.com NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig); @@ -169,17 +177,18 @@ - (void)testIncludeSubdomainsDisabled - (void)testIncludeSubdomainsEnabledAndSpecificConfiguration { NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"good.com" : @{ - kTSKIncludeSubdomains : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" - ]}, - @"www.good.com": @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"good.com" : @{ + kTSKIncludeSubdomains : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}, + @"www.good.com": @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" + ]}}}); // Ensure the configuration specific to www.good.com takes precedence over the more general config for good.com NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig); diff --git a/TrustKitTests/TSKPinValidationOfflineTests.m b/TrustKitTests/TSKPinValidationOfflineTests.m index 3b231386..3d64da40 100644 --- a/TrustKitTests/TSKPinValidationOfflineTests.m +++ b/TrustKitTests/TSKPinValidationOfflineTests.m @@ -64,18 +64,22 @@ - (void)testVerifyAgainstAnyPublicKey // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server key - @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key - ]}}); - + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server key + @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key + ]}}}); + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); - + XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); } @@ -90,18 +94,22 @@ - (void)testVerifyAgainstIntermediateCAPublicKey arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) anchorCertificates:(const void **)trustStoreArray arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - + // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate Key - @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=" // Intermediate Key - ]}}); - + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate Key + @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=" // Intermediate Key + ]}}}); + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); @@ -121,16 +129,20 @@ - (void)testVerifyAgainstCAPublicKey // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); - + XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); } @@ -148,14 +160,18 @@ - (void)testVerifyAgainstLeafPublicKey // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Leaf Key - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf Key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Leaf Key + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf Key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); @@ -176,14 +192,18 @@ - (void)testVerifyAgainstBadPublicKey // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad Key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Bad key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad Key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Bad key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultSuccess; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); XCTAssert(verificationResult == TSKPinValidationResultFailed, @"Validation must NOT pass against invalid public key pins"); @@ -203,14 +223,18 @@ - (void)testVerifyAgainstLeafPublicKeyAndBadPublicKey // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad key - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad key + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against a good and an invalid public key pins"); @@ -230,14 +254,18 @@ - (void)testVerifyAgainstCaPublicKeyAndBadCertificateChain // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); XCTAssert(verificationResult == TSKPinValidationResultFailedCertificateChainNotTrusted, @"Validation must fail against an invalid certificate chain"); @@ -257,14 +285,18 @@ - (void)testVerifyAgainstCaPublicKeyAndBadHostname // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.bad.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.bad.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.bad.com", trustKitConfig[@"www.bad.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.bad.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.bad.com", + trustKitConfig[kTSKPinnedDomains][@"www.bad.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.bad.com"][kTSKPublicKeyHashes]); CFRelease(trust); XCTAssert(verificationResult == TSKPinValidationResultFailedCertificateChainNotTrusted, @"Validation must fail against an invalid hostname"); diff --git a/TrustKitTests/TSKPinValidationOnlineTests.m b/TrustKitTests/TSKPinValidationOnlineTests.m index c5651108..df362aaf 100644 --- a/TrustKitTests/TSKPinValidationOnlineTests.m +++ b/TrustKitTests/TSKPinValidationOnlineTests.m @@ -20,7 +20,7 @@ @interface TSKPinValidationOnlineTests : XCTestCase @implementation TSKPinValidationOnlineTests /* WARNING: For the online tests, we need to use a different domain for every test otherwise the tests will be disrupted by SSL session resumption. - Specifically, connecting to the same host more than once will potentially allow the first session to be resumed, thereby skipping all SSL validation including TrustKit's. This is not a security issue but will make the tests report unexpected results. + Specifically, connecting to the same host more than once will potentially allow the first session to be resumed, thereby skipping all SSL validation including TrustKit's. This is not a security issue but will make the tests report unexpected results. */ - (void)setUp { @@ -43,11 +43,13 @@ - (void)testConnectionValidatingCAPublicKey { NSDictionary *trustKitConfig = @{ - @"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key - ]}}; + kTSKPinnedDomains : + @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ]}}}; [TrustKit initializeWithConfiguration:trustKitConfig]; @@ -68,12 +70,14 @@ - (void)testConnectionUsingFakeHashInvalidatingAllCertificates { NSDictionary *trustKitConfig = @{ - @"www.yahoo.com" : @{ - kTSKEnforcePinning : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key - ]}}; + kTSKPinnedDomains : + @{ + @"www.yahoo.com" : @{ + kTSKEnforcePinning : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; [TrustKit initializeWithConfiguration:trustKitConfig]; @@ -92,21 +96,23 @@ - (void)testConnectionUsingFakeHashInvalidatingAllCertificates - (void)testConnectionUsingFakeHashInvalidatingAllCertificatesButNotEnforcingPinning { NSDictionary *trustKitConfig = - @{ - @"www.google.com" : @{ - kTSKEnforcePinning : @NO, // Pinning disabled! - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key - ]}}; - + @{ + kTSKPinnedDomains : + @{ + @"www.google.com" : @{ + kTSKEnforcePinning : @NO, // Pinning disabled! + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; + [TrustKit initializeWithConfiguration:trustKitConfig]; - + NSError *error = nil; NSHTTPURLResponse *response; NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.com"]]; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; - + XCTAssertNil(error, @"Connection had an error: %@", error); XCTAssert(response.statusCode==200, @"Server did not respond with a 200 OK"); XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); diff --git a/TrustKitTests/TSKPublicKeyAlgorithmTests.m b/TrustKitTests/TSKPublicKeyAlgorithmTests.m index d74492b0..f92f1f35 100644 --- a/TrustKitTests/TSKPublicKeyAlgorithmTests.m +++ b/TrustKitTests/TSKPublicKeyAlgorithmTests.m @@ -49,14 +49,18 @@ - (void)testVerifyRsa2048 // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=", // Leaf Key - @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=", // Leaf Key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=", // Leaf Key + @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=", // Leaf Key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.datatheorem.com", trustKitConfig[@"www.datatheorem.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.datatheorem.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.datatheorem.com", + trustKitConfig[kTSKPinnedDomains][@"www.datatheorem.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.datatheorem.com"][kTSKPublicKeyHashes]); CFRelease(trust); CFRelease(leafCertificate); CFRelease(intermediateCertificate); @@ -81,14 +85,18 @@ - (void)testVerifyRsa4096 // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server Key - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server Key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server Key + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server Key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"www.good.com", trustKitConfig[@"www.good.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"www.good.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); CFRelease(trust); CFRelease(leafCertificate); CFRelease(intermediateCertificate); @@ -112,14 +120,18 @@ - (void)testVerifyEcDsaSecp256r1 // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{@"istlsfastyet.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmEcDsaSecp256r1], - kTSKPublicKeyHashes : @[@"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key - @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key - ]}}); + trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : + @{@"istlsfastyet.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmEcDsaSecp256r1], + kTSKPublicKeyHashes : @[@"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key + @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key + ]}}}); TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, @"istlsfastyet.com", trustKitConfig[@"istlsfastyet.com"][kTSKPublicKeyAlgorithms], trustKitConfig[@"istlsfastyet.com"][kTSKPublicKeyHashes]); + verificationResult = verifyPublicKeyPin(trust, + @"istlsfastyet.com", + trustKitConfig[kTSKPinnedDomains][@"istlsfastyet.com"][kTSKPublicKeyAlgorithms], + trustKitConfig[kTSKPinnedDomains][@"istlsfastyet.com"][kTSKPublicKeyHashes]); CFRelease(trust); CFRelease(leafCertificate); CFRelease(intermediateCertificate); From 83c3f1b4e0ea0b4786ced7cd9bc013baa0d9d7c3 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 7 Oct 2015 16:46:30 -0700 Subject: [PATCH 010/118] Switch TSKIgnorePinningForUserDefinedTrustAnchors to global settings --- TrustKit/TrustKit.m | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 24fcfb78..97af34d9 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -214,6 +214,8 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) // Retrieve global settings + + // Should we auto-swizzle network delegates NSNumber *shouldSwizzleNetworkDelegates = TrustKitArguments[kTSKSwizzleNetworkDelegates]; if (shouldSwizzleNetworkDelegates) { @@ -226,6 +228,22 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) } +#if !TARGET_OS_IPHONE + // OS X only: extract the optional ignorePinningForUserDefinedTrustAnchors setting + NSNumber *shouldIgnorePinningForUserDefinedTrustAnchors = domainTrustKitArguments[kTSKIgnorePinningForUserDefinedTrustAnchors]; + if (shouldIgnorePinningForUserDefinedTrustAnchors) + { + domainFinalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = shouldIgnorePinningForUserDefinedTrustAnchors; + } + else + { + // Default setting is YES + domainFinalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = [NSNumber numberWithBool:YES]; + } +#endif + + + // Retrieve the pinning policy for each domains if ((TrustKitArguments[kTSKPinnedDomains] == nil) || ([TrustKitArguments[kTSKPinnedDomains] count] < 1)) { [NSException raise:@"TrustKit configuration invalid" @@ -233,7 +251,6 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) } - // Retrieve the pinning policy for each domains for (NSString *domainName in TrustKitArguments[kTSKPinnedDomains]) { // Sanity checks on the domain name @@ -286,21 +303,6 @@ static OSStatus replaced_SSLHandshake(SSLContextRef context) } -#if !TARGET_OS_IPHONE - // OS X only: extract the optional ignorePinningForUserDefinedTrustAnchors setting - NSNumber *shouldIgnorePinningForUserDefinedTrustAnchors = domainTrustKitArguments[kTSKIgnorePinningForUserDefinedTrustAnchors]; - if (shouldIgnorePinningForUserDefinedTrustAnchors) - { - domainFinalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = shouldIgnorePinningForUserDefinedTrustAnchors; - } - else - { - // Default setting is YES - domainFinalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = [NSNumber numberWithBool:YES]; - } -#endif - - // Extract the optional disableDefaultReportUri setting NSNumber *shouldDisableDefaultReportUri = domainPinningPolicy[kTSKDisableDefaultReportUri]; if (shouldDisableDefaultReportUri) From dfd625fa49baace0e141bcd02a8574da649cf064 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 7 Oct 2015 16:54:13 -0700 Subject: [PATCH 011/118] Partially update documentation --- TrustKit/TrustKit.h | 62 ++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 3e706b71..7f227486 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -42,33 +42,47 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; Initializing TrustKit requires supplying a dictionary containing domain names as keys and dictionaries as values. Each domain dictionary should specify some configuration keys, which will specify the pinning policy for this domain. For example: - NSDictionary *trustKitConfig; - trustKitConfig = @{ - @"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[ - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", - @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" - ], - kTSKEnforcePinning : @NO, - kTSKReportUris : @[@"http://report.datatheorem.com/log_hpkp_report"], - }, - @"yahoo.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[ - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", - ], - kTSKIncludeSubdomains : @YES - } - }; + NSDictionary *trustKitConfig; + trustKitConfig = @{ + kTSKPinnedDomains : @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[ + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", + @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" + ], + kTSKEnforcePinning : @NO, + kTSKReportUris : @[@"http://report.datatheorem.com/log_hpkp_report"], + }, + @"yahoo.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[ + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", + ], + kTSKIncludeSubdomains : @YES + } + }}; [TrustKit initializeWithConfiguration:trustKitConfig]; It is also possible to supply the pinning policy by adding these configuration keys to the App's _Info.plist_ under a `TSKConfiguration` dictionary key. When doing so, no method needs to be called and TrustKit will automatically be initialized with the policy. - ### Required Configuration Keys + ### Global Configuration Keys + + #### `kTSKPinnedDomains` (required) + TBD + + #### `kTSKSwizzleNetworkDelegates` (optional) + TBD + + #### `kTSKIgnorePinningForUserDefinedTrustAnchors` (optional - OS X only) + If set to `YES`, pinning validation will be skipped if the server's certificate chain terminates at a user-defined trust anchor (such as a root CA that isn't part of OS X's default trust store) and no pin failure reports will be sent; default value is `YES`. + This is useful for allowing SSL connections through corporate proxies or firewalls. See "How does key pinning interact with local proxies and filters?" within the Chromium security FAQ at https://www.chromium.org/Home/chromium-security/security-faq for more information. + + + ### Required Domain-specific Keys #### `kTSKPublicKeyHashes` An array of SSL pins; each pin is the base64-encoded SHA-256 hash of a certificate's Subject Public Key Info. TrustKit will verify that at least one of the specified pins is found in the server's evaluated certificate chain. @@ -77,7 +91,7 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; An array of `kTSKAlgorithm` constants to specify the public key algorithms for the keys to be pinned. TrustKit requires this information in order to compute SSL pins when validating a server's certificate chain, because there are no APIs to directly extract the key's algorithm from an SSL certificate. To minimize the performance impact of Trustkit, only one algorithm should be enabled. - ### Optional Configuration Keys + ### Optional Domain-specific Keys #### `kTSKIncludeSubdomains` If set to `YES`, also pin all the subdomains of the specified domain; default value is `NO`. @@ -111,10 +125,6 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; If set to `YES`, the default report URL for sending pin failure reports will be disabled; default value is `NO`. By default, pin failure reports are sent to a report server hosted by Data Theorem, for detecting potential CA compromises and man-in-the-middle attacks, as well as providing a free dashboard for developers. Only pin failure reports are sent, which contain the App's bundle ID and the server's hostname and certificate chain that failed validation. - #### `kTSKIgnorePinningForUserDefinedTrustAnchors` (OS X only) - If set to `YES`, pinning validation will be skipped if the server's certificate chain terminates at a user-defined trust anchor (such as a root CA that isn't part of OS X's default trust store) and no pin failure reports will be sent; default value is `YES`. - This is useful for allowing SSL connections through corporate proxies or firewalls. See "How does key pinning interact with local proxies and filters?" within the Chromium security FAQ at https://www.chromium.org/Home/chromium-security/security-faq for more information. - ### Public Key Algorithms Keys From 7d880083ffc76bab41efc8e433c4ad7cce325a00 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 7 Oct 2015 17:09:41 -0700 Subject: [PATCH 012/118] Add two extra configuration tests --- TrustKitTests/TSKPinConfigurationTests.m | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/TrustKitTests/TSKPinConfigurationTests.m b/TrustKitTests/TSKPinConfigurationTests.m index b1165dd2..0d04ad31 100644 --- a/TrustKitTests/TSKPinConfigurationTests.m +++ b/TrustKitTests/TSKPinConfigurationTests.m @@ -195,4 +195,29 @@ - (void)testIncludeSubdomainsEnabledAndSpecificConfiguration XCTAssert([serverConfigKey isEqualToString:@"www.good.com"], @"IncludeSubdomains took precedence over a more specialized configuration"); } + +- (void)testNoPinnedDomains +{ + XCTAssertThrows(parseTrustKitArguments(@{kTSKSwizzleNetworkDelegates : @YES}), + @"Configuration with no pinned domains must be rejected"); +} + + +- (void)testGlobalSettings +{ + NSDictionary *trustKitConfig; + trustKitConfig = parseTrustKitArguments(@{kTSKSwizzleNetworkDelegates: @NO, + kTSKPinnedDomains : + @{@"good.com" : @{ + kTSKIncludeSubdomains : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" + ]}}}); + + // Ensure the kTSKSwizzleNetworkDelegates setting was saved + NSDictionary *savedTrustKitConfig = [TrustKit configuration]; + XCTAssert([savedTrustKitConfig[kTSKSwizzleNetworkDelegates] boolValue] == NO, @"kTSKSwizzleNetworkDelegates was not saved in the configuration"); +} + @end \ No newline at end of file From 1c9e2e9618dbafa53048dfeaf453eb35607211d9 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 14:26:41 -0700 Subject: [PATCH 013/118] Add RSSwizzle to dependencies --- TrustKit/Dependencies/RSSwizzle/RSSwizzle.h | 371 ++++++++++++++++++++ TrustKit/Dependencies/RSSwizzle/RSSwizzle.m | 322 +++++++++++++++++ 2 files changed, 693 insertions(+) create mode 100755 TrustKit/Dependencies/RSSwizzle/RSSwizzle.h create mode 100755 TrustKit/Dependencies/RSSwizzle/RSSwizzle.m diff --git a/TrustKit/Dependencies/RSSwizzle/RSSwizzle.h b/TrustKit/Dependencies/RSSwizzle/RSSwizzle.h new file mode 100755 index 00000000..9b91ace3 --- /dev/null +++ b/TrustKit/Dependencies/RSSwizzle/RSSwizzle.h @@ -0,0 +1,371 @@ +// +// RSSwizzle.h +// RSSwizzleTests +// +// Created by Yan Rabovik on 05.09.13. +// +// + +#import + +#pragma mark - Macros Based API + +/// A macro for wrapping the return type of the swizzled method. +#define RSSWReturnType(type) type + +/// A macro for wrapping arguments of the swizzled method. +#define RSSWArguments(arguments...) _RSSWArguments(arguments) + +/// A macro for wrapping the replacement code for the swizzled method. +#define RSSWReplacement(code...) code + +/// A macro for casting and calling original implementation. +/// May be used only in RSSwizzleInstanceMethod or RSSwizzleClassMethod macros. +#define RSSWCallOriginal(arguments...) _RSSWCallOriginal(arguments) + +#pragma mark └ Swizzle Instance Method + +/** + Swizzles the instance method of the class with the new implementation. + + Example for swizzling `-(int)calculate:(int)number;` method: + + @code + + RSSwizzleInstanceMethod(classToSwizzle, + @selector(calculate:), + RSSWReturnType(int), + RSSWArguments(int number), + RSSWReplacement( + { + // Calling original implementation. + int res = RSSWCallOriginal(number); + // Returning modified return value. + return res + 1; + }), 0, NULL); + + @endcode + + Swizzling frequently goes along with checking whether this particular class (or one of its superclasses) has been already swizzled. Here the `RSSwizzleMode` and `key` parameters can help. See +[RSSwizzle swizzleInstanceMethod:inClass:newImpFactory:mode:key:] for details. + + Swizzling is fully thread-safe. + + @param classToSwizzle The class with the method that should be swizzled. + + @param selector Selector of the method that should be swizzled. + + @param RSSWReturnType The return type of the swizzled method wrapped in the RSSWReturnType macro. + + @param RSSWArguments The arguments of the swizzled method wrapped in the RSSWArguments macro. + + @param RSSWReplacement The code of the new implementation of the swizzled method wrapped in the RSSWReplacement macro. + + @param RSSwizzleMode The mode is used in combination with the key to indicate whether the swizzling should be done for the given class. You can pass 0 for RSSwizzleModeAlways. + + @param key The key is used in combination with the mode to indicate whether the swizzling should be done for the given class. May be NULL if the mode is RSSwizzleModeAlways. + + @return YES if successfully swizzled and NO if swizzling has been already done for given key and class (or one of superclasses, depends on the mode). + + */ +#define RSSwizzleInstanceMethod(classToSwizzle, \ + selector, \ + RSSWReturnType, \ + RSSWArguments, \ + RSSWReplacement, \ + RSSwizzleMode, \ + key) \ + _RSSwizzleInstanceMethod(classToSwizzle, \ + selector, \ + RSSWReturnType, \ + _RSSWWrapArg(RSSWArguments), \ + _RSSWWrapArg(RSSWReplacement), \ + RSSwizzleMode, \ + key) + +#pragma mark └ Swizzle Class Method + +/** + Swizzles the class method of the class with the new implementation. + + Example for swizzling `+(int)calculate:(int)number;` method: + + @code + + RSSwizzleClassMethod(classToSwizzle, + @selector(calculate:), + RSSWReturnType(int), + RSSWArguments(int number), + RSSWReplacement( + { + // Calling original implementation. + int res = RSSWCallOriginal(number); + // Returning modified return value. + return res + 1; + })); + + @endcode + + Swizzling is fully thread-safe. + + @param classToSwizzle The class with the method that should be swizzled. + + @param selector Selector of the method that should be swizzled. + + @param RSSWReturnType The return type of the swizzled method wrapped in the RSSWReturnType macro. + + @param RSSWArguments The arguments of the swizzled method wrapped in the RSSWArguments macro. + + @param RSSWReplacement The code of the new implementation of the swizzled method wrapped in the RSSWReplacement macro. + + */ +#define RSSwizzleClassMethod(classToSwizzle, \ + selector, \ + RSSWReturnType, \ + RSSWArguments, \ + RSSWReplacement) \ + _RSSwizzleClassMethod(classToSwizzle, \ + selector, \ + RSSWReturnType, \ + _RSSWWrapArg(RSSWArguments), \ + _RSSWWrapArg(RSSWReplacement)) + +#pragma mark - Main API + +/** + A function pointer to the original implementation of the swizzled method. + */ +typedef void (*RSSwizzleOriginalIMP)(void /* id, SEL, ... */ ); + +/** + RSSwizzleInfo is used in the new implementation block to get and call original implementation of the swizzled method. + */ +@interface RSSwizzleInfo : NSObject + +/** + Returns the original implementation of the swizzled method. + + It is actually either an original implementation if the swizzled class implements the method itself; or a super implementation fetched from one of the superclasses. + + @note You must always cast returned implementation to the appropriate function pointer when calling. + + @return A function pointer to the original implementation of the swizzled method. + */ +-(RSSwizzleOriginalIMP)getOriginalImplementation; + +/// The selector of the swizzled method. +@property (nonatomic, readonly) SEL selector; + +@end + +/** + A factory block returning the block for the new implementation of the swizzled method. + + You must always obtain original implementation with swizzleInfo and call it from the new implementation. + + @param swizzleInfo An info used to get and call the original implementation of the swizzled method. + + @return A block that implements a method. + Its signature should be: `method_return_type ^(id self, method_args...)`. + The selector is not available as a parameter to this block. + */ +typedef id (^RSSwizzleImpFactoryBlock)(RSSwizzleInfo *swizzleInfo); + +typedef NS_ENUM(NSUInteger, RSSwizzleMode) { + /// RSSwizzle always does swizzling. + RSSwizzleModeAlways = 0, + /// RSSwizzle does not do swizzling if the same class has been swizzled earlier with the same key. + RSSwizzleModeOncePerClass = 1, + /// RSSwizzle does not do swizzling if the same class or one of its superclasses have been swizzled earlier with the same key. + /// @note There is no guarantee that your implementation will be called only once per method call. If the order of swizzling is: first inherited class, second superclass, then both swizzlings will be done and the new implementation will be called twice. + RSSwizzleModeOncePerClassAndSuperclasses = 2 +}; + +@interface RSSwizzle : NSObject + +#pragma mark └ Swizzle Instance Method + +/** + Swizzles the instance method of the class with the new implementation. + + Original implementation must always be called from the new implementation. And because of the the fact that for safe and robust swizzling original implementation must be dynamically fetched at the time of calling and not at the time of swizzling, swizzling API is a little bit complicated. + + You should pass a factory block that returns the block for the new implementation of the swizzled method. And use swizzleInfo argument to retrieve and call original implementation. + + Example for swizzling `-(int)calculate:(int)number;` method: + + @code + + SEL selector = @selector(calculate:); + [RSSwizzle + swizzleInstanceMethod:selector + inClass:classToSwizzle + newImpFactory:^id(RSSWizzleInfo *swizzleInfo) { + // This block will be used as the new implementation. + return ^int(__unsafe_unretained id self, int num){ + // You MUST always cast implementation to the correct function pointer. + int (*originalIMP)(__unsafe_unretained id, SEL, int); + originalIMP = (__typeof(originalIMP))[swizzleInfo getOriginalImplementation]; + // Calling original implementation. + int res = originalIMP(self,selector,num); + // Returning modified return value. + return res + 1; + }; + } + mode:RSSwizzleModeAlways + key:NULL]; + + @endcode + + Swizzling frequently goes along with checking whether this particular class (or one of its superclasses) has been already swizzled. Here the `mode` and `key` parameters can help. + + Here is an example of swizzling `-(void)dealloc;` only in case when neither class and no one of its superclasses has been already swizzled with our key. However "Deallocating ..." message still may be logged multiple times per method call if swizzling was called primarily for an inherited class and later for one of its superclasses. + + @code + + static const void *key = &key; + SEL selector = NSSelectorFromString(@"dealloc"); + [RSSwizzle + swizzleInstanceMethod:selector + inClass:classToSwizzle + newImpFactory:^id(RSSWizzleInfo *swizzleInfo) { + return ^void(__unsafe_unretained id self){ + NSLog(@"Deallocating %@.",self); + + void (*originalIMP)(__unsafe_unretained id, SEL); + originalIMP = (__typeof(originalIMP))[swizzleInfo getOriginalImplementation]; + originalIMP(self,selector); + }; + } + mode:RSSwizzleModeOncePerClassAndSuperclasses + key:key]; + + @endcode + + Swizzling is fully thread-safe. + + @param selector Selector of the method that should be swizzled. + + @param classToSwizzle The class with the method that should be swizzled. + + @param factoryBlock The factory block returning the block for the new implementation of the swizzled method. + + @param mode The mode is used in combination with the key to indicate whether the swizzling should be done for the given class. + + @param key The key is used in combination with the mode to indicate whether the swizzling should be done for the given class. May be NULL if the mode is RSSwizzleModeAlways. + + @return YES if successfully swizzled and NO if swizzling has been already done for given key and class (or one of superclasses, depends on the mode). + */ ++(BOOL)swizzleInstanceMethod:(SEL)selector + inClass:(Class)classToSwizzle + newImpFactory:(RSSwizzleImpFactoryBlock)factoryBlock + mode:(RSSwizzleMode)mode + key:(const void *)key; + +#pragma mark └ Swizzle Class method + +/** + Swizzles the class method of the class with the new implementation. + + Original implementation must always be called from the new implementation. And because of the the fact that for safe and robust swizzling original implementation must be dynamically fetched at the time of calling and not at the time of swizzling, swizzling API is a little bit complicated. + + You should pass a factory block that returns the block for the new implementation of the swizzled method. And use swizzleInfo argument to retrieve and call original implementation. + + Example for swizzling `+(int)calculate:(int)number;` method: + + @code + + SEL selector = @selector(calculate:); + [RSSwizzle + swizzleClassMethod:selector + inClass:classToSwizzle + newImpFactory:^id(RSSWizzleInfo *swizzleInfo) { + // This block will be used as the new implementation. + return ^int(__unsafe_unretained id self, int num){ + // You MUST always cast implementation to the correct function pointer. + int (*originalIMP)(__unsafe_unretained id, SEL, int); + originalIMP = (__typeof(originalIMP))[swizzleInfo getOriginalImplementation]; + // Calling original implementation. + int res = originalIMP(self,selector,num); + // Returning modified return value. + return res + 1; + }; + }]; + + @endcode + + Swizzling is fully thread-safe. + + @param selector Selector of the method that should be swizzled. + + @param classToSwizzle The class with the method that should be swizzled. + + @param factoryBlock The factory block returning the block for the new implementation of the swizzled method. + */ ++(void)swizzleClassMethod:(SEL)selector + inClass:(Class)classToSwizzle + newImpFactory:(RSSwizzleImpFactoryBlock)factoryBlock; + +@end + +#pragma mark - Implementation details +// Do not write code that depends on anything below this line. + +// Wrapping arguments to pass them as a single argument to another macro. +#define _RSSWWrapArg(args...) args + +#define _RSSWDel2Arg(a1, a2, args...) a1, ##args +#define _RSSWDel3Arg(a1, a2, a3, args...) a1, a2, ##args + +// To prevent comma issues if there are no arguments we add one dummy argument +// and remove it later. +#define _RSSWArguments(arguments...) DEL, ##arguments + +#define _RSSwizzleInstanceMethod(classToSwizzle, \ + selector, \ + RSSWReturnType, \ + RSSWArguments, \ + RSSWReplacement, \ + RSSwizzleMode, \ + KEY) \ + [RSSwizzle \ + swizzleInstanceMethod:selector \ + inClass:[classToSwizzle class] \ + newImpFactory:^id(RSSwizzleInfo *swizzleInfo) { \ + RSSWReturnType (*originalImplementation_)(_RSSWDel3Arg(__unsafe_unretained id, \ + SEL, \ + RSSWArguments)); \ + SEL selector_ = selector; \ + return ^RSSWReturnType (_RSSWDel2Arg(__unsafe_unretained id self, \ + RSSWArguments)) \ + { \ + RSSWReplacement \ + }; \ + } \ + mode:RSSwizzleMode \ + key:KEY]; + +#define _RSSwizzleClassMethod(classToSwizzle, \ + selector, \ + RSSWReturnType, \ + RSSWArguments, \ + RSSWReplacement) \ + [RSSwizzle \ + swizzleClassMethod:selector \ + inClass:[classToSwizzle class] \ + newImpFactory:^id(RSSwizzleInfo *swizzleInfo) { \ + RSSWReturnType (*originalImplementation_)(_RSSWDel3Arg(__unsafe_unretained id, \ + SEL, \ + RSSWArguments)); \ + SEL selector_ = selector; \ + return ^RSSWReturnType (_RSSWDel2Arg(__unsafe_unretained id self, \ + RSSWArguments)) \ + { \ + RSSWReplacement \ + }; \ + }]; + +#define _RSSWCallOriginal(arguments...) \ + ((__typeof(originalImplementation_))[swizzleInfo \ + getOriginalImplementation])(self, \ + selector_, \ + ##arguments) diff --git a/TrustKit/Dependencies/RSSwizzle/RSSwizzle.m b/TrustKit/Dependencies/RSSwizzle/RSSwizzle.m new file mode 100755 index 00000000..209a7ab8 --- /dev/null +++ b/TrustKit/Dependencies/RSSwizzle/RSSwizzle.m @@ -0,0 +1,322 @@ +// +// RSSwizzle.m +// RSSwizzleTests +// +// Created by Yan Rabovik on 05.09.13. +// +// + +#import "RSSwizzle.h" +#import +#import + +#if !__has_feature(objc_arc) +#error This code needs ARC. Use compiler option -fobjc-arc +#endif + +#pragma mark - Block Helpers +#if !defined(NS_BLOCK_ASSERTIONS) + +// See http://clang.llvm.org/docs/Block-ABI-Apple.html#high-level +struct Block_literal_1 { + void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock + int flags; + int reserved; + void (*invoke)(void *, ...); + struct Block_descriptor_1 { + unsigned long int reserved; // NULL + unsigned long int size; // sizeof(struct Block_literal_1) + // optional helper functions + void (*copy_helper)(void *dst, void *src); // IFF (1<<25) + void (*dispose_helper)(void *src); // IFF (1<<25) + // required ABI.2010.3.16 + const char *signature; // IFF (1<<30) + } *descriptor; + // imported variables +}; + +enum { + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code + BLOCK_IS_GLOBAL = (1 << 28), + BLOCK_HAS_STRET = (1 << 29), // IFF BLOCK_HAS_SIGNATURE + BLOCK_HAS_SIGNATURE = (1 << 30), +}; +typedef int BlockFlags; + +static const char *blockGetType(id block){ + struct Block_literal_1 *blockRef = (__bridge struct Block_literal_1 *)block; + BlockFlags flags = blockRef->flags; + + if (flags & BLOCK_HAS_SIGNATURE) { + void *signatureLocation = blockRef->descriptor; + signatureLocation += sizeof(unsigned long int); + signatureLocation += sizeof(unsigned long int); + + if (flags & BLOCK_HAS_COPY_DISPOSE) { + signatureLocation += sizeof(void(*)(void *dst, void *src)); + signatureLocation += sizeof(void (*)(void *src)); + } + + const char *signature = (*(const char **)signatureLocation); + return signature; + } + + return NULL; +} + +static BOOL blockIsCompatibleWithMethodType(id block, const char *methodType){ + + const char *blockType = blockGetType(block); + + NSMethodSignature *blockSignature; + + if (0 == strncmp(blockType, (const char *)"@\"", 2)) { + // Block return type includes class name for id types + // while methodType does not include. + // Stripping out return class name. + char *quotePtr = strchr(blockType+2, '"'); + if (NULL != quotePtr) { + ++quotePtr; + char filteredType[strlen(quotePtr) + 2]; + memset(filteredType, 0, sizeof(filteredType)); + *filteredType = '@'; + strncpy(filteredType + 1, quotePtr, sizeof(filteredType) - 2); + + blockSignature = [NSMethodSignature signatureWithObjCTypes:filteredType]; + }else{ + return NO; + } + }else{ + blockSignature = [NSMethodSignature signatureWithObjCTypes:blockType]; + } + + NSMethodSignature *methodSignature = + [NSMethodSignature signatureWithObjCTypes:methodType]; + + if (!blockSignature || !methodSignature) { + return NO; + } + + if (blockSignature.numberOfArguments != methodSignature.numberOfArguments){ + return NO; + } + + if (strcmp(blockSignature.methodReturnType, methodSignature.methodReturnType) != 0) { + return NO; + } + + for (int i=0; i Date: Sun, 11 Oct 2015 14:29:37 -0700 Subject: [PATCH 014/118] Add tentative NSURLConnection delegate proxy and tests --- TrustKit.xcodeproj/project.pbxproj | 48 +++++ .../TSKNSURLConnectionDelegateProxy.h | 31 +++ .../TSKNSURLConnectionDelegateProxy.m | 180 ++++++++++++++++++ TrustKit/TrustKit.m | 94 +-------- TrustKitTests/TSKNSURLConnectionTests.m | 128 +++++++++++++ 5 files changed, 394 insertions(+), 87 deletions(-) create mode 100644 TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h create mode 100644 TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m create mode 100644 TrustKitTests/TSKNSURLConnectionTests.m diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index e818f764..62320440 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -89,6 +89,17 @@ 8CC78B281B1B696D00523A25 /* sni41871.cloudflaressl.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1D1B1B55EC00523A25 /* sni41871.cloudflaressl.com.der */; }; 8CC78B291B1B697000523A25 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1C1B1B55EC00523A25 /* COMODOECCDomainValidationSecureServerCA2.der */; }; 8CCBD15B1B186D1100CB88AF /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCBD15A1B186D1100CB88AF /* reporting_utils.m */; }; + 8CD5F7311BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7321BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7331BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7341BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7351BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7381BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7391BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7421BCB06F4005801D8 /* RSSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7431BCB06F4005801D8 /* RSSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7441BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); }; }; 8CE9191E1AEA073C002B29AE /* public_key_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE9191C1AEA073C002B29AE /* public_key_utils.h */; }; 8CE9191F1AEA073C002B29AE /* public_key_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE9191D1AEA073C002B29AE /* public_key_utils.m */; }; 8CE919221AEA077F002B29AE /* ssl_pin_verifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */; }; @@ -172,6 +183,11 @@ 8CC78B221B1B604A00523A25 /* www.datatheorem.com.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = www.datatheorem.com.der; sourceTree = ""; }; 8CC78B241B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKPublicKeyAlgorithmTests.m; sourceTree = ""; }; 8CCBD15A1B186D1100CB88AF /* reporting_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = reporting_utils.m; path = Reporting/reporting_utils.m; sourceTree = ""; }; + 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKNSURLConnectionDelegateProxy.h; path = Swizzling/TSKNSURLConnectionDelegateProxy.h; sourceTree = ""; }; + 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKNSURLConnectionDelegateProxy.m; path = Swizzling/TSKNSURLConnectionDelegateProxy.m; sourceTree = ""; }; + 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKNSURLConnectionTests.m; sourceTree = ""; }; + 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSSwizzle.h; path = Dependencies/RSSwizzle/RSSwizzle.h; sourceTree = ""; }; + 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RSSwizzle.m; path = Dependencies/RSSwizzle/RSSwizzle.m; sourceTree = ""; }; 8CE9191C1AEA073C002B29AE /* public_key_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = public_key_utils.h; path = Pinning/public_key_utils.h; sourceTree = ""; }; 8CE9191D1AEA073C002B29AE /* public_key_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = public_key_utils.m; path = Pinning/public_key_utils.m; sourceTree = ""; }; 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ssl_pin_verifier.m; path = Pinning/ssl_pin_verifier.m; sourceTree = ""; }; @@ -273,6 +289,7 @@ 8C8480491A896EE30017C155 /* TrustKit */ = { isa = PBXGroup; children = ( + 8CA6CC571BAF60DA00BDA419 /* Swizzling */, 8CE919281AEA0F61002B29AE /* Dependencies */, 8CE919201AEA0745002B29AE /* Reporting */, 8CE9191B1AEA072A002B29AE /* Pinning */, @@ -297,6 +314,7 @@ children = ( 070868B31ADFF68200E5AFDC /* Certificates */, 0710306B1AA88A510028092C /* TSKPinValidationOnlineTests.m */, + 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */, 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */, 8C8480571A896EE30017C155 /* Supporting Files */, 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */, @@ -345,6 +363,15 @@ name = "OS X"; sourceTree = ""; }; + 8CA6CC571BAF60DA00BDA419 /* Swizzling */ = { + isa = PBXGroup; + children = ( + 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */, + 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */, + ); + name = Swizzling; + sourceTree = ""; + }; 8CC78B191B1B54F700523A25 /* ECDSA sec256r1 */ = { isa = PBXGroup; children = ( @@ -374,6 +401,15 @@ name = "RSA 4096"; sourceTree = ""; }; + 8CD5F73F1BCB06E8005801D8 /* RSSwizzle */ = { + isa = PBXGroup; + children = ( + 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */, + 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */, + ); + name = RSSwizzle; + sourceTree = ""; + }; 8CE9191B1AEA072A002B29AE /* Pinning */ = { isa = PBXGroup; children = ( @@ -408,6 +444,7 @@ 8CE919281AEA0F61002B29AE /* Dependencies */ = { isa = PBXGroup; children = ( + 8CD5F73F1BCB06E8005801D8 /* RSSwizzle */, 8C84806B1A896F3C0017C155 /* fishhook */, 8C3492901ADCA059001849FD /* domain_registry */, ); @@ -424,8 +461,10 @@ 8CE9192D1AEA0F7E002B29AE /* domain_registry.h in Headers */, 8CE9191E1AEA073C002B29AE /* public_key_utils.h in Headers */, 6B2B06AD1B05154A00FC749E /* TSKBackgroundReporter.h in Headers */, + 8CD5F7311BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */, 8C9EBE021B619BBE00CA7EE0 /* TSKReportsRateLimiter.h in Headers */, 6B032D3E1AF1A4AC00EAFA69 /* TSKSimpleReporter.h in Headers */, + 8CD5F7421BCB06F4005801D8 /* RSSwizzle.h in Headers */, 8C15F9931B132F9200F06C0E /* TSKPinningValidator.h in Headers */, 8C9492F61B2379A100F5DF38 /* reporting_utils.h in Headers */, 8C84804D1A896EE30017C155 /* TrustKit.h in Headers */, @@ -443,8 +482,10 @@ 8CA6CC171BAE2B6600BDA419 /* TSKSimpleReporter.h in Headers */, 8CA6CC1B1BAE2B6600BDA419 /* TSKPinFailureReport.h in Headers */, 8CA6CC141BAE2B6600BDA419 /* TSKReportsRateLimiter.h in Headers */, + 8CD5F7321BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */, 8CA6CC211BAE2B6A00BDA419 /* ssl_pin_verifier.h in Headers */, 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */, + 8CD5F7431BCB06F4005801D8 /* RSSwizzle.h in Headers */, 8CA6CC191BAE2B6600BDA419 /* TSKBackgroundReporter.h in Headers */, 8CA6CC271BAE2B7000BDA419 /* domain_registry.h in Headers */, 8CA6CC161BAE2B6600BDA419 /* TSKReporterDelegate.h in Headers */, @@ -656,8 +697,10 @@ 8CE919351AEA0F8B002B29AE /* fishhook.c in Sources */, 8C15F9A11B16094E00F06C0E /* TSKPinFailureReport.m in Sources */, 8C15F9941B132F9200F06C0E /* TSKPinningValidator.m in Sources */, + 8CD5F7331BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, 8C84806D1A896F660017C155 /* TrustKit.m in Sources */, 8CCBD15B1B186D1100CB88AF /* reporting_utils.m in Sources */, + 8CD5F7441BCB06F4005801D8 /* RSSwizzle.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -666,6 +709,7 @@ buildActionMask = 2147483647; files = ( 0710306C1AA88A510028092C /* TSKPinValidationOnlineTests.m in Sources */, + 8CD5F7381BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */, 8C15F9A41B17564400F06C0E /* TSKPinConfigurationTests.m in Sources */, 075AA1091AC985FD00178223 /* TSKPinValidationOfflineTests.m in Sources */, 8CC78B251B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m in Sources */, @@ -686,6 +730,7 @@ 8C8716B81B23AA0D00267E1D /* TrustKit.m in Sources */, 8C8716B21B23A9F400267E1D /* TSKBackgroundReporter.m in Sources */, 0E64A7601B867BA000CA164A /* TSKReportsRateLimiter.m in Sources */, + 8CD5F7341BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, 8C8716B11B23A9F000267E1D /* TSKSimpleReporter.m in Sources */, 8C8716B61B23AA0800267E1D /* ssl_pin_verifier.m in Sources */, ); @@ -703,8 +748,10 @@ 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */, 8CA6CC281BAE2B7500BDA419 /* fishhook.c in Sources */, 8CA6CC151BAE2B6600BDA419 /* TSKReportsRateLimiter.m in Sources */, + 8CD5F7351BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, 8CA6CC181BAE2B6600BDA419 /* TSKSimpleReporter.m in Sources */, 8CA6CC221BAE2B6A00BDA419 /* ssl_pin_verifier.m in Sources */, + 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -713,6 +760,7 @@ buildActionMask = 2147483647; files = ( 8CA6CC381BAE2C7200BDA419 /* TSKPinValidationOnlineTests.m in Sources */, + 8CD5F7391BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */, 8CA6CC3A1BAE2C7C00BDA419 /* TSKReporterTests.m in Sources */, 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */, 8CA6CC3C1BAE2C8100BDA419 /* TSKPublicKeyAlgorithmTests.m in Sources */, diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h new file mode 100644 index 00000000..0e2f4ada --- /dev/null +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h @@ -0,0 +1,31 @@ +// +// TSKNSURLConnectionDelegateProxy.h +// TrustKit +// +// Created by Alban Diquet on 10/7/15. +// Copyright © 2015 TrustKit. All rights reserved. +// + +#import + + +@interface TSKNSURLConnectionDelegateProxy : NSObject +{ + id originalDelegate; // The NSURLConnectionDelegate we're going to proxy +} + +// Initalize our hooks ++ (void)swizzleNSURLConnectionConstructor; + +- (TSKNSURLConnectionDelegateProxy *)initWithDelegate:(id)delegate; + +// Mirror the original delegate's list of implemented methods +- (BOOL)respondsToSelector:(SEL)aSelector ; + +// Forward messages to the original delegate if the proxy doesn't implement the method +- (id)forwardingTargetForSelector:(SEL)sel; + +- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; + + +@end diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m new file mode 100644 index 00000000..7bb92715 --- /dev/null +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -0,0 +1,180 @@ +// +// TSKNSURLConnectionDelegateProxy.m +// TrustKit +// +// Created by Alban Diquet on 10/7/15. +// Copyright © 2015 TrustKit. All rights reserved. +// + +#import "TSKNSURLConnectionDelegateProxy.h" +#import "TSKPinningValidator.h" +#import "TrustKit+Private.h" +#import "RSSwizzle.h" + + +static const void *swizzleOnceKey = &swizzleOnceKey; + + +@implementation TSKNSURLConnectionDelegateProxy + ++ (void)swizzleNSURLConnectionConstructor +{ + // - initWithRequest:delegate: + RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), + @selector(initWithRequest:delegate:), + RSSWReturnType(NSURLConnection*), + RSSWArguments(NSURLRequest *request, id delegate), + RSSWReplacement( + { + // Replace the delegate with our own so we can intercept and handle authentication challenges + TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; + NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate); + return connection; + }), RSSwizzleModeOncePerClass, swizzleOnceKey); + + + // - initWithRequest:delegate:startImmediately: + RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), + @selector(initWithRequest:delegate:startImmediately:), + RSSWReturnType(NSURLConnection*), + RSSWArguments(NSURLRequest *request, id delegate, BOOL startImmediately), + RSSWReplacement( + { + // Replace the delegate with our own so we can intercept and handle authentication challenges + TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; + NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate, startImmediately); + return connection; + }), RSSwizzleModeOncePerClass, swizzleOnceKey); + + + // TODO: Add warning for constructors that do not have a delegate (ie. we can't protect these connections) +} + + +- (TSKNSURLConnectionDelegateProxy *)initWithDelegate:(id)delegate +{ + self = [super init]; + if (self) + { + originalDelegate = delegate; + } + TSKLog(@"Proxy-ing NSURLConnectionDelegate: %@", NSStringFromClass([delegate class])); + return self; +} + + +- (BOOL)respondsToSelector:(SEL)aSelector +{ + if (aSelector == @selector(connection:willSendRequestForAuthenticationChallenge:)) + { + // The swizzled delegate should always receive authentication challenges + return YES; + } + else + { + // The swizzled delegate should mirror the original delegate's methods so that it doesn't change the app flow + return [originalDelegate respondsToSelector:aSelector]; + } +} + + +- (id)forwardingTargetForSelector:(SEL)sel +{ + // Forward messages to the original delegate if the proxy doesn't implement the method + return originalDelegate; +} + + +// NSURLConnection is deprecated in iOS 9 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +-(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge forConnection:(NSURLConnection *)connection +{ + BOOL wasChallengeHandled = NO; + + // Can the original delegate handle this challenge ? + if ([originalDelegate respondsToSelector:@selector(connection:willSendRequestForAuthenticationChallenge:)]) + { + // Yes - forward the challenge to the original delegate + wasChallengeHandled = YES; + [originalDelegate connection:connection willSendRequestForAuthenticationChallenge:challenge]; + } + else if ([originalDelegate respondsToSelector:@selector(connection:canAuthenticateAgainstProtectionSpace:)]) + { + if ([originalDelegate connection:connection canAuthenticateAgainstProtectionSpace:challenge.protectionSpace]) + { + // Yes - forward the challenge to the original delegate + wasChallengeHandled = YES; + [originalDelegate connection:connection didReceiveAuthenticationChallenge:challenge]; + } + } + + return wasChallengeHandled; +} +#pragma GCC diagnostic pop + + +- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + BOOL wasChallengeHandled = NO; + TSKPinValidationResult result = TSKPinValidationResultFailed; + + // For pinning we only care about server authentication + if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) + { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + NSString *serverHostname = challenge.protectionSpace.host; + + // Check the trust object against the pinning policy + result = [TSKPinningValidator evaluateTrust:serverTrust forHostname:serverHostname]; + if (result == TSKPinValidationResultSuccess) + { + // Success - don't do anything and forward the challenge to the original delegate + wasChallengeHandled = NO; + } + else if (result == TSKPinValidationResultDomainNotPinned) + { + if ([self forwardToOriginalDelegateAuthenticationChallenge:challenge forConnection:connection]) + { + // The original delegate handled the challenge and performed SSL validation itself + wasChallengeHandled = YES; + } + else + { + // The original delegate does not have authentication handlers for this challenge + // We need to do the default validation ourselves to avoid disabling SSL validation for all non pinned domains + SecTrustResultType trustResult = 0; + SecTrustEvaluate(serverTrust, &trustResult); + if ((trustResult != kSecTrustResultUnspecified) && (trustResult != kSecTrustResultProceed)) + { + // Default SSL validation failed - block the connection + CFDictionaryRef evaluationDetails = SecTrustCopyResult(serverTrust); + TSKLog(@"Error: default SSL validation failed: %@", evaluationDetails); + CFRelease(evaluationDetails); + wasChallengeHandled = YES; + [challenge.sender cancelAuthenticationChallenge:challenge]; + } + } + } + else + { + // Pinning validation failed - block the connection + wasChallengeHandled = YES; + [challenge.sender cancelAuthenticationChallenge:challenge]; + } + } + + // Forward all challenges (including client auth challenges) to the original delegate + if (wasChallengeHandled == NO) + { + if ([self forwardToOriginalDelegateAuthenticationChallenge:challenge forConnection:connection] == NO) + { + // The original delegate could not handle the challenge; use the default handler + [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } +} + + + +@end diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 97af34d9..3a7b6fb3 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -17,6 +17,7 @@ #import "domain_registry.h" #import "TSKBackgroundReporter.h" #import "TSKSimpleReporter.h" +#import "TSKNSURLConnectionDelegateProxy.h" #pragma mark Configuration Constants @@ -120,82 +121,6 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus } -#pragma mark SSLHandshake Hook - - -static OSStatus (*original_SSLHandshake)(SSLContextRef context) = NULL; - -static OSStatus replaced_SSLHandshake(SSLContextRef context) -{ - OSStatus result = original_SSLHandshake(context); - if ((result == noErr) && (_isTrustKitInitialized)) - { - // The handshake was sucessful, let's do our additional checks on the server certificate - _wasTrustKitCalled = YES; - char *serverName = NULL; - size_t serverNameLen = 0; - - // Get the server's domain name - SSLGetPeerDomainNameLength (context, &serverNameLen); - serverName = malloc(serverNameLen+1); - SSLGetPeerDomainName(context, serverName, &serverNameLen); - serverName[serverNameLen] = '\0'; - NSString *serverNameStr = [NSString stringWithUTF8String:serverName]; - free(serverName); - - // Retrieve the pinning configuration for this specific domain, if there is one - NSString *domainConfigKey = getPinningConfigurationKeyForDomain(serverNameStr, _trustKitGlobalConfiguration); - if (domainConfigKey != nil) - { - // This domain is pinned - NSDictionary *domainConfig = _trustKitGlobalConfiguration[domainConfigKey]; - - // Retrieve the server's trust object - SecTrustRef serverTrust; - SSLCopyPeerTrust(context, &serverTrust); - - // Re-evaluate the server's certificate chain and look for one the configured SPKI pins - TSKPinValidationResult validationResult = TSKPinValidationResultFailed; - validationResult = verifyPublicKeyPin(serverTrust, serverNameStr, domainConfig[kTSKPublicKeyAlgorithms], domainConfig[kTSKPublicKeyHashes]); - - if (validationResult == TSKPinValidationResultSuccess) - { - // Pin validation was successful - CFRelease(serverTrust); - } - else - { - // Pin validation failed -#if !TARGET_OS_IPHONE - if ((validationResult == TSKPinValidationResultFailedUserDefinedTrustAnchor) - && ([domainConfig[kTSKIgnorePinningForUserDefinedTrustAnchors] boolValue] == YES)) - { - // OS-X only: user-defined trust anchors can be whitelisted (for corporate proxies, etc.) - TSKLog(@"Ignoring pinning result for user-defined trust anchor"); - CFRelease(serverTrust); - } - else -#endif - { - // Send a pin failure report - sendPinFailureReport_async(validationResult, serverTrust, serverNameStr, domainConfigKey, domainConfig, ^void (void) - { - // Release the trust once the report has been sent - CFRelease(serverTrust); - }); - - // If TrustKit was configured to enforce pinning, make the connection fail - if ([domainConfig[kTSKEnforcePinning] boolValue] == YES) - { - result = errSSLXCertChainInvalid; - } - } - } - } - } - return result; -} - #pragma mark TrustKit Initialization Helper Functions @@ -423,19 +348,14 @@ static void initializeTrustKit(NSDictionary *trustKitConfig) // Convert and store the SSL pins in our global variable _trustKitGlobalConfiguration = [[NSDictionary alloc]initWithDictionary:parseTrustKitArguments(trustKitConfig)]; - // Hook SSLHandshake() - if (original_SSLHandshake == NULL) + // Hook network APIs if needed + if ([_trustKitGlobalConfiguration[kTSKSwizzleNetworkDelegates] boolValue] == YES) { - int rebindResult = -1; - char functionToHook[] = "SSLHandshake"; - original_SSLHandshake = dlsym(RTLD_DEFAULT, functionToHook); - rebindResult = rebind_symbols((struct rebinding[1]){{(char *)functionToHook, (void *)replaced_SSLHandshake}}, 1); - if ((rebindResult < 0) || (original_SSLHandshake == NULL)) - { - [NSException raise:@"TrustKit initialization error" - format:@"Fishook returned an error: %d", rebindResult]; - } + // NSURLConnection + [TSKNSURLConnectionDelegateProxy swizzleNSURLConnectionConstructor]; } + + // Create our reporter for sending pin validation failures @try diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m new file mode 100644 index 00000000..a2489e8a --- /dev/null +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -0,0 +1,128 @@ +// +// TSKNSURLConnectionTests.m +// TrustKit +// +// Created by Alban Diquet on 10/11/15. +// Copyright © 2015 TrustKit. All rights reserved. +// + +#import +#import "TrustKit+Private.h" + + +@interface TestNSURLConnectionDelegate : NSObject +{ + XCTestExpectation *testExpectation; +} +- (instancetype)initWithExpectation:(XCTestExpectation *)expectation; +- (void)connectionDidFinishLoading:(NSURLConnection *)connection; +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse; +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; +@end + + +@implementation TestNSURLConnectionDelegate { +} + +- (instancetype)initWithExpectation:(XCTestExpectation *)expectation +{ + self = [super init]; + if (self) + { + testExpectation = expectation; + } + return self; +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection {} + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error +{ + NSLog(@"%@ - failed: %@", NSStringFromClass([self class]), error); + [testExpectation fulfill]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data +{ + NSLog(@"%@ - received %lu bytes", NSStringFromClass([self class]), (unsigned long)[data length]); + [testExpectation fulfill]; +} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse +{ + return cachedResponse; +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response +{ + NSLog(@"%@ - success: %@", NSStringFromClass([self class]), [[response URL] host]); + [testExpectation fulfill]; +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse +{ + NSLog(@"%@ - redirect: %@", NSStringFromClass([self class]), [[request URL] host]); + [testExpectation fulfill]; + return request; +} + +@end + + +@interface TSKNSURLConnectionTests : XCTestCase + +@end + +@implementation TSKNSURLConnectionTests + +- (void)setUp { + [super setUp]; + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. + [super tearDown]; +} + +- (void)testExample { + + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"High Expectations"]; + + // NSURLConnection is deprecated +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + TestNSURLConnectionDelegate* deleg2 = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + NSURLConnection *conn2 = [[NSURLConnection alloc] + initWithRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.reddit.com/normal"]] + delegate:deleg2]; + [conn2 start]; +#pragma GCC diagnostic pop + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { + if (error) { + NSLog(@"Timeout Error: %@", error); + } + }]; +} + + + + +@end From 5f64910401175d5ec3b0ef5e99fcba0d58ce2948 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 14:38:58 -0700 Subject: [PATCH 015/118] Properly call the default handling mechanism --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 7bb92715..f69bcd6e 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -170,7 +170,7 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio if ([self forwardToOriginalDelegateAuthenticationChallenge:challenge forConnection:connection] == NO) { // The original delegate could not handle the challenge; use the default handler - [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; + [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; } } } From a7124fa04ac831db134132ad78a686a9c08bc0c7 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 14:42:52 -0700 Subject: [PATCH 016/118] Minor tweaks --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h | 2 +- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 4 ++-- TrustKit/TrustKit.m | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h index 0e2f4ada..3b3c45cc 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h @@ -15,7 +15,7 @@ } // Initalize our hooks -+ (void)swizzleNSURLConnectionConstructor; ++ (void)swizzleNSURLConnectionConstructors; - (TSKNSURLConnectionDelegateProxy *)initWithDelegate:(id)delegate; diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index f69bcd6e..8cfd7547 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -17,7 +17,7 @@ @implementation TSKNSURLConnectionDelegateProxy -+ (void)swizzleNSURLConnectionConstructor ++ (void)swizzleNSURLConnectionConstructors { // - initWithRequest:delegate: RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @@ -119,7 +119,7 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio BOOL wasChallengeHandled = NO; TSKPinValidationResult result = TSKPinValidationResultFailed; - // For pinning we only care about server authentication + // For SSL pinning we only care about server authentication if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 3a7b6fb3..98575821 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -352,7 +352,7 @@ static void initializeTrustKit(NSDictionary *trustKitConfig) if ([_trustKitGlobalConfiguration[kTSKSwizzleNetworkDelegates] boolValue] == YES) { // NSURLConnection - [TSKNSURLConnectionDelegateProxy swizzleNSURLConnectionConstructor]; + [TSKNSURLConnectionDelegateProxy swizzleNSURLConnectionConstructors]; } From e99686c77c5901b4c2d6e4ce86da61dfdbb1c9b5 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 14:47:41 -0700 Subject: [PATCH 017/118] Switch swizzling mode and add comment --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 8cfd7547..331471b7 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -15,11 +15,17 @@ static const void *swizzleOnceKey = &swizzleOnceKey; +@interface TSKNSURLConnectionDelegateProxy(Private) +-(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge forConnection:(NSURLConnection *)connection; +@end + + @implementation TSKNSURLConnectionDelegateProxy + (void)swizzleNSURLConnectionConstructors { // - initWithRequest:delegate: + // We can use RSSwizzleModeAlways, NULL as the swizzling parameters because this should only be called from within a dispatch_once() RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @selector(initWithRequest:delegate:), RSSWReturnType(NSURLConnection*), @@ -30,7 +36,7 @@ + (void)swizzleNSURLConnectionConstructors TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate); return connection; - }), RSSwizzleModeOncePerClass, swizzleOnceKey); + }), RSSwizzleModeAlways, NULL); // - initWithRequest:delegate:startImmediately: @@ -44,7 +50,7 @@ + (void)swizzleNSURLConnectionConstructors TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate, startImmediately); return connection; - }), RSSwizzleModeOncePerClass, swizzleOnceKey); + }), RSSwizzleModeAlways, NULL); // TODO: Add warning for constructors that do not have a delegate (ie. we can't protect these connections) From 0f53215d1a01c9f66f81d272bbd68e0cc05e31ea Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 15:42:09 -0700 Subject: [PATCH 018/118] Fix pinning configuration when using TSKPinningValidator --- TrustKit/Pinning/TSKPinningValidator.m | 8 ++++++-- TrustKit/Pinning/ssl_pin_verifier.m | 9 +++++---- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 10 ++++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.m b/TrustKit/Pinning/TSKPinningValidator.m index 9fbaa309..dfcbaad7 100644 --- a/TrustKit/Pinning/TSKPinningValidator.m +++ b/TrustKit/Pinning/TSKPinningValidator.m @@ -27,6 +27,7 @@ + (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(N if ((serverTrust == NULL) || (serverHostname == nil)) { + TSKLog(@"Pin validation error - invalid parameters for %@", serverHostname); return TSKPinValidationResultErrorInvalidParameters; } @@ -38,29 +39,32 @@ + (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(N if (domainConfigKey == nil) { // The domain is not pinned: nothing to validate + TSKLog(@"Domain not pinned - %@", serverHostname); validationResult = TSKPinValidationResultDomainNotPinned; } else { // This domain is pinned: look for one the configured public key pins in the server's evaluated certificate chain CFRetain(serverTrust); - NSDictionary *domainConfig = trustKitConfig[domainConfigKey]; + NSDictionary *domainConfig = trustKitConfig[kTSKPinnedDomains][domainConfigKey]; validationResult = verifyPublicKeyPin(serverTrust, serverHostname, domainConfig[kTSKPublicKeyAlgorithms], domainConfig[kTSKPublicKeyHashes]); if (validationResult == TSKPinValidationResultSuccess) { // Pin validation was successful + TSKLog(@"Pin validation succeeded for %@", serverHostname); CFRelease(serverTrust); } else { // Pin validation failed + TSKLog(@"Pin validation failed for %@", serverHostname); #if !TARGET_OS_IPHONE if ((validationResult == TSKPinValidationResultFailedUserDefinedTrustAnchor) && ([domainConfig[kTSKIgnorePinningForUserDefinedTrustAnchors] boolValue] == YES)) { // OS-X only: user-defined trust anchors can be whitelisted (for corporate proxies, etc.) so don't send reports - TSKLog(@"Ignoring pinning result for user-defined trust anchor"); + TSKLog(@"Ignoring pinning failure due to user-defined trust anchor for %@", serverHostname); CFRelease(serverTrust); } else diff --git a/TrustKit/Pinning/ssl_pin_verifier.m b/TrustKit/Pinning/ssl_pin_verifier.m index 1bfa9ef2..1c6fb715 100644 --- a/TrustKit/Pinning/ssl_pin_verifier.m +++ b/TrustKit/Pinning/ssl_pin_verifier.m @@ -92,6 +92,7 @@ TSKPinValidationResult verifyPublicKeyPin(SecTrustRef serverTrust, NSString *ser { if ((serverTrust == NULL) || (supportedAlgorithms == nil) || (knownPins == nil)) { + TSKLog(@"Invalid pinning parameters for %@", serverHostname); return TSKPinValidationResultErrorInvalidParameters; } @@ -108,7 +109,7 @@ TSKPinValidationResult verifyPublicKeyPin(SecTrustRef serverTrust, NSString *ser SecTrustResultType trustResult = 0; if (SecTrustEvaluate(serverTrust, &trustResult) != errSecSuccess) { - TSKLog(@"SecTrustEvaluate error"); + TSKLog(@"SecTrustEvaluate error for %@", serverHostname); return TSKPinValidationResultErrorInvalidParameters; } @@ -116,7 +117,7 @@ TSKPinValidationResult verifyPublicKeyPin(SecTrustRef serverTrust, NSString *ser { // Default SSL validation failed CFDictionaryRef evaluationDetails = SecTrustCopyResult(serverTrust); - TSKLog(@"Error: default SSL validation failed: %@", evaluationDetails); + TSKLog(@"Error: default SSL validation failed for %@: %@", serverHostname, evaluationDetails); CFRelease(evaluationDetails); return TSKPinValidationResultFailedCertificateChainNotTrusted; } @@ -138,7 +139,7 @@ TSKPinValidationResult verifyPublicKeyPin(SecTrustRef serverTrust, NSString *ser TSKLog(@"Testing SSL Pin %@", subjectPublicKeyInfoHash); if ([knownPins containsObject:subjectPublicKeyInfoHash]) { - TSKLog(@"SSL Pin found"); + TSKLog(@"SSL Pin found for %@", serverHostname); return TSKPinValidationResultSuccess; } } @@ -184,6 +185,6 @@ TSKPinValidationResult verifyPublicKeyPin(SecTrustRef serverTrust, NSString *ser #endif // If we get here, we didn't find any matching SPKI hash in the chain - TSKLog(@"Error: SSL Pin not found"); + TSKLog(@"Error: SSL Pin not found for %@", serverHostname); return TSKPinValidationResultFailed; } diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 331471b7..5c1675de 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -73,13 +73,18 @@ - (BOOL)respondsToSelector:(SEL)aSelector { if (aSelector == @selector(connection:willSendRequestForAuthenticationChallenge:)) { - // The swizzled delegate should always receive authentication challenges + // The delegate proxy should always receive authentication challenges return YES; } + if (aSelector == @selector(connection:didReceiveAuthenticationChallenge:)) + { + return NO; + } else { - // The swizzled delegate should mirror the original delegate's methods so that it doesn't change the app flow + // The delegate proxy should mirror the original delegate's methods so that it doesn't change the app flow return [originalDelegate respondsToSelector:aSelector]; + // return NO; } } @@ -149,6 +154,7 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio { // The original delegate does not have authentication handlers for this challenge // We need to do the default validation ourselves to avoid disabling SSL validation for all non pinned domains + TSKLog(@"Performing default certificate validation for %@", serverHostname); SecTrustResultType trustResult = 0; SecTrustEvaluate(serverTrust, &trustResult); if ((trustResult != kSecTrustResultUnspecified) && (trustResult != kSecTrustResultProceed)) From aa0c107e09402ec562436a67c9bf1fa0cce4b49a Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 15:51:23 -0700 Subject: [PATCH 019/118] Add RSSwizzle to ATTRIBUTIONS --- ATTRIBUTIONS | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/ATTRIBUTIONS b/ATTRIBUTIONS index e9daa662..d5a52b33 100644 --- a/ATTRIBUTIONS +++ b/ATTRIBUTIONS @@ -41,3 +41,27 @@ domain-registry-provider - https://code.google.com/p/domain-registry-provider/ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. + + +RSSwizzle - https://github.com/rabovik/RSSwizzle +------------------------------------------------ + +Copyright (c) 2013 Yan Rabovik + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file From 552813f0cbd7c727098010b0dc65c23f8b7a0142 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 15:51:34 -0700 Subject: [PATCH 020/118] Remove extra logging statement --- TrustKit/Pinning/TSKPinningValidator.m | 1 - 1 file changed, 1 deletion(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.m b/TrustKit/Pinning/TSKPinningValidator.m index dfcbaad7..aa7b2501 100644 --- a/TrustKit/Pinning/TSKPinningValidator.m +++ b/TrustKit/Pinning/TSKPinningValidator.m @@ -39,7 +39,6 @@ + (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(N if (domainConfigKey == nil) { // The domain is not pinned: nothing to validate - TSKLog(@"Domain not pinned - %@", serverHostname); validationResult = TSKPinValidationResultDomainNotPinned; } else From 5065284e489fc2cd7f78e7dfe88e73e28748c036 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 16:21:11 -0700 Subject: [PATCH 021/118] Display a warning for NSURLConnection methods where pinning cannot be enforced --- .../TSKNSURLConnectionDelegateProxy.m | 34 ++++++++++++++++-- TrustKitTests/TSKNSURLConnectionTests.m | 36 ++++++++++++------- 2 files changed, 56 insertions(+), 14 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 5c1675de..4dea860b 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -12,7 +12,9 @@ #import "RSSwizzle.h" -static const void *swizzleOnceKey = &swizzleOnceKey; + +typedef void (^AsyncCompletionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError); + @interface TSKNSURLConnectionDelegateProxy(Private) @@ -53,7 +55,35 @@ + (void)swizzleNSURLConnectionConstructors }), RSSwizzleModeAlways, NULL); - // TODO: Add warning for constructors that do not have a delegate (ie. we can't protect these connections) + // Not hooking + connectionWithRequest:delegate: as it ends up calling initWithRequest:delegate: + + // Log a warning for methods that do not have a delegate (ie. we can't protect these connections) + // + sendAsynchronousRequest:queue:completionHandler: + + RSSwizzleClassMethod(NSClassFromString(@"NSURLConnection"), + @selector(sendAsynchronousRequest:queue:completionHandler:), + RSSWReturnType(void), + RSSWArguments(NSURLRequest *request, NSOperationQueue *queue, AsyncCompletionHandler handler), + RSSWReplacement( + { + // Just display a warning + TSKLog(@"Warning: + sendAsynchronousRequest:queue:completionHandler: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); + RSSWCallOriginal(request, queue, handler); + })); + + + // + sendSynchronousRequest:returningResponse:error: + RSSwizzleClassMethod(NSClassFromString(@"NSURLConnection"), + @selector(sendSynchronousRequest:returningResponse:error:), + RSSWReturnType(NSData *), + RSSWArguments(NSURLRequest *request, NSURLResponse * _Nullable *response, NSError * _Nullable *error), + RSSWReplacement( + { + // Just display a warning + TSKLog(@"Warning: + sendSynchronousRequest:returningResponse:error: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); + NSData *data = RSSWCallOriginal(request, response, error); + return data; + })); } diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index a2489e8a..23711e92 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -46,7 +46,6 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { NSLog(@"%@ - received %lu bytes", NSStringFromClass([self class]), (unsigned long)[data length]); - [testExpectation fulfill]; } - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse @@ -63,7 +62,6 @@ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLRespon - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse { NSLog(@"%@ - redirect: %@", NSStringFromClass([self class]), [[request URL] host]); - [testExpectation fulfill]; return request; } @@ -86,13 +84,13 @@ - (void)tearDown { [super tearDown]; } -- (void)testExample { +- (void)testNSURLConnection { NSDictionary *trustKitConfig = @{ kTSKPinnedDomains : @{ - @"www.datatheorem.com" : @{ + @"www.yahoo.com" : @{ kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key @@ -101,20 +99,35 @@ - (void)testExample { [TrustKit initializeWithConfiguration:trustKitConfig]; - XCTestExpectation *expectation = [self expectationWithDescription:@"High Expectations"]; // NSURLConnection is deprecated #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - TestNSURLConnectionDelegate* deleg2 = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; - NSURLConnection *conn2 = [[NSURLConnection alloc] - initWithRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.reddit.com/normal"]] - delegate:deleg2]; - [conn2 start]; + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; + TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + NSURLConnection *connection = [[NSURLConnection alloc] + initWithRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.reddit.com/normal"]] + delegate:delegate]; + [connection start]; + + + // Run other methods that we swizzle to display a warning, to ensure they don't crash + XCTestExpectation *expectation2 = [self expectationWithDescription:@"Asynchronous request"]; + [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.datatheorem.com/test"]] + queue:[NSOperationQueue mainQueue] + completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { + [expectation2 fulfill]; + }]; + + [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.datatheorem.com/test"]] + returningResponse:nil error:nil]; #pragma GCC diagnostic pop + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { if (error) { NSLog(@"Timeout Error: %@", error); @@ -124,5 +137,4 @@ - (void)testExample { - @end From 30da1e40a1ede4cd7618a174219cc7fda5459e2d Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 16:34:08 -0700 Subject: [PATCH 022/118] Tweak the warnings --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 4dea860b..ed266a8f 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -67,7 +67,7 @@ + (void)swizzleNSURLConnectionConstructors RSSWReplacement( { // Just display a warning - TSKLog(@"Warning: + sendAsynchronousRequest:queue:completionHandler: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); + TSKLog(@"WARNING: +sendAsynchronousRequest:queue:completionHandler: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); RSSWCallOriginal(request, queue, handler); })); @@ -80,7 +80,7 @@ + (void)swizzleNSURLConnectionConstructors RSSWReplacement( { // Just display a warning - TSKLog(@"Warning: + sendSynchronousRequest:returningResponse:error: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); + TSKLog(@"WARNING: +sendSynchronousRequest:returningResponse:error: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); NSData *data = RSSWCallOriginal(request, response, error); return data; })); From 4dc244114dbdfefd870f71ea2ae54ae93ebade23 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 16:39:45 -0700 Subject: [PATCH 023/118] Clarify warnings --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index ed266a8f..0e95955b 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -67,7 +67,7 @@ + (void)swizzleNSURLConnectionConstructors RSSWReplacement( { // Just display a warning - TSKLog(@"WARNING: +sendAsynchronousRequest:queue:completionHandler: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); + TSKLog(@"WARNING: +sendAsynchronousRequest:queue:completionHandler: was called to connect to %@. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections", [[request URL]host]); RSSWCallOriginal(request, queue, handler); })); @@ -80,7 +80,7 @@ + (void)swizzleNSURLConnectionConstructors RSSWReplacement( { // Just display a warning - TSKLog(@"WARNING: +sendSynchronousRequest:returningResponse:error: was called. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections"); + TSKLog(@"WARNING: +sendSynchronousRequest:returningResponse:error: was called to connect to %@. This method does not expose a delegate argument for handling authentication challenges; TrustKit cannot enforce SSL pinning for these connections", [[request URL]host]); NSData *data = RSSWCallOriginal(request, response, error); return data; })); From 5052bc67d82582f8541c7f08ddbde58798f4ce0c Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 18:16:46 -0700 Subject: [PATCH 024/118] Add some more (currently failing) tests --- .../TSKNSURLConnectionDelegateProxy.m | 21 +- TrustKit/TrustKit+Private.h | 1 - TrustKit/TrustKit.m | 11 - TrustKitTests/TSKNSURLConnectionTests.m | 203 ++++++++++++++++-- TrustKitTests/TSKPinValidationOnlineTests.m | 10 +- 5 files changed, 204 insertions(+), 42 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 0e95955b..582e465a 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -12,6 +12,9 @@ #import "RSSwizzle.h" +// Useful for the tests +static TSKPinValidationResult lastTrustKitValidationResult = -1; + typedef void (^AsyncCompletionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError); @@ -24,10 +27,20 @@ -(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChal @implementation TSKNSURLConnectionDelegateProxy + ++(TSKPinValidationResult)getLastTrustKitValidationResult +{ + return lastTrustKitValidationResult; +} + + + (void)swizzleNSURLConnectionConstructors { + static const void *swizzleOncekey = &swizzleOncekey; + // - initWithRequest:delegate: // We can use RSSwizzleModeAlways, NULL as the swizzling parameters because this should only be called from within a dispatch_once() + RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @selector(initWithRequest:delegate:), RSSWReturnType(NSURLConnection*), @@ -38,7 +51,8 @@ + (void)swizzleNSURLConnectionConstructors TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate); return connection; - }), RSSwizzleModeAlways, NULL); + }), RSSwizzleModeOncePerClass, swizzleOncekey); + // - initWithRequest:delegate:startImmediately: @@ -52,7 +66,7 @@ + (void)swizzleNSURLConnectionConstructors TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate, startImmediately); return connection; - }), RSSwizzleModeAlways, NULL); + }), RSSwizzleModeOncePerClass, swizzleOncekey); // Not hooking + connectionWithRequest:delegate: as it ends up calling initWithRequest:delegate: @@ -95,6 +109,7 @@ - (TSKNSURLConnectionDelegateProxy *)initWithDelegate:(id)delegate originalDelegate = delegate; } TSKLog(@"Proxy-ing NSURLConnectionDelegate: %@", NSStringFromClass([delegate class])); + lastTrustKitValidationResult = -1; return self; } @@ -168,6 +183,7 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio // Check the trust object against the pinning policy result = [TSKPinningValidator evaluateTrust:serverTrust forHostname:serverHostname]; + lastTrustKitValidationResult = result; if (result == TSKPinValidationResultSuccess) { // Success - don't do anything and forward the challenge to the original delegate @@ -218,5 +234,4 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio } - @end diff --git a/TrustKit/TrustKit+Private.h b/TrustKit/TrustKit+Private.h index e432574c..9c7e2d1e 100644 --- a/TrustKit/TrustKit+Private.h +++ b/TrustKit/TrustKit+Private.h @@ -26,7 +26,6 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus + (void) resetConfiguration; + (NSDictionary *) configuration; -+ (BOOL) wasTrustKitCalled; + (BOOL) wasTrustKitInitialized; @end diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 98575821..4269b41c 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -57,9 +57,6 @@ static char kTSKPinFailureReporterQueueLabel[] = "com.datatheorem.trustkit.reporterqueue"; static dispatch_queue_t _pinFailureReporterQueue = NULL; -// For tests -static BOOL _wasTrustKitCalled = NO; - // Default report URI - can be disabled with TSKDisableDefaultReportUri static NSString * const kTSKDefaultReportUri = @"https://trustkit-reports-server.appspot.com/log_report"; @@ -354,8 +351,6 @@ static void initializeTrustKit(NSDictionary *trustKitConfig) // NSURLConnection [TSKNSURLConnectionDelegateProxy swizzleNSURLConnectionConstructors]; } - - // Create our reporter for sending pin validation failures @try @@ -398,11 +393,6 @@ + (void) initializeWithConfiguration:(NSDictionary *)trustKitConfig # pragma mark Private / Test Methods -+ (BOOL) wasTrustKitCalled -{ - return _wasTrustKitCalled; -} - + (NSDictionary *) configuration { @@ -422,7 +412,6 @@ + (void) resetConfiguration resetSubjectPublicKeyInfoCache(); _trustKitGlobalConfiguration = nil; _isTrustKitInitialized = NO; - _wasTrustKitCalled = NO; _pinFailureReporter = nil; _pinFailureReporterQueue= NULL; dispatchOnceTrustKitInit = 0; diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index 23711e92..b6b008c0 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -8,12 +8,21 @@ #import #import "TrustKit+Private.h" +#import "TSKNSURLConnectionDelegateProxy.h" + +@interface TSKNSURLConnectionDelegateProxy(Private) ++(TSKPinValidationResult)getLastTrustKitValidationResult; +@end @interface TestNSURLConnectionDelegate : NSObject { XCTestExpectation *testExpectation; } + +@property NSError *lastError; +@property NSURLResponse *lastResponse; + - (instancetype)initWithExpectation:(XCTestExpectation *)expectation; - (void)connectionDidFinishLoading:(NSURLConnection *)connection; - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; @@ -39,13 +48,12 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection {} - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - NSLog(@"%@ - failed: %@", NSStringFromClass([self class]), error); + _lastError = error; [testExpectation fulfill]; } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { - NSLog(@"%@ - received %lu bytes", NSStringFromClass([self class]), (unsigned long)[data length]); } - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse @@ -55,13 +63,12 @@ - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheRespo - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - NSLog(@"%@ - success: %@", NSStringFromClass([self class]), [[response URL] host]); + _lastResponse = response; [testExpectation fulfill]; } - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse { - NSLog(@"%@ - redirect: %@", NSStringFromClass([self class]), [[request URL] host]); return request; } @@ -76,58 +83,211 @@ @implementation TSKNSURLConnectionTests - (void)setUp { [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. + [TrustKit resetConfiguration]; } - (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. [super tearDown]; } -- (void)testNSURLConnection { +// NSURLConnection is deprecated - disable Xcode warnings +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + +// Disable auto-swizzling and ensure TrustKit does not get called +/* +- (void)testSwizzleNetworkDelegatesDiabled +{ + NSDictionary *trustKitConfig = + @{ + kTSKSwizzleNetworkDelegates: @NO, + kTSKPinnedDomains : + @{ + @"www.reddit.com" : @{ + kTSKEnforcePinning : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; + TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + NSURLConnection *connection = [[NSURLConnection alloc] + initWithRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.yahoo.com/"]] + delegate:delegate]; + [connection start]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { + if (error) { + NSLog(@"Timeout Error: %@", error); + } + }]; + // The initial value for getLastTrustKitValidationResult is -1 when no pinning validation has been done yet + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult] < 0), @"TrustKit was called although swizzling was disabled"); +} +*/ + + +// Tests a secure connection to https://www.yahoo.com and forces validation to fail by providing a fake hash +- (void)testPinningValidationFailed +{ NSDictionary *trustKitConfig = @{ kTSKPinnedDomains : @{ @"www.yahoo.com" : @{ + kTSKEnforcePinning : @YES, kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key ]}}}; [TrustKit initializeWithConfiguration:trustKitConfig]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; + TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + // Use -initWithRequest:delegate: + NSURLConnection *connection = [[NSURLConnection alloc] + initWithRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.yahoo.com/"]] + delegate:delegate]; + [connection start]; + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) + { + if (error) + { + NSLog(@"Timeout Error: %@", error); + } + }]; + + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult] == TSKPinValidationResultFailed), @"TrustKit accepted an invalid certificate"); + XCTAssertNotNil(delegate.lastError, @"TrustKit did not trigger an error"); + XCTAssertNil(delegate.lastResponse, @"TrustKit returned a response although pin validation failed"); +} + + +// Tests a secure connection to https://www.yahoo.com and forces validation to fail by providing a fake hash, but do not enforce pinning +- (void)testPinningValidationFailedDoNotEnforcePinning +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.yahoo.com" : @{ + kTSKEnforcePinning : @NO, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; - // NSURLConnection is deprecated -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + // Use +connectionWithRequest:delegate: + NSURLConnection *connection = [NSURLConnection + connectionWithRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.yahoo.com/"]] + delegate:delegate]; + [connection start]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) + { + if (error) + { + NSLog(@"Timeout Error: %@", error); + } + }]; + + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult] == TSKPinValidationResultFailed), @"TrustKit accepted an invalid certificate"); + XCTAssertNotNil(delegate.lastError, @"TrustKit did not trigger an error"); + XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); + XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit did not return a response although pinning was not enforced"); +} + + +// Tests a secure connection to https://www.datatheorem.com by pinning only to the CA public key +- (void)testPinningValidationSucceeded +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; + TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + // Use -initWithRequest:delegate:startstartImmediately: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.reddit.com/normal"]] - delegate:delegate]; + [NSURL URLWithString:@"https://www.datatheorem.com/"]] + delegate:delegate + startImmediately:YES]; [connection start]; + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) + { + if (error) + { + NSLog(@"Timeout Error: %@", error); + } + }]; + + NSLog(@"lol %ld",(long)[TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult]); - // Run other methods that we swizzle to display a warning, to ensure they don't crash - XCTestExpectation *expectation2 = [self expectationWithDescription:@"Asynchronous request"]; + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult] == TSKPinValidationResultSuccess), @"TrustKit rejected a valid certificate"); + XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); + XCTAssertNotNil(delegate.lastResponse, @"TrustKit prevented a response from being returned"); + XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit prevented a response from being returned"); + +} + + +- (void)testNoDelegateWarnings +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.yahoo.com" : @{ + kTSKEnforcePinning : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + // Run other NSURLConnection methods that we swizzle to display a warning, to ensure they don't crash + XCTestExpectation *expectation = [self expectationWithDescription:@"Asynchronous request"]; [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL: [NSURL URLWithString:@"https://www.datatheorem.com/test"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { - [expectation2 fulfill]; + [expectation fulfill]; }]; [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL: [NSURL URLWithString:@"https://www.datatheorem.com/test"]] returningResponse:nil error:nil]; -#pragma GCC diagnostic pop - - + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { if (error) { NSLog(@"Timeout Error: %@", error); @@ -135,6 +295,5 @@ - (void)testNSURLConnection { }]; } - - +#pragma GCC diagnostic pop @end diff --git a/TrustKitTests/TSKPinValidationOnlineTests.m b/TrustKitTests/TSKPinValidationOnlineTests.m index df362aaf..8b1ea015 100644 --- a/TrustKitTests/TSKPinValidationOnlineTests.m +++ b/TrustKitTests/TSKPinValidationOnlineTests.m @@ -61,7 +61,7 @@ - (void)testConnectionValidatingCAPublicKey XCTAssertNil(error, @"Connection had an error: %@", error); XCTAssert(response.statusCode==200, @"Server did not respond with a 200 OK"); - XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); +// XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); } @@ -86,8 +86,8 @@ - (void)testConnectionUsingFakeHashInvalidatingAllCertificates NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.yahoo.com"]]; [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; - XCTAssert(error.code==-1202 && [error.domain isEqual:@"NSURLErrorDomain"], @"Invalid certificate error not fired"); - XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); +// XCTAssert(error.code==-1202 && [error.domain isEqual:@"NSURLErrorDomain"], @"Invalid certificate error not fired"); +// XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); } @@ -115,7 +115,7 @@ - (void)testConnectionUsingFakeHashInvalidatingAllCertificatesButNotEnforcingPin XCTAssertNil(error, @"Connection had an error: %@", error); XCTAssert(response.statusCode==200, @"Server did not respond with a 200 OK"); - XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); +// XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); } @@ -129,7 +129,7 @@ - (void)testConnectionWithoutPinningAnything XCTAssertNil(error, @"Connection had an error: %@", error); XCTAssert(response.statusCode==200, @"Server did not respond with a 200 OK"); - XCTAssert(![TrustKit wasTrustKitCalled], @"TrustKit was called"); +// XCTAssert(![TrustKit wasTrustKitCalled], @"TrustKit was called"); } #pragma clang diagnostic pop From c3ab69fefefc28215a4f5ffb3ead3e93ca8eac02 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 18:39:23 -0700 Subject: [PATCH 025/118] Simplify TSKPinningValidator return value and change API --- TrustKit/Pinning/TSKPinningValidator.h | 38 ++++--------------- TrustKit/Pinning/TSKPinningValidator.m | 37 ++++++++++++------ TrustKit/Pinning/ssl_pin_verifier.h | 32 ++++++++++++++++ TrustKit/Reporting/TSKPinFailureReport.h | 2 +- TrustKit/Reporting/TSKReporterDelegate.h | 2 +- .../TSKNSURLConnectionDelegateProxy.m | 18 ++++----- TrustKitTests/TSKNSURLConnectionTests.m | 10 ++--- 7 files changed, 80 insertions(+), 59 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.h b/TrustKit/Pinning/TSKPinningValidator.h index 64c93fd4..05ebe2e7 100644 --- a/TrustKit/Pinning/TSKPinningValidator.h +++ b/TrustKit/Pinning/TSKPinningValidator.h @@ -11,41 +11,17 @@ #import + + /** Possible return values when verifying a server's identity against the global SSL pinning policy using `TSKPinningValidator`. */ -typedef NS_ENUM(NSInteger, TSKPinValidationResult) +typedef NS_ENUM(NSInteger, TSKTrustDecision) { -/** - The server trust was succesfully evaluated and contained at least one of the configured pins. -*/ - TSKPinValidationResultSuccess, - -/** - The server trust was succesfully evaluated but did not contain any of the configured pins. -*/ - TSKPinValidationResultFailed, - -/** - The server trust's evaluation failed: the server's certificate chain is not trusted. -*/ - TSKPinValidationResultFailedCertificateChainNotTrusted, - -/** - The server trust could not be evaluated due to invalid parameters. -*/ - TSKPinValidationResultErrorInvalidParameters, - -/** - The supplied hostname does not have a pinning policy configured; no validation was performed. -*/ - TSKPinValidationResultDomainNotPinned, - -/** - The server trust was succesfully evaluated but did not contain any of the configured pins. However, the certificate chain terminates at a user-defined trust anchor (ie. a custom/private CA that was manually added to OS X's trust store). Only available on OS X. -*/ - TSKPinValidationResultFailedUserDefinedTrustAnchor NS_AVAILABLE_MAC(10_9), + TSKTrustDecisionShouldAllowConnection, + TSKTrustDecisionShouldBlockConnection, + TSKTrustDecisionDomainNotPinned, }; @@ -81,6 +57,6 @@ typedef NS_ENUM(NSInteger, TSKPinValidationResult) @exception NSException Thrown when TrustKit has not been initialized with a pinning policy. */ -+ (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(NSString *)serverHostname; ++ (TSKTrustDecision) evaluateTrust:(SecTrustRef)serverTrust forHostname:(NSString *)serverHostname; @end diff --git a/TrustKit/Pinning/TSKPinningValidator.m b/TrustKit/Pinning/TSKPinningValidator.m index aa7b2501..dcf2187f 100644 --- a/TrustKit/Pinning/TSKPinningValidator.m +++ b/TrustKit/Pinning/TSKPinningValidator.m @@ -17,7 +17,7 @@ @implementation TSKPinningValidator -+ (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(NSString *)serverHostname ++ (TSKTrustDecision) evaluateTrust:(SecTrustRef)serverTrust forHostname:(NSString *)serverHostname { if ([TrustKit wasTrustKitInitialized] == NO) { @@ -28,10 +28,10 @@ + (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(N if ((serverTrust == NULL) || (serverHostname == nil)) { TSKLog(@"Pin validation error - invalid parameters for %@", serverHostname); - return TSKPinValidationResultErrorInvalidParameters; + return TSKTrustDecisionShouldBlockConnection; } - TSKPinValidationResult validationResult = TSKPinValidationResultFailed; + TSKTrustDecision finalTrustDecision = TSKTrustDecisionShouldBlockConnection; NSDictionary *trustKitConfig = [TrustKit configuration]; // Retrieve the pinning configuration for this specific domain, if there is one @@ -39,7 +39,7 @@ + (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(N if (domainConfigKey == nil) { // The domain is not pinned: nothing to validate - validationResult = TSKPinValidationResultDomainNotPinned; + finalTrustDecision = TSKTrustDecisionDomainNotPinned; } else { @@ -47,11 +47,12 @@ + (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(N CFRetain(serverTrust); NSDictionary *domainConfig = trustKitConfig[kTSKPinnedDomains][domainConfigKey]; - validationResult = verifyPublicKeyPin(serverTrust, serverHostname, domainConfig[kTSKPublicKeyAlgorithms], domainConfig[kTSKPublicKeyHashes]); + TSKPinValidationResult validationResult = verifyPublicKeyPin(serverTrust, serverHostname, domainConfig[kTSKPublicKeyAlgorithms], domainConfig[kTSKPublicKeyHashes]); if (validationResult == TSKPinValidationResultSuccess) { // Pin validation was successful TSKLog(@"Pin validation succeeded for %@", serverHostname); + finalTrustDecision = TSKTrustDecisionShouldAllowConnection; CFRelease(serverTrust); } else @@ -64,21 +65,33 @@ + (TSKPinValidationResult) evaluateTrust:(SecTrustRef)serverTrust forHostname:(N { // OS-X only: user-defined trust anchors can be whitelisted (for corporate proxies, etc.) so don't send reports TSKLog(@"Ignoring pinning failure due to user-defined trust anchor for %@", serverHostname); + finalTrustDecision = TSKTrustDecisionShouldAllowConnection; CFRelease(serverTrust); } else #endif { - // Send a pin failure report - sendPinFailureReport_async(validationResult, serverTrust, serverHostname, domainConfigKey, domainConfig, ^void (void) - { - // Release the trust once the report has been sent - CFRelease(serverTrust); - }); + // Send a pin failure report + sendPinFailureReport_async(validationResult, serverTrust, serverHostname, domainConfigKey, domainConfig, ^void (void) + { + // Release the trust once the report has been sent + CFRelease(serverTrust); + }); + + // Is pinning enforced? + if ([domainConfig[kTSKEnforcePinning] boolValue] == YES) + { + // Yes - Block the connection + finalTrustDecision = TSKTrustDecisionShouldBlockConnection; + } + else + { + finalTrustDecision = TSKTrustDecisionShouldAllowConnection; + } } } } - return validationResult; + return finalTrustDecision; } @end \ No newline at end of file diff --git a/TrustKit/Pinning/ssl_pin_verifier.h b/TrustKit/Pinning/ssl_pin_verifier.h index 9d88cf2f..14164737 100644 --- a/TrustKit/Pinning/ssl_pin_verifier.h +++ b/TrustKit/Pinning/ssl_pin_verifier.h @@ -17,6 +17,38 @@ #import "TSKPinningValidator.h" +/** + Possible return values when verifying a server's identity. + */ +typedef NS_ENUM(NSInteger, TSKPinValidationResult) +{ + /** + The server trust was succesfully evaluated and contained at least one of the configured pins. + */ + TSKPinValidationResultSuccess, + + /** + The server trust was succesfully evaluated but did not contain any of the configured pins. + */ + TSKPinValidationResultFailed, + + /** + The server trust's evaluation failed: the server's certificate chain is not trusted. + */ + TSKPinValidationResultFailedCertificateChainNotTrusted, + + /** + The server trust could not be evaluated due to invalid parameters. + */ + TSKPinValidationResultErrorInvalidParameters, + + /** + The server trust was succesfully evaluated but did not contain any of the configured pins. However, the certificate chain terminates at a user-defined trust anchor (ie. a custom/private CA that was manually added to OS X's trust store). Only available on OS X. + */ + TSKPinValidationResultFailedUserDefinedTrustAnchor NS_AVAILABLE_MAC(10_9), +}; + + // Figure out if a specific domain is pinned and retrieve this domain's configuration key; returns nil if no configuration was found NSString *getPinningConfigurationKeyForDomain(NSString *hostname, NSDictionary *trustKitConfiguration); diff --git a/TrustKit/Reporting/TSKPinFailureReport.h b/TrustKit/Reporting/TSKPinFailureReport.h index 88d43496..1a7a7971 100644 --- a/TrustKit/Reporting/TSKPinFailureReport.h +++ b/TrustKit/Reporting/TSKPinFailureReport.h @@ -10,7 +10,7 @@ */ #import -#import "TSKPinningValidator.h" +#import "ssl_pin_verifier.h" @interface TSKPinFailureReport : NSObject diff --git a/TrustKit/Reporting/TSKReporterDelegate.h b/TrustKit/Reporting/TSKReporterDelegate.h index 1b4d1b57..17136929 100644 --- a/TrustKit/Reporting/TSKReporterDelegate.h +++ b/TrustKit/Reporting/TSKReporterDelegate.h @@ -10,7 +10,7 @@ */ #import -#import "TSKPinningValidator.h" +#import "ssl_pin_verifier.h" @protocol TSKReporterDelegate diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 582e465a..6a8cd2eb 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -13,7 +13,7 @@ // Useful for the tests -static TSKPinValidationResult lastTrustKitValidationResult = -1; +static TSKTrustDecision lastTrustDecision = -1; typedef void (^AsyncCompletionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError); @@ -28,9 +28,9 @@ -(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChal @implementation TSKNSURLConnectionDelegateProxy -+(TSKPinValidationResult)getLastTrustKitValidationResult ++(TSKTrustDecision)getLastTrustKitTrustDecision { - return lastTrustKitValidationResult; + return lastTrustDecision; } @@ -109,7 +109,7 @@ - (TSKNSURLConnectionDelegateProxy *)initWithDelegate:(id)delegate originalDelegate = delegate; } TSKLog(@"Proxy-ing NSURLConnectionDelegate: %@", NSStringFromClass([delegate class])); - lastTrustKitValidationResult = -1; + lastTrustDecision = -1; return self; } @@ -173,23 +173,23 @@ -(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChal - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { BOOL wasChallengeHandled = NO; - TSKPinValidationResult result = TSKPinValidationResultFailed; // For SSL pinning we only care about server authentication if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + TSKTrustDecision trustDecision = TSKTrustDecisionShouldBlockConnection; SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; NSString *serverHostname = challenge.protectionSpace.host; // Check the trust object against the pinning policy - result = [TSKPinningValidator evaluateTrust:serverTrust forHostname:serverHostname]; - lastTrustKitValidationResult = result; - if (result == TSKPinValidationResultSuccess) + trustDecision = [TSKPinningValidator evaluateTrust:serverTrust forHostname:serverHostname]; + lastTrustDecision = trustDecision; + if (trustDecision == TSKTrustDecisionShouldAllowConnection) { // Success - don't do anything and forward the challenge to the original delegate wasChallengeHandled = NO; } - else if (result == TSKPinValidationResultDomainNotPinned) + else if (trustDecision == TSKTrustDecisionDomainNotPinned) { if ([self forwardToOriginalDelegateAuthenticationChallenge:challenge forConnection:connection]) { diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index b6b008c0..ebcab2ba 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -11,7 +11,7 @@ #import "TSKNSURLConnectionDelegateProxy.h" @interface TSKNSURLConnectionDelegateProxy(Private) -+(TSKPinValidationResult)getLastTrustKitValidationResult; ++(TSKPinValidationResult)getLastTrustKitTrustDecision; @end @@ -168,7 +168,7 @@ - (void)testPinningValidationFailed } }]; - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult] == TSKPinValidationResultFailed), @"TrustKit accepted an invalid certificate"); + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision] == TSKTrustDecisionShouldBlockConnection), @"TrustKit accepted an invalid certificate"); XCTAssertNotNil(delegate.lastError, @"TrustKit did not trigger an error"); XCTAssertNil(delegate.lastResponse, @"TrustKit returned a response although pin validation failed"); } @@ -208,7 +208,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning } }]; - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult] == TSKPinValidationResultFailed), @"TrustKit accepted an invalid certificate"); + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); XCTAssertNotNil(delegate.lastError, @"TrustKit did not trigger an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit did not return a response although pinning was not enforced"); @@ -249,9 +249,9 @@ - (void)testPinningValidationSucceeded } }]; - NSLog(@"lol %ld",(long)[TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult]); + NSLog(@"lol %ld",(long)[TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision]); - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitValidationResult] == TSKPinValidationResultSuccess), @"TrustKit rejected a valid certificate"); + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit rejected a valid certificate"); XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit prevented a response from being returned"); XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit prevented a response from being returned"); From 0311640464fea284053608ed7c6186b9d0df37e1 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 18:41:38 -0700 Subject: [PATCH 026/118] Successful NSURLConnection tests --- TrustKitTests/TSKNSURLConnectionTests.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index ebcab2ba..63d7873e 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -96,6 +96,7 @@ - (void)tearDown { // Disable auto-swizzling and ensure TrustKit does not get called +// Disabling this test for now as there are no ways to reset the swizzling /* - (void)testSwizzleNetworkDelegatesDiabled { @@ -209,7 +210,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning }]; XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); - XCTAssertNotNil(delegate.lastError, @"TrustKit did not trigger an error"); + XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit did not return a response although pinning was not enforced"); } From c9efc040f3acb1d6982899218d74c729b19831ca Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 18:43:22 -0700 Subject: [PATCH 027/118] Remove comment --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 6a8cd2eb..dedb13f4 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -19,7 +19,6 @@ typedef void (^AsyncCompletionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError); - @interface TSKNSURLConnectionDelegateProxy(Private) -(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge forConnection:(NSURLConnection *)connection; @end @@ -39,8 +38,6 @@ + (void)swizzleNSURLConnectionConstructors static const void *swizzleOncekey = &swizzleOncekey; // - initWithRequest:delegate: - // We can use RSSwizzleModeAlways, NULL as the swizzling parameters because this should only be called from within a dispatch_once() - RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @selector(initWithRequest:delegate:), RSSWReturnType(NSURLConnection*), From 3788106086819c5eeb9527c8f49f1db9b639532f Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 19:03:52 -0700 Subject: [PATCH 028/118] Sinplify name --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 2 +- TrustKitTests/TSKNSURLConnectionTests.m | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index dedb13f4..99f2e82f 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -27,7 +27,7 @@ -(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChal @implementation TSKNSURLConnectionDelegateProxy -+(TSKTrustDecision)getLastTrustKitTrustDecision ++(TSKTrustDecision)getLastTrustDecision { return lastTrustDecision; } diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index 63d7873e..068381b2 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -11,7 +11,7 @@ #import "TSKNSURLConnectionDelegateProxy.h" @interface TSKNSURLConnectionDelegateProxy(Private) -+(TSKPinValidationResult)getLastTrustKitTrustDecision; ++(TSKPinValidationResult)getLastTrustDecision; @end @@ -169,7 +169,7 @@ - (void)testPinningValidationFailed } }]; - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision] == TSKTrustDecisionShouldBlockConnection), @"TrustKit accepted an invalid certificate"); + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldBlockConnection), @"TrustKit accepted an invalid certificate"); XCTAssertNotNil(delegate.lastError, @"TrustKit did not trigger an error"); XCTAssertNil(delegate.lastResponse, @"TrustKit returned a response although pin validation failed"); } @@ -209,7 +209,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning } }]; - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit did not return a response although pinning was not enforced"); @@ -250,9 +250,9 @@ - (void)testPinningValidationSucceeded } }]; - NSLog(@"lol %ld",(long)[TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision]); + NSLog(@"lol %ld",(long)[TSKNSURLConnectionDelegateProxy getLastTrustDecision]); - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustKitTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit rejected a valid certificate"); + XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit rejected a valid certificate"); XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit prevented a response from being returned"); XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit prevented a response from being returned"); From 0ea4c0f90b9dc377c3a4280ff3539be54ce15880 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 19:37:54 -0700 Subject: [PATCH 029/118] Minor cleanup --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h | 4 ++-- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h index 3b3c45cc..df1fb801 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h @@ -9,7 +9,7 @@ #import -@interface TSKNSURLConnectionDelegateProxy : NSObject +@interface TSKNSURLConnectionDelegateProxy : NSObject { id originalDelegate; // The NSURLConnectionDelegate we're going to proxy } @@ -17,7 +17,7 @@ // Initalize our hooks + (void)swizzleNSURLConnectionConstructors; -- (TSKNSURLConnectionDelegateProxy *)initWithDelegate:(id)delegate; +- (instancetype)initWithDelegate:(id)delegate; // Mirror the original delegate's list of implemented methods - (BOOL)respondsToSelector:(SEL)aSelector ; diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 99f2e82f..913ad32a 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -98,7 +98,7 @@ + (void)swizzleNSURLConnectionConstructors } -- (TSKNSURLConnectionDelegateProxy *)initWithDelegate:(id)delegate +- (instancetype)initWithDelegate:(id)delegate { self = [super init]; if (self) From 676d6d7bb74f254b29c7da97f8977e218b3cf477 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 21:41:23 -0700 Subject: [PATCH 030/118] Cleanup --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 913ad32a..ab4ef65e 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -41,7 +41,7 @@ + (void)swizzleNSURLConnectionConstructors RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @selector(initWithRequest:delegate:), RSSWReturnType(NSURLConnection*), - RSSWArguments(NSURLRequest *request, id delegate), + RSSWArguments(NSURLRequest *request, id delegate), RSSWReplacement( { // Replace the delegate with our own so we can intercept and handle authentication challenges @@ -56,7 +56,7 @@ + (void)swizzleNSURLConnectionConstructors RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @selector(initWithRequest:delegate:startImmediately:), RSSWReturnType(NSURLConnection*), - RSSWArguments(NSURLRequest *request, id delegate, BOOL startImmediately), + RSSWArguments(NSURLRequest *request, id delegate, BOOL startImmediately), RSSWReplacement( { // Replace the delegate with our own so we can intercept and handle authentication challenges @@ -118,10 +118,6 @@ - (BOOL)respondsToSelector:(SEL)aSelector // The delegate proxy should always receive authentication challenges return YES; } - if (aSelector == @selector(connection:didReceiveAuthenticationChallenge:)) - { - return NO; - } else { // The delegate proxy should mirror the original delegate's methods so that it doesn't change the app flow From 290b6cc15e57855a19b9ace57f38efb92a750384 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 22:32:48 -0700 Subject: [PATCH 031/118] minor tweaks --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 1 - TrustKitTests/TSKNSURLConnectionTests.m | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index ab4ef65e..869f7780 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -122,7 +122,6 @@ - (BOOL)respondsToSelector:(SEL)aSelector { // The delegate proxy should mirror the original delegate's methods so that it doesn't change the app flow return [originalDelegate respondsToSelector:aSelector]; - // return NO; } } diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index 068381b2..26b8b675 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -10,6 +10,7 @@ #import "TrustKit+Private.h" #import "TSKNSURLConnectionDelegateProxy.h" + @interface TSKNSURLConnectionDelegateProxy(Private) +(TSKPinValidationResult)getLastTrustDecision; @end From 3caad729c8ea40f383fe2d74dda0d88e5b3fd92b Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 11 Oct 2015 23:29:47 -0700 Subject: [PATCH 032/118] Add tentative NSURLSession swizzling code and test --- TrustKit.xcodeproj/project.pbxproj | 20 ++ .../Swizzling/TSKNSURLSessionDelegateProxy.h | 38 +++ .../Swizzling/TSKNSURLSessionDelegateProxy.m | 236 ++++++++++++++++++ TrustKit/TrustKit.m | 4 + TrustKitTests/TSKNSURLConnectionTests.m | 2 - TrustKitTests/TSKNSURLSessionTests.m | 125 ++++++++++ 6 files changed, 423 insertions(+), 2 deletions(-) create mode 100644 TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.h create mode 100644 TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m create mode 100644 TrustKitTests/TSKNSURLSessionTests.m diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 62320440..643bb43e 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -100,6 +100,13 @@ 8CD5F7431BCB06F4005801D8 /* RSSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7441BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); }; }; 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7491BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; + 8CD5F74A1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; + 8CD5F74B1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F74C1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F74D1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7571BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7581BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */; settings = {ASSET_TAGS = (); }; }; 8CE9191E1AEA073C002B29AE /* public_key_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE9191C1AEA073C002B29AE /* public_key_utils.h */; }; 8CE9191F1AEA073C002B29AE /* public_key_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE9191D1AEA073C002B29AE /* public_key_utils.m */; }; 8CE919221AEA077F002B29AE /* ssl_pin_verifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */; }; @@ -188,6 +195,9 @@ 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKNSURLConnectionTests.m; sourceTree = ""; }; 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSSwizzle.h; path = Dependencies/RSSwizzle/RSSwizzle.h; sourceTree = ""; }; 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RSSwizzle.m; path = Dependencies/RSSwizzle/RSSwizzle.m; sourceTree = ""; }; + 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKNSURLSessionDelegateProxy.h; path = Swizzling/TSKNSURLSessionDelegateProxy.h; sourceTree = ""; }; + 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKNSURLSessionDelegateProxy.m; path = Swizzling/TSKNSURLSessionDelegateProxy.m; sourceTree = ""; }; + 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKNSURLSessionTests.m; sourceTree = ""; }; 8CE9191C1AEA073C002B29AE /* public_key_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = public_key_utils.h; path = Pinning/public_key_utils.h; sourceTree = ""; }; 8CE9191D1AEA073C002B29AE /* public_key_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = public_key_utils.m; path = Pinning/public_key_utils.m; sourceTree = ""; }; 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ssl_pin_verifier.m; path = Pinning/ssl_pin_verifier.m; sourceTree = ""; }; @@ -315,6 +325,7 @@ 070868B31ADFF68200E5AFDC /* Certificates */, 0710306B1AA88A510028092C /* TSKPinValidationOnlineTests.m */, 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */, + 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */, 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */, 8C8480571A896EE30017C155 /* Supporting Files */, 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */, @@ -368,6 +379,8 @@ children = ( 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */, 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */, + 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */, + 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */, ); name = Swizzling; sourceTree = ""; @@ -459,6 +472,7 @@ buildActionMask = 2147483647; files = ( 8CE9192D1AEA0F7E002B29AE /* domain_registry.h in Headers */, + 8CD5F7491BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */, 8CE9191E1AEA073C002B29AE /* public_key_utils.h in Headers */, 6B2B06AD1B05154A00FC749E /* TSKBackgroundReporter.h in Headers */, 8CD5F7311BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */, @@ -480,6 +494,7 @@ buildActionMask = 2147483647; files = ( 8CA6CC171BAE2B6600BDA419 /* TSKSimpleReporter.h in Headers */, + 8CD5F74A1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */, 8CA6CC1B1BAE2B6600BDA419 /* TSKPinFailureReport.h in Headers */, 8CA6CC141BAE2B6600BDA419 /* TSKReportsRateLimiter.h in Headers */, 8CD5F7321BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */, @@ -692,6 +707,7 @@ 8CE919221AEA077F002B29AE /* ssl_pin_verifier.m in Sources */, 8C9EBE031B619BBE00CA7EE0 /* TSKReportsRateLimiter.m in Sources */, 6B2B06AF1B05157400FC749E /* TSKBackgroundReporter.m in Sources */, + 8CD5F74B1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */, 6B032D3A1AF1794D00EAFA69 /* TSKSimpleReporter.m in Sources */, 8CE9191F1AEA073C002B29AE /* public_key_utils.m in Sources */, 8CE919351AEA0F8B002B29AE /* fishhook.c in Sources */, @@ -714,6 +730,7 @@ 075AA1091AC985FD00178223 /* TSKPinValidationOfflineTests.m in Sources */, 8CC78B251B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m in Sources */, 6B032D401AF1AEC200EAFA69 /* TSKReporterTests.m in Sources */, + 8CD5F7571BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */, 8CC78B201B1B586F00523A25 /* TSKCertificateUtils.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -730,6 +747,7 @@ 8C8716B81B23AA0D00267E1D /* TrustKit.m in Sources */, 8C8716B21B23A9F400267E1D /* TSKBackgroundReporter.m in Sources */, 0E64A7601B867BA000CA164A /* TSKReportsRateLimiter.m in Sources */, + 8CD5F74C1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */, 8CD5F7341BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, 8C8716B11B23A9F000267E1D /* TSKSimpleReporter.m in Sources */, 8C8716B61B23AA0800267E1D /* ssl_pin_verifier.m in Sources */, @@ -743,6 +761,7 @@ 8CA6CC201BAE2B6A00BDA419 /* public_key_utils.m in Sources */, 8CA6CC1A1BAE2B6600BDA419 /* TSKBackgroundReporter.m in Sources */, 8CA6CC1C1BAE2B6600BDA419 /* TSKPinFailureReport.m in Sources */, + 8CD5F74D1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */, 8CA6CC241BAE2B6A00BDA419 /* TSKPinningValidator.m in Sources */, 8CA6CC1E1BAE2B6600BDA419 /* reporting_utils.m in Sources */, 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */, @@ -765,6 +784,7 @@ 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */, 8CA6CC3C1BAE2C8100BDA419 /* TSKPublicKeyAlgorithmTests.m in Sources */, 8CA6CC3B1BAE2C7E00BDA419 /* TSKPinConfigurationTests.m in Sources */, + 8CD5F7581BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */, 8CA6CC3D1BAE2C8500BDA419 /* TSKCertificateUtils.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.h b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.h new file mode 100644 index 00000000..dd973755 --- /dev/null +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.h @@ -0,0 +1,38 @@ +// +// TSKNSURLSessionDelegateProxy.h +// TrustKit +// +// Created by Alban Diquet on 10/11/15. +// Copyright © 2015 TrustKit. All rights reserved. +// + +#import + + +@interface TSKNSURLSessionDelegateProxy : NSObject +{ + id originalDelegate; // The NSURLSessionDelegate we're going to proxy +} + ++ (void)swizzleNSURLSessionConstructors; + +- (_Nullable instancetype)initWithDelegate:(_Nonnull id)delegate; + +// Mirror the original delegate's list of implemented methods +- (BOOL)respondsToSelector:(_Nonnull SEL)aSelector; + +// Forward messages to the original delegate if the proxy doesn't implement the method +- (_Nonnull id)forwardingTargetForSelector:(_Nonnull SEL)sel; + +- (void)URLSession:(NSURLSession * _Nonnull)session +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler; + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler; + +@end diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m new file mode 100644 index 00000000..10c6ab5b --- /dev/null +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -0,0 +1,236 @@ +// +// TSKNSURLSessionDelegateProxy.m +// TrustKit +// +// Created by Alban Diquet on 10/11/15. +// Copyright © 2015 TrustKit. All rights reserved. +// + +#import "TSKNSURLSessionDelegateProxy.h" +#import "RSSwizzle.h" +#import "TrustKit+Private.h" + + +// Useful for the tests +static TSKTrustDecision lastTrustDecision = -1; + + +@implementation TSKNSURLSessionDelegateProxy + + ++(TSKTrustDecision)getLastTrustDecision +{ + return lastTrustDecision; +} + + ++ (void)swizzleNSURLSessionConstructors +{ + static const void *swizzleOncekey = &swizzleOncekey; + + // Figure out NSURLSession's "real" class + NSString *NSURLSessionClass; + if (NSClassFromString(@"NSURLSession") != nil) + { + // iOS 8+ + NSURLSessionClass = @"NSURLSession"; + } + else if (NSClassFromString(@"NSURLSession") != nil) + { + // Pre iOS 8, for some reason hooking NSURLSession doesn't work. We need to use the real/private class __NSCFURLSession + NSURLSessionClass = @"__NSCFURLSession"; + } + else + { + TSKLog(@"ERROR: Could not find NSURLSession's class"); + return; + } + + // + sessionWithConfiguration:delegate:delegateQueue: + RSSwizzleClassMethod(NSClassFromString(NSURLSessionClass), + @selector(sessionWithConfiguration:delegate:delegateQueue:), + RSSWReturnType(NSURLSession *), + RSSWArguments(NSURLSessionConfiguration * _Nonnull configuration, id _Nullable delegate, NSOperationQueue * _Nullable queue), + RSSWReplacement( + { + // Replace the delegate with our own so we can intercept and handle authentication challenges + TSKNSURLSessionDelegateProxy *swizzledDelegate = [[TSKNSURLSessionDelegateProxy alloc]initWithDelegate:delegate]; + NSURLSession *session = RSSWCallOriginal(configuration, swizzledDelegate, queue); + return session; + })); + + // TODO: Add warnings for methods we can't swizzle +} + + + +- (instancetype)initWithDelegate:(id)delegate +{ + self = [super init]; + if (self) + { + originalDelegate = delegate; + } + TSKLog(@"Proxy-ing NSURLSessionDelegate: %@", NSStringFromClass([delegate class])); + lastTrustDecision = -1; + return self; +} + + +- (BOOL)respondsToSelector:(SEL)aSelector +{ + if (aSelector == @selector(URLSession:task:didReceiveChallenge:completionHandler:)) + { + // For the task-level handler, mirror the delegate + return [originalDelegate respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)]; + } + else if (aSelector == @selector(URLSession:didReceiveChallenge:completionHandler:)) + { + if ([originalDelegate respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)] == NO) + { + // If the task-level handler is not implemented in the delegate, we need to implement the session-level handler + // regardless of what the delegate implements, to ensure we get to handle auth challenges + return YES; + } + else + { + return [originalDelegate respondsToSelector:@selector(URLSession:didReceiveChallenge:completionHandler:)]; + } + } + else + { + // The delegate proxy should mirror the original delegate's methods so that it doesn't change the app flow + return [originalDelegate respondsToSelector:aSelector]; + } +} + + +- (id)forwardingTargetForSelector:(SEL)sel +{ + // Forward messages to the original delegate if the proxy doesn't implement the method + return originalDelegate; +} + + +-(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^ _Nonnull) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler + forSession:(NSURLSession * _Nonnull)session +{ + BOOL wasChallengeHandled = NO; + + // Can the original delegate handle this challenge ? + if ([originalDelegate respondsToSelector:@selector(URLSession:didReceiveChallenge:completionHandler:)]) + { + // Yes - forward the challenge to the original delegate + wasChallengeHandled = YES; + [originalDelegate URLSession:session didReceiveChallenge:challenge completionHandler:completionHandler]; + } + return wasChallengeHandled; +} + + +- (void)URLSession:(NSURLSession * _Nonnull)session +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler +{ + BOOL wasChallengeHandled = NO; + + // For SSL pinning we only care about server authentication + if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) + { + TSKTrustDecision trustDecision = TSKTrustDecisionShouldBlockConnection; + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + NSString *serverHostname = challenge.protectionSpace.host; + + // Check the trust object against the pinning policy + trustDecision = [TSKPinningValidator evaluateTrust:serverTrust forHostname:serverHostname]; + lastTrustDecision = trustDecision; + if (trustDecision == TSKTrustDecisionShouldAllowConnection) + { + // Success - don't do anything and forward the challenge to the original delegate + wasChallengeHandled = NO; + } + else if (trustDecision == TSKTrustDecisionDomainNotPinned) + { + if ([self forwardToOriginalDelegateAuthenticationChallenge:challenge completionHandler:completionHandler forSession:session]) + { + // The original delegate handled the challenge and performed SSL validation itself + wasChallengeHandled = YES; + } + else + { + // The original delegate does not have authentication handlers for this challenge + // We need to do the default validation ourselves to avoid disabling SSL validation for all non pinned domains + TSKLog(@"Performing default certificate validation for %@", serverHostname); + SecTrustResultType trustResult = 0; + SecTrustEvaluate(serverTrust, &trustResult); + if ((trustResult != kSecTrustResultUnspecified) && (trustResult != kSecTrustResultProceed)) + { + // Default SSL validation failed - block the connection + CFDictionaryRef evaluationDetails = SecTrustCopyResult(serverTrust); + TSKLog(@"Error: default SSL validation failed: %@", evaluationDetails); + CFRelease(evaluationDetails); + wasChallengeHandled = YES; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL); + } + } + } + else + { + // Pinning validation failed - block the connection + wasChallengeHandled = YES; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL); + } + } + + // Forward all challenges (including client auth challenges) to the original delegate + if (wasChallengeHandled == NO) + { + if ([self forwardToOriginalDelegateAuthenticationChallenge:challenge completionHandler:completionHandler forSession:session] == NO) + { + // The original delegate could not handle the challenge; use the default handler + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, NULL); + } + } +} + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler +{ + BOOL wasChallengeHandled = NO; + + // For SSL pinning we only care about server authentication + if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) + { + TSKTrustDecision trustDecision = TSKTrustDecisionShouldBlockConnection; + + // Check the trust object against the pinning policy + trustDecision = [TSKPinningValidator evaluateTrust:challenge.protectionSpace.serverTrust + forHostname:challenge.protectionSpace.host]; + lastTrustDecision = trustDecision; + if ((trustDecision == TSKTrustDecisionShouldAllowConnection) || (trustDecision == TSKTrustDecisionDomainNotPinned)) + { + // Don't do anything and forward the challenge to the original delegate + wasChallengeHandled = NO; + } + else + { + // Pinning validation failed - block the connection + wasChallengeHandled = YES; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL); + } + } + + // Forward all challenges (including client auth challenges) to the original delegate + if (wasChallengeHandled == NO) + { + // If we're here it means the delegate implement the handler method so we can call it directly + [originalDelegate URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler]; + } +} + +@end diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 4269b41c..1b72e9e3 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -18,6 +18,7 @@ #import "TSKBackgroundReporter.h" #import "TSKSimpleReporter.h" #import "TSKNSURLConnectionDelegateProxy.h" +#import "TSKNSURLSessionDelegateProxy.h" #pragma mark Configuration Constants @@ -350,6 +351,9 @@ static void initializeTrustKit(NSDictionary *trustKitConfig) { // NSURLConnection [TSKNSURLConnectionDelegateProxy swizzleNSURLConnectionConstructors]; + + // NSURLSession + [TSKNSURLSessionDelegateProxy swizzleNSURLSessionConstructors]; } // Create our reporter for sending pin validation failures diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index 26b8b675..68b3a782 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -251,8 +251,6 @@ - (void)testPinningValidationSucceeded } }]; - NSLog(@"lol %ld",(long)[TSKNSURLConnectionDelegateProxy getLastTrustDecision]); - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit rejected a valid certificate"); XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit prevented a response from being returned"); diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m new file mode 100644 index 00000000..357b1e6e --- /dev/null +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -0,0 +1,125 @@ +// +// TSKNSURLSessionTests.m +// TrustKit +// +// Created by Alban Diquet on 10/11/15. +// Copyright © 2015 TrustKit. All rights reserved. +// + +#import +#import "TrustKit+Private.h" +#import "TSKNSURLSessionDelegateProxy.h" + + +@interface TSKNSURLSessionDelegateProxy(Private) ++(TSKPinValidationResult)getLastTrustDecision; +@end + + +@interface TestNSURLSessionTaskDelegate : NSObject +{ + XCTestExpectation *testExpectation; +} +@property NSError *lastError; +@property NSURLResponse *lastResponse; + + +- (instancetype)initWithExpectation:(XCTestExpectation *)expectation; + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didCompleteWithError:(NSError * _Nullable)error; + +- (void)URLSession:(NSURLSession * _Nonnull)session + dataTask:(NSURLSessionDataTask * _Nonnull)dataTask +didReceiveResponse:(NSURLResponse * _Nonnull)response + completionHandler:(void (^ _Nonnull)(NSURLSessionResponseDisposition disposition))completionHandler; + +@end + + +@implementation TestNSURLSessionTaskDelegate + +- (instancetype)initWithExpectation:(XCTestExpectation *)expectation +{ + self = [super init]; + if (self) + { + testExpectation = expectation; + } + return self; +} + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didCompleteWithError:(NSError * _Nullable)error +{ + _lastError = error; + [testExpectation fulfill]; +} + +- (void)URLSession:(NSURLSession * _Nonnull)session + dataTask:(NSURLSessionDataTask * _Nonnull)dataTask +didReceiveResponse:(NSURLResponse * _Nonnull)response + completionHandler:(void (^ _Nonnull)(NSURLSessionResponseDisposition disposition))completionHandler +{ + _lastResponse = response; + [testExpectation fulfill]; +} + +@end + + +@interface TSKNSURLSessionTests : XCTestCase + +@end + +@implementation TSKNSURLSessionTests + +- (void)setUp { + [super setUp]; + [TrustKit resetConfiguration]; +} + +- (void)tearDown { + [super tearDown]; +} + +- (void)testExample { + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSession"]; + TestNSURLSessionTaskDelegate *delegate = [[TestNSURLSessionTaskDelegate alloc] initWithExpectation:expectation]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:delegate + delegateQueue:nil]; + + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + [task resume]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { + if (error) { + NSLog(@"Timeout Error: %@", error); + } + }]; + + XCTAssert(([TSKNSURLSessionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit rejected a valid certificate"); + XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); + XCTAssertNotNil(delegate.lastResponse, @"TrustKit prevented a response from being returned"); + XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit prevented a response from being returned"); +} + + +@end From 73229a687819b9f9351c44fda2898b1b885ded81 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 08:38:46 -0700 Subject: [PATCH 033/118] Remove obsolete online tests --- TrustKit.xcodeproj/project.pbxproj | 6 - TrustKitTests/TSKPinValidationOnlineTests.m | 137 -------------------- 2 files changed, 143 deletions(-) delete mode 100644 TrustKitTests/TSKPinValidationOnlineTests.m diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 643bb43e..17d2d5d2 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 070868B71ADFFADF00E5AFDC /* GoodIntermediateCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868B11ADFF67200E5AFDC /* GoodIntermediateCA.der */; }; 070868B81ADFFADF00E5AFDC /* www.good.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868B21ADFF67200E5AFDC /* www.good.com.der */; }; 070868BB1AE1672D00E5AFDC /* www.good.com.selfsigned.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868BA1AE1672D00E5AFDC /* www.good.com.selfsigned.der */; }; - 0710306C1AA88A510028092C /* TSKPinValidationOnlineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0710306B1AA88A510028092C /* TSKPinValidationOnlineTests.m */; }; 075AA1091AC985FD00178223 /* TSKPinValidationOfflineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */; }; 0E64A7601B867BA000CA164A /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */; }; 6B032D3A1AF1794D00EAFA69 /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; }; @@ -68,7 +67,6 @@ 8CA6CC351BAE2C1100BDA419 /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC321BAE2C1100BDA419 /* libassert_lib.a */; settings = {ASSET_TAGS = (); }; }; 8CA6CC361BAE2C1100BDA419 /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC331BAE2C1100BDA419 /* libdomain_registry_lib.a */; settings = {ASSET_TAGS = (); }; }; 8CA6CC371BAE2C1100BDA419 /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC341BAE2C1100BDA419 /* libinit_registry_tables_lib.a */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC381BAE2C7200BDA419 /* TSKPinValidationOnlineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0710306B1AA88A510028092C /* TSKPinValidationOnlineTests.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC3A1BAE2C7C00BDA419 /* TSKReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC3B1BAE2C7E00BDA419 /* TSKPinConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F9A31B17564400F06C0E /* TSKPinConfigurationTests.m */; settings = {ASSET_TAGS = (); }; }; @@ -151,7 +149,6 @@ 070868B21ADFF67200E5AFDC /* www.good.com.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = www.good.com.der; sourceTree = ""; }; 070868B41ADFF6B000E5AFDC /* GoodRootCA.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = GoodRootCA.der; sourceTree = ""; }; 070868BA1AE1672D00E5AFDC /* www.good.com.selfsigned.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = www.good.com.selfsigned.der; sourceTree = ""; }; - 0710306B1AA88A510028092C /* TSKPinValidationOnlineTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKPinValidationOnlineTests.m; sourceTree = ""; }; 2FA286123F801C437F35D240 /* TrustKit+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TrustKit+Private.h"; sourceTree = ""; }; 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKPinValidationOfflineTests.m; sourceTree = ""; }; 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKSimpleReporter.m; path = Reporting/TSKSimpleReporter.m; sourceTree = ""; }; @@ -323,7 +320,6 @@ isa = PBXGroup; children = ( 070868B31ADFF68200E5AFDC /* Certificates */, - 0710306B1AA88A510028092C /* TSKPinValidationOnlineTests.m */, 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */, 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */, 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */, @@ -724,7 +720,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0710306C1AA88A510028092C /* TSKPinValidationOnlineTests.m in Sources */, 8CD5F7381BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */, 8C15F9A41B17564400F06C0E /* TSKPinConfigurationTests.m in Sources */, 075AA1091AC985FD00178223 /* TSKPinValidationOfflineTests.m in Sources */, @@ -778,7 +773,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 8CA6CC381BAE2C7200BDA419 /* TSKPinValidationOnlineTests.m in Sources */, 8CD5F7391BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */, 8CA6CC3A1BAE2C7C00BDA419 /* TSKReporterTests.m in Sources */, 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */, diff --git a/TrustKitTests/TSKPinValidationOnlineTests.m b/TrustKitTests/TSKPinValidationOnlineTests.m deleted file mode 100644 index 8b1ea015..00000000 --- a/TrustKitTests/TSKPinValidationOnlineTests.m +++ /dev/null @@ -1,137 +0,0 @@ -/* - - TSKPinValidationOnlineTests.m - TrustKit - - Copyright 2015 The TrustKit Project Authors - Licensed under the MIT license, see associated LICENSE file for terms. - See AUTHORS file for the list of project authors. - - */ - -#import -#import "TrustKit+Private.h" -#import "public_key_utils.h" - - -@interface TSKPinValidationOnlineTests : XCTestCase - -@end - -@implementation TSKPinValidationOnlineTests -/* WARNING: For the online tests, we need to use a different domain for every test otherwise the tests will be disrupted by SSL session resumption. - Specifically, connecting to the same host more than once will potentially allow the first session to be resumed, thereby skipping all SSL validation including TrustKit's. This is not a security issue but will make the tests report unexpected results. - */ - -- (void)setUp { - [super setUp]; - [TrustKit resetConfiguration]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -// Tests a secure connection to https://www.datatheorem.com by pinning only to the CA public key -- (void)testConnectionValidatingCAPublicKey -{ - NSDictionary *trustKitConfig = - @{ - kTSKPinnedDomains : - @{ - @"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key - ]}}}; - - [TrustKit initializeWithConfiguration:trustKitConfig]; - - NSError *error = nil; - NSHTTPURLResponse *response; - NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.datatheorem.com"]]; - - [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; - - XCTAssertNil(error, @"Connection had an error: %@", error); - XCTAssert(response.statusCode==200, @"Server did not respond with a 200 OK"); -// XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); -} - - -// Tests a secure connection to https://www.yahoo.com and forces validation to fail by providing a fake hash -- (void)testConnectionUsingFakeHashInvalidatingAllCertificates -{ - NSDictionary *trustKitConfig = - @{ - kTSKPinnedDomains : - @{ - @"www.yahoo.com" : @{ - kTSKEnforcePinning : @YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key - ]}}}; - - [TrustKit initializeWithConfiguration:trustKitConfig]; - - NSError *error = nil; - NSHTTPURLResponse *response; - NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.yahoo.com"]]; - [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; - -// XCTAssert(error.code==-1202 && [error.domain isEqual:@"NSURLErrorDomain"], @"Invalid certificate error not fired"); -// XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); -} - - -// Tests a secure connection to https://www.google.com and validation should fail because of a fake hash, -// however TrustKit is configured to not enforce pinning so the connection must work -- (void)testConnectionUsingFakeHashInvalidatingAllCertificatesButNotEnforcingPinning -{ - NSDictionary *trustKitConfig = - @{ - kTSKPinnedDomains : - @{ - @"www.google.com" : @{ - kTSKEnforcePinning : @NO, // Pinning disabled! - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key - ]}}}; - - [TrustKit initializeWithConfiguration:trustKitConfig]; - - NSError *error = nil; - NSHTTPURLResponse *response; - NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.google.com"]]; - [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; - - XCTAssertNil(error, @"Connection had an error: %@", error); - XCTAssert(response.statusCode==200, @"Server did not respond with a 200 OK"); -// XCTAssert([TrustKit wasTrustKitCalled], @"TrustKit was not called"); -} - - -// Don't pin anything (connection must work) -- (void)testConnectionWithoutPinningAnything -{ - NSError *error = nil; - NSHTTPURLResponse *response; - NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"https://www.outlook.com"]]; - [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; - - XCTAssertNil(error, @"Connection had an error: %@", error); - XCTAssert(response.statusCode==200, @"Server did not respond with a 200 OK"); -// XCTAssert(![TrustKit wasTrustKitCalled], @"TrustKit was called"); -} - -#pragma clang diagnostic pop - -@end From 6a450ddf3b14f3192342930bf24f879f17001795 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 11:48:10 -0700 Subject: [PATCH 034/118] Final NSURLSession implementation and tests --- .../Swizzling/TSKNSURLSessionDelegateProxy.m | 34 +++-- TrustKitTests/TSKNSURLSessionTests.m | 122 +++++++++++++++++- 2 files changed, 147 insertions(+), 9 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 10c6ab5b..635deb9b 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -26,8 +26,6 @@ +(TSKTrustDecision)getLastTrustDecision + (void)swizzleNSURLSessionConstructors { - static const void *swizzleOncekey = &swizzleOncekey; - // Figure out NSURLSession's "real" class NSString *NSURLSessionClass; if (NSClassFromString(@"NSURLSession") != nil) @@ -53,13 +51,32 @@ + (void)swizzleNSURLSessionConstructors RSSWArguments(NSURLSessionConfiguration * _Nonnull configuration, id _Nullable delegate, NSOperationQueue * _Nullable queue), RSSWReplacement( { - // Replace the delegate with our own so we can intercept and handle authentication challenges - TSKNSURLSessionDelegateProxy *swizzledDelegate = [[TSKNSURLSessionDelegateProxy alloc]initWithDelegate:delegate]; - NSURLSession *session = RSSWCallOriginal(configuration, swizzledDelegate, queue); + NSURLSession *session; + + if (delegate == nil) + { + // Just display a warning + TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); + session = RSSWCallOriginal(configuration, delegate, queue); + } + + // Do not swizzle TrustKit objects (such as the reporter) + else if ([NSStringFromClass([delegate class]) hasPrefix:@"TSK"]) + { + session = RSSWCallOriginal(configuration, delegate, queue); + } + else + { + // Replace the delegate with our own so we can intercept and handle authentication challenges + TSKNSURLSessionDelegateProxy *swizzledDelegate = [[TSKNSURLSessionDelegateProxy alloc]initWithDelegate:delegate]; + session = RSSWCallOriginal(configuration, swizzledDelegate, queue); + } + return session; })); - - // TODO: Add warnings for methods we can't swizzle + // Not hooking the following methods as they end up calling +sessionWithConfiguration:delegate:delegateQueue: + // +sessionWithConfiguration: + // +sharedSession } @@ -228,7 +245,8 @@ - (void)URLSession:(NSURLSession * _Nonnull)session // Forward all challenges (including client auth challenges) to the original delegate if (wasChallengeHandled == NO) { - // If we're here it means the delegate implement the handler method so we can call it directly + // If we're in this delegate method (and not URLSession:didReceiveChallenge:completionHandler:) + // it means the delegate definitely implements the handler method so we can call it directly [originalDelegate URLSession:session task:task didReceiveChallenge:challenge completionHandler:completionHandler]; } } diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index 357b1e6e..82b323cf 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -85,7 +85,91 @@ - (void)tearDown { [super tearDown]; } -- (void)testExample { +- (void)testPinningValidationFailed +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.yahoo.com" : @{ + kTSKEnforcePinning : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSessionTaskDelegate"]; + TestNSURLSessionTaskDelegate* delegate = [[TestNSURLSessionTaskDelegate alloc] initWithExpectation:expectation]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:delegate + delegateQueue:nil]; + + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; + [task resume]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) + { + if (error) + { + NSLog(@"Timeout Error: %@", error); + } + }]; + + XCTAssert(([TSKNSURLSessionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldBlockConnection), @"TrustKit accepted an invalid certificate"); + XCTAssertNotNil(delegate.lastError, @"TrustKit did not trigger an error"); + XCTAssertNil(delegate.lastResponse, @"TrustKit returned a response although pin validation failed"); +} + + +// Tests a secure connection to https://www.yahoo.com and forces validation to fail by providing a fake hash, but do not enforce pinning +- (void)testPinningValidationFailedDoNotEnforcePinning +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.yahoo.com" : @{ + kTSKEnforcePinning : @NO, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSessionTaskDelegate"]; + TestNSURLSessionTaskDelegate* delegate = [[TestNSURLSessionTaskDelegate alloc] initWithExpectation:expectation]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:delegate + delegateQueue:nil]; + + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; + [task resume]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) + { + if (error) + { + NSLog(@"Timeout Error: %@", error); + } + }]; + + XCTAssert(([TSKNSURLSessionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); + XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); + XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); + XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit did not return a response although pinning was not enforced"); +} + + + +- (void)testPinningValidationSucceeded +{ NSDictionary *trustKitConfig = @{ kTSKPinnedDomains : @@ -122,4 +206,40 @@ - (void)testExample { } +- (void)testNoDelegateWarnings +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.yahoo.com" : @{ + kTSKEnforcePinning : @YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + // Run other NSURLSession methods that we swizzle to display a warning, to ensure they don't crash + + // Start a session with a nil delegate + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:nil + delegateQueue:nil]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + [task resume]; + + // Start a session with +sessionWithConfiguration: + NSURLSession *session2 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + NSURLSessionDataTask *task2 = [session2 dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + [task2 resume]; + + // Start a session with +sharedSession + NSURLSession *session3 = [NSURLSession sharedSession]; + NSURLSessionDataTask *task3 = [session3 dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + [task3 resume]; +} + + @end From 20079a64c90d9d6626f278ed9794fd571ab14ef9 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 11:52:06 -0700 Subject: [PATCH 035/118] Fix OS X builds --- TrustKit/TrustKit.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 1b72e9e3..cb093c03 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -153,15 +153,15 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus #if !TARGET_OS_IPHONE // OS X only: extract the optional ignorePinningForUserDefinedTrustAnchors setting - NSNumber *shouldIgnorePinningForUserDefinedTrustAnchors = domainTrustKitArguments[kTSKIgnorePinningForUserDefinedTrustAnchors]; + NSNumber *shouldIgnorePinningForUserDefinedTrustAnchors = TrustKitArguments[kTSKIgnorePinningForUserDefinedTrustAnchors]; if (shouldIgnorePinningForUserDefinedTrustAnchors) { - domainFinalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = shouldIgnorePinningForUserDefinedTrustAnchors; + finalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = shouldIgnorePinningForUserDefinedTrustAnchors; } else { // Default setting is YES - domainFinalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = [NSNumber numberWithBool:YES]; + finalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = [NSNumber numberWithBool:YES]; } #endif From 3361e83d2f611874f404eb8ff9fbcf836333f6a2 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 13:17:38 -0700 Subject: [PATCH 036/118] Fix failing ECDSA test due to new certificates --- TrustKit.xcodeproj/project.pbxproj | 12 ++++++++++++ TrustKitTests/AddTrustExternalRootCA.der | Bin 0 -> 1082 bytes .../COMODOECCCertificationAuthority.der | Bin 0 -> 653 bytes TrustKitTests/TSKPublicKeyAlgorithmTests.m | 12 ++++++++---- TrustKitTests/sni41871.cloudflaressl.com.der | Bin 1770 -> 1571 bytes 5 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 TrustKitTests/AddTrustExternalRootCA.der create mode 100644 TrustKitTests/COMODOECCCertificationAuthority.der diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 17d2d5d2..ab5ab66d 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -105,6 +105,10 @@ 8CD5F74D1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; 8CD5F7571BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */; settings = {ASSET_TAGS = (); }; }; 8CD5F7581BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7831BCC40AF005801D8 /* COMODOECCCertificationAuthority.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CD5F7821BCC40AF005801D8 /* COMODOECCCertificationAuthority.der */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7841BCC40AF005801D8 /* COMODOECCCertificationAuthority.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CD5F7821BCC40AF005801D8 /* COMODOECCCertificationAuthority.der */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7861BCC4650005801D8 /* AddTrustExternalRootCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CD5F7851BCC4650005801D8 /* AddTrustExternalRootCA.der */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7871BCC4650005801D8 /* AddTrustExternalRootCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CD5F7851BCC4650005801D8 /* AddTrustExternalRootCA.der */; settings = {ASSET_TAGS = (); }; }; 8CE9191E1AEA073C002B29AE /* public_key_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE9191C1AEA073C002B29AE /* public_key_utils.h */; }; 8CE9191F1AEA073C002B29AE /* public_key_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE9191D1AEA073C002B29AE /* public_key_utils.m */; }; 8CE919221AEA077F002B29AE /* ssl_pin_verifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */; }; @@ -195,6 +199,8 @@ 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKNSURLSessionDelegateProxy.h; path = Swizzling/TSKNSURLSessionDelegateProxy.h; sourceTree = ""; }; 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKNSURLSessionDelegateProxy.m; path = Swizzling/TSKNSURLSessionDelegateProxy.m; sourceTree = ""; }; 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKNSURLSessionTests.m; sourceTree = ""; }; + 8CD5F7821BCC40AF005801D8 /* COMODOECCCertificationAuthority.der */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COMODOECCCertificationAuthority.der; sourceTree = ""; }; + 8CD5F7851BCC4650005801D8 /* AddTrustExternalRootCA.der */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AddTrustExternalRootCA.der; sourceTree = ""; }; 8CE9191C1AEA073C002B29AE /* public_key_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = public_key_utils.h; path = Pinning/public_key_utils.h; sourceTree = ""; }; 8CE9191D1AEA073C002B29AE /* public_key_utils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = public_key_utils.m; path = Pinning/public_key_utils.m; sourceTree = ""; }; 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ssl_pin_verifier.m; path = Pinning/ssl_pin_verifier.m; sourceTree = ""; }; @@ -385,6 +391,8 @@ isa = PBXGroup; children = ( 8CC78B1C1B1B55EC00523A25 /* COMODOECCDomainValidationSecureServerCA2.der */, + 8CD5F7851BCC4650005801D8 /* AddTrustExternalRootCA.der */, + 8CD5F7821BCC40AF005801D8 /* COMODOECCCertificationAuthority.der */, 8CC78B1D1B1B55EC00523A25 /* sni41871.cloudflaressl.com.der */, ); name = "ECDSA sec256r1"; @@ -661,11 +669,13 @@ buildActionMask = 2147483647; files = ( 8CC78B291B1B697000523A25 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */, + 8CD5F7861BCC4650005801D8 /* AddTrustExternalRootCA.der in Resources */, 8CC78B261B1B696500523A25 /* ThawteSSLCA.der in Resources */, 070868B51ADFFADF00E5AFDC /* GoodRootCA.der in Resources */, 070868BB1AE1672D00E5AFDC /* www.good.com.selfsigned.der in Resources */, 070868B71ADFFADF00E5AFDC /* GoodIntermediateCA.der in Resources */, 8CC78B271B1B696800523A25 /* www.datatheorem.com.der in Resources */, + 8CD5F7831BCC40AF005801D8 /* COMODOECCCertificationAuthority.der in Resources */, 8CC78B281B1B696D00523A25 /* sni41871.cloudflaressl.com.der in Resources */, 070868B81ADFFADF00E5AFDC /* www.good.com.der in Resources */, ); @@ -683,11 +693,13 @@ buildActionMask = 2147483647; files = ( 8CA6CC421BAE2E8600BDA419 /* ThawteSSLCA.der in Resources */, + 8CD5F7871BCC4650005801D8 /* AddTrustExternalRootCA.der in Resources */, 8CA6CC3F1BAE2E8300BDA419 /* GoodRootCA.der in Resources */, 8CA6CC401BAE2E8300BDA419 /* GoodIntermediateCA.der in Resources */, 8CA6CC411BAE2E8300BDA419 /* www.good.com.der in Resources */, 8CA6CC451BAE2E8800BDA419 /* sni41871.cloudflaressl.com.der in Resources */, 8CA6CC431BAE2E8600BDA419 /* www.datatheorem.com.der in Resources */, + 8CD5F7841BCC40AF005801D8 /* COMODOECCCertificationAuthority.der in Resources */, 8CA6CC441BAE2E8800BDA419 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */, 8CA6CC3E1BAE2E8300BDA419 /* www.good.com.selfsigned.der in Resources */, ); diff --git a/TrustKitTests/AddTrustExternalRootCA.der b/TrustKitTests/AddTrustExternalRootCA.der new file mode 100644 index 0000000000000000000000000000000000000000..8a99c54a99fbe7d188e8349044bbf835338815b0 GIT binary patch literal 1082 zcmXqLVlgvlVwPLL%*4pV#K>sC%f_kI=F#?@mywZ`mBAq2klTQhjX9KsO_(Xz)lkGh z2*lwM=5|a;2`MTqE>UoFGE_5A0f}-8%fdxnD@sy}@)C0tLP7!*{8CHG^NX?#l?)U> z>X?NkG1WOcDg@={ml(*2^BNc!m>L@x8kkrZTSSTT8XjN?rvBY=YQMRKuAJRO$F&7v$3OVnzc89ta_Yo{keA2e z`77qma!f!mNNh*Jt^yXWhK4aLSy*%>fBq$A#xwu(vU-c)21|O=7}o zpAG)XtF8Q7ZrndN|6ykS?(0t1vt6DXU;8fCF}^6Oki&d)W$Kd11yjtwGwAaknpAY_ zf<@77krl2-Vzp|wZ@G5l-I}w)F56FP-*skC{gt>gGb=(_aQkxO{;<->uV*!{yKU#v zPTh9dDPMHcj_TjoB)8i0+;|888*y*(5iaqn(`z5X>60`I?kALv!$}}rd+fLyRuno|Argo zyVp48xF<9RZun_r`~1&0HR0n8VoUc&{b@g6QQ4_D>yZyTSDWdcPxk_kT$;B1PMzPo zg1<7BuX&gPMRfc2iaj`Z->vky%Gx(yoVK)1E)YoHHJ8oQOX9M2)tNx2g;mKHpY2|F zRQr(GK4IQxdz0%btCw@~I;_sR+uwEg+qWJmC)U6#u3zUbPg2YfRdBYM`MhSY%8iv1 z#fv-a!=w!@B(@at&pLa8Z(g6C^uwMR&8OuJKf3rFV=4A5OW;5LW3PBaw%*G#K73KL eD)|+-^sdfJR+9^zH04HJkHs&Ff$u8wiGaUlsK=kg@K`=g^{tTrKx4qpmArJfdCsjIP{np z*;ut3Ss0X&Wc<&< z0*rVz1AdTlVGy6yfEh?3$2)TdgFz~jA;Wv-=&Ci_E4YfbcijKK)lGzx>(_#3wH(K! z+V@JVDBi1fDuHM2xta6N$M73G+$UoAipfCa%VZnR<;GPL+}t-O*9y<}+nz6B-Vprn euEGP;S!NfHGwytL=kDkKvN~2`;WsB)UIPHw3dtk@ literal 0 HcmV?d00001 diff --git a/TrustKitTests/TSKPublicKeyAlgorithmTests.m b/TrustKitTests/TSKPublicKeyAlgorithmTests.m index f92f1f35..13f48f8c 100644 --- a/TrustKitTests/TSKPublicKeyAlgorithmTests.m +++ b/TrustKitTests/TSKPublicKeyAlgorithmTests.m @@ -111,12 +111,16 @@ - (void)testVerifyEcDsaSecp256r1 // Create a valid server trust SecCertificateRef leafCertificate = [TSKCertificateUtils createCertificateFromDer:@"sni41871.cloudflaressl.com"]; SecCertificateRef intermediateCertificate = [TSKCertificateUtils createCertificateFromDer:@"COMODOECCDomainValidationSecureServerCA2"]; - SecCertificateRef certChainArray[2] = {leafCertificate, intermediateCertificate}; + SecCertificateRef intermediateCertificate2 = [TSKCertificateUtils createCertificateFromDer:@"COMODOECCCertificationAuthority"]; + SecCertificateRef certChainArray[3] = {leafCertificate, intermediateCertificate, intermediateCertificate2}; + + SecCertificateRef rootCertificate = [TSKCertificateUtils createCertificateFromDer:@"AddTrustExternalRootCA"]; + SecCertificateRef trustStoreArray[1] = {rootCertificate}; SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:NULL - arrayLength:0]; + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; // Create a configuration and parse it so we get the right format NSDictionary *trustKitConfig; @@ -126,7 +130,7 @@ - (void)testVerifyEcDsaSecp256r1 kTSKPublicKeyHashes : @[@"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key ]}}}); - + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; verificationResult = verifyPublicKeyPin(trust, @"istlsfastyet.com", diff --git a/TrustKitTests/sni41871.cloudflaressl.com.der b/TrustKitTests/sni41871.cloudflaressl.com.der index ebaf53be8e55997a53d40c6e3f5eeb0794ac1319..88b4d7fa491567e97cc661b37bffa23141a9bea8 100644 GIT binary patch delta 426 zcmaFGyO>A8povZ1po#V90%j&gCMH3KIX!=-%T9Wd?5ANEdVR6?yNU8E1T2jWARtPd z*U;3^XyWxNtU!${GMhIrZe|Q)N@rsZl@(-ZVu~|pVv1^#D$dI^F|;r@)Jx9EFHK3y zNi0e&F3!^omMBaw+*m`RVy-X+ZAe-OL(X zoLYJr1xa~8wUfUyt4-Etsf-lX(km`W%uCKn)y>b#$;?aDE68aQ)Y2cNT ziwwBfIJDY4&e^gsGckKG7`QSiGVC~CS2epekc*`!_L;PO+P%xCBR`yA7MNe|<6l*^ sLhK!rLfW5M1|@6eDnGSrKK|SObKFS{qj}T3w=eEa*~Gf=XS~LH0K`C-iU0rr delta 618 zcmZ3?^NLsApo#4n5ce!#W@2Pw5^!JAY*!Ry-?C~!%J;Ub0zMNJRtT6HnHYdUlsK=U zse$Fh8&_Cg7&Ngw*}Rc)Gh+m^J{xnWtRPDhvzkE@vr>~(abBj0p@q4jUUE);X-Zm7 zVo_>wagJVcer^-DmY#7+QD!li!>gs2l3$dco}ZScS5(@>ucen-tec#loSByhlApYb zSwlovOD`j_D5W63C@;S_H5;sP@*8F~UI8t=+)Ul7#Dc_<{Nl;HEOqrlT6)DmbtORK zQj1bkz*YdY7ndaFC1<7T=I7;P=B4Tt6N4wm*l1vC6^Xe>gA=DG;yjTJjRXeEnZYlJz-H162$b90IL!= zACiZ3S&QlgFuWs(=^0u4Ucrz?^$0(jHw?JgIJDY4&e^gsGkGz4Fc`QpDKe}Jn7(3C zX{hue>Dgy24z26k9DC%JB1cw$-z5&auHzHEnG^&krh6xbGc~T0G}2tWHdx_H@3&tM Q8uQOq?-4lKx#?^g02<)kegFUf From 844d4752c1913e483f35b6d9e8dd4a1c67030b71 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 14:36:45 -0700 Subject: [PATCH 037/118] Add extra NSURLConnection tests --- TrustKitTests/TSKNSURLConnectionTests.m | 139 +++++++++++++++++++-- TrustKitTests/TSKPinConfigurationTests.m | 3 +- TrustKitTests/TSKPublicKeyAlgorithmTests.m | 2 +- 3 files changed, 134 insertions(+), 10 deletions(-) diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index 68b3a782..eb1d08c8 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -11,12 +11,14 @@ #import "TSKNSURLConnectionDelegateProxy.h" +#pragma mark Private test methods @interface TSKNSURLConnectionDelegateProxy(Private) +(TSKPinValidationResult)getLastTrustDecision; @end -@interface TestNSURLConnectionDelegate : NSObject +#pragma mark Test NSURLConnection delegate with no auth handler +@interface TestNSURLConnectionDelegateNoAuthHandler : NSObject { XCTestExpectation *testExpectation; } @@ -32,7 +34,7 @@ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLRespon @end -@implementation TestNSURLConnectionDelegate { +@implementation TestNSURLConnectionDelegateNoAuthHandler { } - (instancetype)initWithExpectation:(XCTestExpectation *)expectation @@ -76,6 +78,58 @@ - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSUR @end +#pragma mark Test NSURLConnection delegate with connection:didReceiveAuthenticationChallenge: +@interface TestNSURLConnectionDelegateDidReceiveAuth : TestNSURLConnectionDelegateNoAuthHandler + +@property BOOL wasAuthHandlerCalled; // Used to validate that the delegate's auth handler was called + +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; +- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace; +@end + + +@implementation TestNSURLConnectionDelegateDidReceiveAuth +- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ + _wasAuthHandlerCalled = YES; + [testExpectation fulfill]; +} + +- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace +{ + return YES; +} +@end + + + +#pragma mark Test NSURLConnection delegate with connection:willSendRequestForAuthenticationChallenge: +@interface TestNSURLConnectionDelegateWillSendRequestForAuth : TestNSURLConnectionDelegateNoAuthHandler + +@property BOOL wasAuthHandlerCalled; // Used to validate that the delegate's auth handler was called + +- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; +@end + + +@implementation TestNSURLConnectionDelegateWillSendRequestForAuth +- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; +{ + _wasAuthHandlerCalled = YES; + [testExpectation fulfill]; +} + +@end + + +#pragma mark Test suite + +// WARNING: For NSURLConnection tests, whenever we connect to a real endpoint as a test, the TLS Session Cache +// will automatically cache the session, causing subsequent connections to the same host to resume the session. +// When that happens, authentication handlers don't get called which would cause our tests to fail. +// As a hacky workaround, every test that connects to an endpoint uses a different domain. +// https://developer.apple.com/library/mac/qa/qa1727/_index.html + @interface TSKNSURLConnectionTests : XCTestCase @end @@ -154,7 +208,7 @@ - (void)testPinningValidationFailed XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; - TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateNoAuthHandler* delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; // Use -initWithRequest:delegate: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: @@ -194,7 +248,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; - TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateNoAuthHandler* delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; // Use +connectionWithRequest:delegate: NSURLConnection *connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL: @@ -234,11 +288,11 @@ - (void)testPinningValidationSucceeded XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; - TestNSURLConnectionDelegate* delegate = [[TestNSURLConnectionDelegate alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateNoAuthHandler* delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; // Use -initWithRequest:delegate:startstartImmediately: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.datatheorem.com/"]] + [NSURL URLWithString:@"https://www.datatheorem.com:443/"]] delegate:delegate startImmediately:YES]; [connection start]; @@ -255,7 +309,6 @@ - (void)testPinningValidationSucceeded XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit prevented a response from being returned"); XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit prevented a response from being returned"); - } @@ -295,5 +348,77 @@ - (void)testNoDelegateWarnings }]; } +// Ensure that if the original delegate has an auth handler, it also gets called when pinning validation succeed +// so that we don't disrupt the App's usual flow because of TrustKit's swizzling +- (void)testDidReceiveAuthHandlerGetsCalled +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.apple.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"gMxWOrX4PMQesK9qFNbYBxjBfjUvlkn/vN1n+L9lE5E=", // CA key + @"gMxWOrX4PMQesK9qFNbYBxjBfjUvlkn/vN1n+L9lE5E=" // CA key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegateDidReceiveAuth"]; + TestNSURLConnectionDelegateDidReceiveAuth* delegate = [[TestNSURLConnectionDelegateDidReceiveAuth alloc] initWithExpectation:expectation]; + NSURLConnection *connection = [[NSURLConnection alloc] + initWithRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.apple.com/"]] + delegate:delegate]; + [connection start]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) + { + if (error) + { + NSLog(@"Timeout Error: %@", error); + } + }]; + XCTAssert(delegate.wasAuthHandlerCalled, @"TrustKit prevented the original delegate's auth handler from being called."); +} + + +// Ensure that if the original delegate has an auth handler, it also gets called when pinning validation succeed +// so that we don't disrupt the App's usual flow because of TrustKit's swizzling +- (void)testWillSendRequestForAuthHandlerGetsCalled +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.fastmail.fm" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws=", // CA key + @"k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws=" // CA key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegateDidReceiveAuth"]; + TestNSURLConnectionDelegateWillSendRequestForAuth* delegate = [[TestNSURLConnectionDelegateWillSendRequestForAuth alloc] initWithExpectation:expectation]; + NSURLConnection *connection = [[NSURLConnection alloc] + initWithRequest:[NSURLRequest requestWithURL: + [NSURL URLWithString:@"https://www.fastmail.fm/"]] + delegate:delegate]; + [connection start]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) + { + if (error) + { + NSLog(@"Timeout Error: %@", error); + } + }]; + XCTAssert(delegate.wasAuthHandlerCalled, @"TrustKit prevented the original delegate's auth handler from being called."); +} + + #pragma GCC diagnostic pop @end diff --git a/TrustKitTests/TSKPinConfigurationTests.m b/TrustKitTests/TSKPinConfigurationTests.m index 0d04ad31..8b1d5ffd 100644 --- a/TrustKitTests/TSKPinConfigurationTests.m +++ b/TrustKitTests/TSKPinConfigurationTests.m @@ -216,8 +216,7 @@ - (void)testGlobalSettings ]}}}); // Ensure the kTSKSwizzleNetworkDelegates setting was saved - NSDictionary *savedTrustKitConfig = [TrustKit configuration]; - XCTAssert([savedTrustKitConfig[kTSKSwizzleNetworkDelegates] boolValue] == NO, @"kTSKSwizzleNetworkDelegates was not saved in the configuration"); + XCTAssert([trustKitConfig[kTSKSwizzleNetworkDelegates] boolValue] == NO, @"kTSKSwizzleNetworkDelegates was not saved in the configuration"); } @end \ No newline at end of file diff --git a/TrustKitTests/TSKPublicKeyAlgorithmTests.m b/TrustKitTests/TSKPublicKeyAlgorithmTests.m index 13f48f8c..0767e329 100644 --- a/TrustKitTests/TSKPublicKeyAlgorithmTests.m +++ b/TrustKitTests/TSKPublicKeyAlgorithmTests.m @@ -130,7 +130,7 @@ - (void)testVerifyEcDsaSecp256r1 kTSKPublicKeyHashes : @[@"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", // Server Key ]}}}); - + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; verificationResult = verifyPublicKeyPin(trust, @"istlsfastyet.com", From 9a468884f313c2b7e21253a1173fff0a0cc55b30 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 14:47:34 -0700 Subject: [PATCH 038/118] Add extra tests for NSURLSession delegate handling --- TrustKitTests/TSKNSURLSessionTests.m | 143 +++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 6 deletions(-) diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index 82b323cf..a1ad9e4d 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -11,12 +11,14 @@ #import "TSKNSURLSessionDelegateProxy.h" +#pragma mark Private test methods @interface TSKNSURLSessionDelegateProxy(Private) +(TSKPinValidationResult)getLastTrustDecision; @end -@interface TestNSURLSessionTaskDelegate : NSObject +#pragma mark Test NSURLSession delegate with no auth handler +@interface TestNSURLSessionDelegate : NSObject { XCTestExpectation *testExpectation; } @@ -38,7 +40,7 @@ - (void)URLSession:(NSURLSession * _Nonnull)session @end -@implementation TestNSURLSessionTaskDelegate +@implementation TestNSURLSessionDelegate - (instancetype)initWithExpectation:(XCTestExpectation *)expectation { @@ -70,6 +72,63 @@ - (void)URLSession:(NSURLSession * _Nonnull)session @end +#pragma mark Test NSURLSession delegate with URLSession:task:didReceiveChallenge:completionHandler: +@interface TestNSURLSessionDelegateTaskDidReceiveChallenge : TestNSURLSessionDelegate + +@property BOOL wasAuthHandlerCalled; // Used to validate that the delegate's auth handler was called + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler; + +@end + + +@implementation TestNSURLSessionDelegateTaskDidReceiveChallenge + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler +{ + _wasAuthHandlerCalled = YES; + [testExpectation fulfill]; +} + +@end + + +#pragma mark Test NSURLSession delegate with -URLSession:didReceiveChallenge:completionHandler: +@interface TestNSURLSessionDelegateSessionDidReceiveChallenge : TestNSURLSessionDelegate + +@property BOOL wasAuthHandlerCalled; // Used to validate that the delegate's auth handler was called + +- (void)URLSession:(NSURLSession * _Nonnull)session +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler; + +@end + + +@implementation TestNSURLSessionDelegateSessionDidReceiveChallenge + +- (void)URLSession:(NSURLSession * _Nonnull)session +didReceiveChallenge:(NSURLAuthenticationChallenge * _Nonnull)challenge + completionHandler:(void (^ _Nonnull)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential * _Nullable credential))completionHandler +{ + _wasAuthHandlerCalled = YES; + [testExpectation fulfill]; +} + +@end + + +#pragma mark Test suite @interface TSKNSURLSessionTests : XCTestCase @end @@ -102,7 +161,7 @@ - (void)testPinningValidationFailed XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSessionTaskDelegate"]; - TestNSURLSessionTaskDelegate* delegate = [[TestNSURLSessionTaskDelegate alloc] initWithExpectation:expectation]; + TestNSURLSessionDelegate* delegate = [[TestNSURLSessionDelegate alloc] initWithExpectation:expectation]; NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:delegate @@ -143,7 +202,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSessionTaskDelegate"]; - TestNSURLSessionTaskDelegate* delegate = [[TestNSURLSessionTaskDelegate alloc] initWithExpectation:expectation]; + TestNSURLSessionDelegate* delegate = [[TestNSURLSessionDelegate alloc] initWithExpectation:expectation]; NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:delegate @@ -167,7 +226,6 @@ - (void)testPinningValidationFailedDoNotEnforcePinning } - - (void)testPinningValidationSucceeded { NSDictionary *trustKitConfig = @@ -184,7 +242,7 @@ - (void)testPinningValidationSucceeded XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSession"]; - TestNSURLSessionTaskDelegate *delegate = [[TestNSURLSessionTaskDelegate alloc] initWithExpectation:expectation]; + TestNSURLSessionDelegate *delegate = [[TestNSURLSessionDelegate alloc] initWithExpectation:expectation]; NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:delegate @@ -242,4 +300,77 @@ - (void)testNoDelegateWarnings } +// Ensure that if the original delegate has an auth handler, it also gets called when pinning validation succeed +// so that we don't disrupt the App's usual flow because of TrustKit's swizzling +- (void)testTaskDidReceiveChallengeGetsCalled +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSession"]; + TestNSURLSessionDelegateTaskDidReceiveChallenge *delegate = [[TestNSURLSessionDelegateTaskDidReceiveChallenge alloc] initWithExpectation:expectation]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:delegate + delegateQueue:nil]; + + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + [task resume]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { + if (error) { + NSLog(@"Timeout Error: %@", error); + } + }]; + + XCTAssert(delegate.wasAuthHandlerCalled, @"TrustKit prevented the original delegate's auth handler from being called"); +} + + +// Ensure that if the original delegate has an auth handler, it also gets called when pinning validation succeed +// so that we don't disrupt the App's usual flow because of TrustKit's swizzling +- (void)testSessionDidReceiveChallengeGetsCalled +{ + NSDictionary *trustKitConfig = + @{ + kTSKPinnedDomains : + @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ]}}}; + + [TrustKit initializeWithConfiguration:trustKitConfig]; + + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSession"]; + TestNSURLSessionDelegateSessionDidReceiveChallenge *delegate = [[TestNSURLSessionDelegateSessionDidReceiveChallenge alloc] initWithExpectation:expectation]; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:delegate + delegateQueue:nil]; + + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + [task resume]; + + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { + if (error) { + NSLog(@"Timeout Error: %@", error); + } + }]; + + XCTAssert(delegate.wasAuthHandlerCalled, @"TrustKit prevented the original delegate's auth handler from being called"); +} + @end From e42ea1fcedb44df2ee9a4c1f1b7a08cb8dfbebe1 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 15:11:21 -0700 Subject: [PATCH 039/118] Add the IDFV to trust kit reports --- TrustKit/Reporting/TSKBackgroundReporter.m | 17 ++++++++++++++++- TrustKit/Reporting/TSKPinFailureReport.h | 4 +++- TrustKit/Reporting/TSKPinFailureReport.m | 5 ++++- TrustKit/Reporting/TSKSimpleReporter.m | 15 ++++++++++++++- TrustKitTests/TSKReporterTests.m | 12 ++++++++---- 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index 23750f80..28945216 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -15,6 +15,10 @@ #import "reporting_utils.h" #import "TSKReportsRateLimiter.h" +#if TARGET_OS_IPHONE +@import UIKit; // For accessing the IDFV +#endif + // Session identifier for background uploads: .TSKSimpleReporter static NSString* kTSKBackgroundSessionIdentifierFormat = @"%@.TSKSimpleReporter"; static NSURLSession *_backgroundSession = nil; @@ -25,6 +29,7 @@ @interface TSKBackgroundReporter() @property (nonatomic, strong) NSString * appBundleId; @property (nonatomic, strong) NSString * appVersion; +@property (nonatomic, strong) NSString * appIdentifier; @property BOOL shouldRateLimitReports; @end @@ -33,6 +38,7 @@ @interface TSKBackgroundReporter() @implementation TSKBackgroundReporter + - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports { self = [super init]; @@ -41,6 +47,14 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports self.shouldRateLimitReports = shouldRateLimitReports; // Retrieve the App's information +#if TARGET_OS_IPHONE + // On iOS use the IDFV + self.appIdentifier = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; +#else + // On OS X, don't use anything for now + self.appIdentifier = @"OS-X"; +#endif + CFBundleRef appBundle = CFBundleGetMainBundle(); self.appBundleId = (__bridge NSString *)CFBundleGetIdentifier(appBundle); self.appVersion = (__bridge NSString *)CFBundleGetValueForInfoDictionaryKey(appBundle, kCFBundleVersionKey); @@ -146,7 +160,8 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname includeSubdomains:includeSubdomains validatedCertificateChain:certificateChain knownPins:formattedPins - validationResult:validationResult]; + validationResult:validationResult + appIdentifier:self.appIdentifier]; // Should we rate-limit this report? diff --git a/TrustKit/Reporting/TSKPinFailureReport.h b/TrustKit/Reporting/TSKPinFailureReport.h index 1a7a7971..64acde6f 100644 --- a/TrustKit/Reporting/TSKPinFailureReport.h +++ b/TrustKit/Reporting/TSKPinFailureReport.h @@ -17,6 +17,7 @@ @property (readonly, nonatomic) NSString *appBundleId; // Not part of the HPKP spec @property (readonly, nonatomic) NSString *appVersion; // Not part of the HPKP spec +@property (readonly, nonatomic) NSString *appIdentifier; // Not part of the HPKP spec @property (readonly, nonatomic) NSString *notedHostname; @property (readonly, nonatomic) NSString *hostname; @property (readonly, nonatomic) NSNumber *port; @@ -37,7 +38,8 @@ includeSubdomains:(BOOL) includeSubdomains validatedCertificateChain:(NSArray *)validatedCertificateChain knownPins:(NSArray *)knownPins - validationResult:(TSKPinValidationResult) validationResult; + validationResult:(TSKPinValidationResult) validationResult + appIdentifier:(NSString *)appIdentifier; // Return the report in JSON format for POSTing it - (NSData *)json; diff --git a/TrustKit/Reporting/TSKPinFailureReport.m b/TrustKit/Reporting/TSKPinFailureReport.m index 91cb2038..27a56520 100644 --- a/TrustKit/Reporting/TSKPinFailureReport.m +++ b/TrustKit/Reporting/TSKPinFailureReport.m @@ -24,6 +24,7 @@ - (instancetype) initWithAppBundleId:(NSString *) appBundleId validatedCertificateChain:(NSArray *)validatedCertificateChain knownPins:(NSArray *)knownPins validationResult:(TSKPinValidationResult) validationResult + appIdentifier:(NSString *)appIdentifier { self = [super init]; if (self) @@ -38,6 +39,7 @@ - (instancetype) initWithAppBundleId:(NSString *) appBundleId _validatedCertificateChain = validatedCertificateChain; _knownPins = knownPins; _validationResult = validationResult; + _appIdentifier = appIdentifier; } return self; } @@ -62,7 +64,8 @@ - (NSData *)json; @"noted-hostname" : self.notedHostname, @"validated-certificate-chain" : self.validatedCertificateChain, @"known-pins" : self.knownPins, - @"validation-result": [NSNumber numberWithInt:self.validationResult] + @"validation-result": [NSNumber numberWithInt:self.validationResult], + @"app-idfv": self.appIdentifier }; NSError *error; diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m index 6649f507..cc14a88f 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ b/TrustKit/Reporting/TSKSimpleReporter.m @@ -15,10 +15,14 @@ #import "reporting_utils.h" #import "TSKReportsRateLimiter.h" +#if TARGET_OS_IPHONE +@import UIKit; // For accessing the IDFV +#endif @interface TSKSimpleReporter() @property (nonatomic, strong) NSString * appBundleId; @property (nonatomic, strong) NSString * appVersion; +@property (nonatomic, strong) NSString * appIdentifier; @property BOOL shouldRateLimitReports; @end @@ -34,6 +38,14 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports self.shouldRateLimitReports = shouldRateLimitReports; // Retrieve the App's information +#if TARGET_OS_IPHONE + // On iOS use the IDFV + self.appIdentifier = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; +#else + // On OS X, don't use anything for now + self.appIdentifier = @"OS-X"; +#endif + CFBundleRef appBundle = CFBundleGetMainBundle(); self.appBundleId = (__bridge NSString *)CFBundleGetIdentifier(appBundle); self.appVersion = (__bridge NSString *)CFBundleGetValueForInfoDictionaryKey(appBundle, kCFBundleVersionKey); @@ -89,7 +101,8 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname includeSubdomains:includeSubdomains validatedCertificateChain:certificateChain knownPins:formattedPins - validationResult:validationResult]; + validationResult:validationResult + appIdentifier:self.appIdentifier]; // Should we rate-limit this report? diff --git a/TrustKitTests/TSKReporterTests.m b/TrustKitTests/TSKReporterTests.m index ecb49b68..ff952f35 100644 --- a/TrustKitTests/TSKReporterTests.m +++ b/TrustKitTests/TSKReporterTests.m @@ -96,7 +96,8 @@ - (void)testReportsRateLimiter includeSubdomains:NO validatedCertificateChain:certificateChain knownPins:formattedPins - validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted]; + validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted + appIdentifier:@"test"]; // Ensure the same report will not be sent twice in a row XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); @@ -117,7 +118,8 @@ - (void)testReportsRateLimiter includeSubdomains:NO validatedCertificateChain:certificateChain knownPins:formattedPins - validationResult:TSKPinValidationResultFailed]; + validationResult:TSKPinValidationResultFailed + appIdentifier:@"test"]; XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == YES, @"Did not rate-limit an identical report"); @@ -132,7 +134,8 @@ - (void)testReportsRateLimiter includeSubdomains:NO validatedCertificateChain:certificateChain knownPins:formattedPins - validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted]; + validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted + appIdentifier:@"test"]; XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == YES, @"Did not rate-limit an identical report"); @@ -147,7 +150,8 @@ - (void)testReportsRateLimiter includeSubdomains:NO validatedCertificateChain:[certificateChain subarrayWithRange:NSMakeRange(1, 2)] knownPins:formattedPins - validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted]; + validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted + appIdentifier:@"test"]; XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == YES, @"Did not rate-limit an identical report"); } From a2d8ca58237bb49c476b04d2ec412b078eb35aa5 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 15:12:27 -0700 Subject: [PATCH 040/118] Fix Xcode warning --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h index df1fb801..1a7812a0 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.h @@ -9,7 +9,7 @@ #import -@interface TSKNSURLConnectionDelegateProxy : NSObject +@interface TSKNSURLConnectionDelegateProxy : NSObject { id originalDelegate; // The NSURLConnectionDelegate we're going to proxy } From 942a866d1550fde34f648adf5bade97118daf839 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 15:14:34 -0700 Subject: [PATCH 041/118] Don't print a warning --- TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 635deb9b..50de5030 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -56,7 +56,7 @@ + (void)swizzleNSURLSessionConstructors if (delegate == nil) { // Just display a warning - TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); + //TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); session = RSSWCallOriginal(configuration, delegate, queue); } From 13190edd304a3e10278c9903d22833b2139cffdd Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 15:22:15 -0700 Subject: [PATCH 042/118] Fix remaining failing test --- TrustKitTests/TSKPublicKeyAlgorithmTests.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/TrustKitTests/TSKPublicKeyAlgorithmTests.m b/TrustKitTests/TSKPublicKeyAlgorithmTests.m index 0767e329..e87c6c49 100644 --- a/TrustKitTests/TSKPublicKeyAlgorithmTests.m +++ b/TrustKitTests/TSKPublicKeyAlgorithmTests.m @@ -114,8 +114,9 @@ - (void)testVerifyEcDsaSecp256r1 SecCertificateRef intermediateCertificate2 = [TSKCertificateUtils createCertificateFromDer:@"COMODOECCCertificationAuthority"]; SecCertificateRef certChainArray[3] = {leafCertificate, intermediateCertificate, intermediateCertificate2}; - SecCertificateRef rootCertificate = [TSKCertificateUtils createCertificateFromDer:@"AddTrustExternalRootCA"]; - SecCertificateRef trustStoreArray[1] = {rootCertificate}; + // If we put the real root CA, the test fails on OS X; using the last intermediate cert instead + //SecCertificateRef rootCertificate = [TSKCertificateUtils createCertificateFromDer:@"AddTrustExternalRootCA"]; + SecCertificateRef trustStoreArray[1] = {intermediateCertificate2}; SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) From e3cfef28ba8eaeae725abb12d3ef66b944c711b7 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 15:36:56 -0700 Subject: [PATCH 043/118] Fix project settings --- TrustKit.xcodeproj/project.pbxproj | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index ab5ab66d..50144fb9 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -983,11 +983,12 @@ GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = TrustKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @loader_path/../Frameworks @executable_path/../Frameworks"; + ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = "$(inherited)"; - SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "$(inherited)"; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "armv7 arm64"; }; name = Debug; }; @@ -1005,11 +1006,12 @@ GCC_TREAT_WARNINGS_AS_ERRORS = YES; INFOPLIST_FILE = TrustKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks @loader_path/../Frameworks @executable_path/../Frameworks"; + ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = "$(inherited)"; - SUPPORTED_PLATFORMS = "$(inherited)"; - VALID_ARCHS = "$(inherited)"; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + VALID_ARCHS = "armv7 arm64"; }; name = Release; }; @@ -1081,9 +1083,12 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/osx"; MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.datatheorem.TrustKit; PRODUCT_NAME = TrustKit; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = macosx; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Debug; }; @@ -1105,9 +1110,12 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/osx"; MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = com.datatheorem.TrustKit; PRODUCT_NAME = TrustKit; SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = macosx; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Release; }; @@ -1121,8 +1129,11 @@ INFOPLIST_FILE = TrustKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.TrustKit-OS-XTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = macosx; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Debug; }; @@ -1137,8 +1148,11 @@ INFOPLIST_FILE = TrustKitTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.10; + ONLY_ACTIVE_ARCH = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.TrustKit-OS-XTests"; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = macosx; + VALID_ARCHS = "$(ARCHS_STANDARD)"; }; name = Release; }; From 112532135f12db51ffe45cf3474f1098750ca88c Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 15:46:55 -0700 Subject: [PATCH 044/118] Try new travis build matrix --- .travis.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 092f46f6..b44a3138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ language: objective-c env: matrix: - - TEST_SDK=macosx10.9 - - TEST_SDK=macosx10.10 - - TEST_SDK=iphonesimulator8.1 - - TEST_SDK=iphonesimulator7.0 + - TEST_SDK=macosx10.9 TEST_SCHEME="TrustKit OS X" + - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" + - TEST_SDK=iphonesimulator9.0 TEST_SCHEME="TrustKit" + - TEST_SDK=iphonesimulator7.0 TEST_SCHEME="TrustKit" script: - - xcodebuild clean -project TrustKit.xcodeproj -scheme TrustKit -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - - xcodebuild build test -project TrustKit.xcodeproj -scheme TrustKit -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild build test -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From 55dd7e175613f91dd9d6c50db02da84cbb6d442e Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 15:56:29 -0700 Subject: [PATCH 045/118] Force Xcode 7 for travis builds --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b44a3138..1659daa5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: objective-c +osx_image: xcode7 env: matrix: - TEST_SDK=macosx10.9 TEST_SCHEME="TrustKit OS X" From 32ca72fb54b453f135ea53313bd423bd1f9a5a96 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 16:06:56 -0700 Subject: [PATCH 046/118] style --- TrustKitTests/TSKNSURLConnectionTests.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index eb1d08c8..7f0d0351 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -208,7 +208,7 @@ - (void)testPinningValidationFailed XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; - TestNSURLConnectionDelegateNoAuthHandler* delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateNoAuthHandler *delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; // Use -initWithRequest:delegate: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: @@ -248,7 +248,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; - TestNSURLConnectionDelegateNoAuthHandler* delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateNoAuthHandler *delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; // Use +connectionWithRequest:delegate: NSURLConnection *connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL: @@ -288,7 +288,7 @@ - (void)testPinningValidationSucceeded XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; - TestNSURLConnectionDelegateNoAuthHandler* delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateNoAuthHandler *delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; // Use -initWithRequest:delegate:startstartImmediately: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: @@ -366,7 +366,7 @@ - (void)testDidReceiveAuthHandlerGetsCalled XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegateDidReceiveAuth"]; - TestNSURLConnectionDelegateDidReceiveAuth* delegate = [[TestNSURLConnectionDelegateDidReceiveAuth alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateDidReceiveAuth *delegate = [[TestNSURLConnectionDelegateDidReceiveAuth alloc] initWithExpectation:expectation]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: [NSURL URLWithString:@"https://www.apple.com/"]] @@ -402,7 +402,7 @@ - (void)testWillSendRequestForAuthHandlerGetsCalled XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegateDidReceiveAuth"]; - TestNSURLConnectionDelegateWillSendRequestForAuth* delegate = [[TestNSURLConnectionDelegateWillSendRequestForAuth alloc] initWithExpectation:expectation]; + TestNSURLConnectionDelegateWillSendRequestForAuth *delegate = [[TestNSURLConnectionDelegateWillSendRequestForAuth alloc] initWithExpectation:expectation]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: [NSURL URLWithString:@"https://www.fastmail.fm/"]] From f9e96350016d0a5e07d3470e94ffaad4309a5e0e Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 16:07:11 -0700 Subject: [PATCH 047/118] Use 7.0 as the iOS deployment target --- TrustKit.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 50144fb9..6bb42107 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -916,7 +916,7 @@ ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -948,7 +948,7 @@ ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", From 8587fcf4e933e197520edbf4553f60824518aff9 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 16:17:30 -0700 Subject: [PATCH 048/118] Fix tests --- TrustKitTests/TSKNSURLConnectionTests.m | 1 - TrustKitTests/TSKNSURLSessionTests.m | 1 - 2 files changed, 2 deletions(-) diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index 7f0d0351..401758cd 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -267,7 +267,6 @@ - (void)testPinningValidationFailedDoNotEnforcePinning XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); - XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit did not return a response although pinning was not enforced"); } diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index a1ad9e4d..70f06f47 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -222,7 +222,6 @@ - (void)testPinningValidationFailedDoNotEnforcePinning XCTAssert(([TSKNSURLSessionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); - XCTAssert([(NSHTTPURLResponse *)delegate.lastResponse statusCode] == 200, @"TrustKit did not return a response although pinning was not enforced"); } From 51f62c4fbe50c4baf2e4fa9084db4589c53bdeb8 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 16:18:00 -0700 Subject: [PATCH 049/118] Remove iOS 7 builds as travis doesn't support them --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1659daa5..e01900fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ env: - TEST_SDK=macosx10.9 TEST_SCHEME="TrustKit OS X" - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" - TEST_SDK=iphonesimulator9.0 TEST_SCHEME="TrustKit" - - TEST_SDK=iphonesimulator7.0 TEST_SCHEME="TrustKit" + - TEST_SDK=iphonesimulator8.0 TEST_SCHEME="TrustKit" script: - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - xcodebuild build test -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From ad160a04e657993c76e871ee2c75979118e711c5 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 16:54:26 -0700 Subject: [PATCH 050/118] Simplify travis file --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e01900fc..b6b01de8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,10 +2,8 @@ language: objective-c osx_image: xcode7 env: matrix: - - TEST_SDK=macosx10.9 TEST_SCHEME="TrustKit OS X" - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" - TEST_SDK=iphonesimulator9.0 TEST_SCHEME="TrustKit" - - TEST_SDK=iphonesimulator8.0 TEST_SCHEME="TrustKit" script: - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - xcodebuild build test -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From 150649fd4ad5fd05558734b9822ac7b07073f876 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 17:36:34 -0700 Subject: [PATCH 051/118] Tweak name --- TrustKit/Reporting/TSKPinFailureReport.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Reporting/TSKPinFailureReport.m b/TrustKit/Reporting/TSKPinFailureReport.m index 27a56520..500e2378 100644 --- a/TrustKit/Reporting/TSKPinFailureReport.m +++ b/TrustKit/Reporting/TSKPinFailureReport.m @@ -65,7 +65,7 @@ - (NSData *)json; @"validated-certificate-chain" : self.validatedCertificateChain, @"known-pins" : self.knownPins, @"validation-result": [NSNumber numberWithInt:self.validationResult], - @"app-idfv": self.appIdentifier + @"app-identifier": self.appIdentifier }; NSError *error; From c94a927dcbca71733708ebc6bf109e15e64e605d Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 17:51:28 -0700 Subject: [PATCH 052/118] Tweak Demo App to support new iOS 9 implementation --- .../TrustKitDemo.xcodeproj/project.pbxproj | 37 +++++++++++ TrustKitDemo/TrustKitDemo/AppDelegate.m | 46 +++++++++---- .../TrustKitDemo/Base.lproj/Main.storyboard | 27 ++------ TrustKitDemo/TrustKitDemo/ViewController.h | 7 +- TrustKitDemo/TrustKitDemo/ViewController.m | 64 +++++++++++++------ 5 files changed, 125 insertions(+), 56 deletions(-) diff --git a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj index d269dce8..256aabd5 100644 --- a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj +++ b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj @@ -61,6 +61,20 @@ remoteGlobalIDString = 8C8480461A896EE30017C155; remoteInfo = TrustKit; }; + 8CD5F7911BCC801B005801D8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6B6B477D1B1F0BBD007757EE /* TrustKit.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8CA6CBFD1BAE2ADD00BDA419; + remoteInfo = "TrustKit OS X"; + }; + 8CD5F7931BCC801B005801D8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 6B6B477D1B1F0BBD007757EE /* TrustKit.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8CA6CC061BAE2ADD00BDA419; + remoteInfo = "TrustKit OS XTests"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -179,6 +193,8 @@ 6B6B47831B1F0BBD007757EE /* TrustKit.framework */, 8C8717281B23D12300267E1D /* libTrustKit_Static.a */, 6B6B47851B1F0BBD007757EE /* TrustKitTests.xctest */, + 8CD5F7921BCC801B005801D8 /* TrustKit.framework */, + 8CD5F7941BCC801B005801D8 /* TrustKit OS XTests.xctest */, ); name = Products; sourceTree = ""; @@ -235,6 +251,7 @@ TargetAttributes = { 6B6B47531B1EECB3007757EE = { CreatedOnToolsVersion = 6.3.1; + DevelopmentTeam = D94Z5227S5; }; 6B6B476C1B1EECB4007757EE = { CreatedOnToolsVersion = 6.3.1; @@ -289,6 +306,20 @@ remoteRef = 8C8717271B23D12300267E1D /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 8CD5F7921BCC801B005801D8 /* TrustKit.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = TrustKit.framework; + remoteRef = 8CD5F7911BCC801B005801D8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 8CD5F7941BCC801B005801D8 /* TrustKit OS XTests.xctest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = "TrustKit OS XTests.xctest"; + remoteRef = 8CD5F7931BCC801B005801D8 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ @@ -464,9 +495,12 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = TrustKitDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; }; name = Debug; }; @@ -474,9 +508,12 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = TrustKitDemo/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE = ""; }; name = Release; }; diff --git a/TrustKitDemo/TrustKitDemo/AppDelegate.m b/TrustKitDemo/TrustKitDemo/AppDelegate.m index 4ab4fa1f..6ae26e2b 100644 --- a/TrustKitDemo/TrustKitDemo/AppDelegate.m +++ b/TrustKitDemo/TrustKitDemo/AppDelegate.m @@ -22,20 +22,42 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. - // Initialize TrustKit here so that from this point on, pin check is turned on + // Initialize TrustKit NSDictionary *trustKitConfig = @{ - @"www.datatheorem.com" : @{ - kTSKEnforcePinning:@YES, - kTSKIncludeSubdomains:@YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[ - // Bad SSL pins for datatheorem.com to demonstrate pinning failures in the webview - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTX=", - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" - ], - kTSKReportUris: @[@"https://trustkit-reports-server.appspot.com/log_report"] - }}; + // Auto-swizzle NSURLSession delegates to add pinning validation + kTSKSwizzleNetworkDelegates: @YES, + + kTSKPinnedDomains: @{ + + // Pin invalid SPKI hashes to *.yahoo.com to demonstrate pinning failures + @"yahoo.com" : @{ + kTSKEnforcePinning:@YES, + kTSKIncludeSubdomains:@YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + + // Wrong SPKI hashes to demonstrate pinning failure + kTSKPublicKeyHashes : @[ + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" + ], + + // Send reports for pinning failures + kTSKReportUris: @[@"https://trustkit-reports-server.appspot.com/log_report"] + }, + + + // Pin valid SPKI hashes to *.datatheorem.com to demonstrate success + @"www.datatheorem.com" : @{ + kTSKEnforcePinning:@YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + + // Valid SPKI hashes to demonstrate success + kTSKPublicKeyHashes : @[ + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ] + }}}; [TrustKit initializeWithConfiguration:trustKitConfig]; diff --git a/TrustKitDemo/TrustKitDemo/Base.lproj/Main.storyboard b/TrustKitDemo/TrustKitDemo/Base.lproj/Main.storyboard index fd87e0cf..76df1017 100644 --- a/TrustKitDemo/TrustKitDemo/Base.lproj/Main.storyboard +++ b/TrustKitDemo/TrustKitDemo/Base.lproj/Main.storyboard @@ -1,7 +1,8 @@ - + - + + @@ -16,36 +17,18 @@ - - - - - - + - + - diff --git a/TrustKitDemo/TrustKitDemo/ViewController.h b/TrustKitDemo/TrustKitDemo/ViewController.h index f7d18de3..50c27fac 100644 --- a/TrustKitDemo/TrustKitDemo/ViewController.h +++ b/TrustKitDemo/TrustKitDemo/ViewController.h @@ -11,7 +11,12 @@ #import -@interface ViewController : UIViewController +@interface ViewController : UIViewController + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didCompleteWithError:(NSError * _Nullable)error; + @end diff --git a/TrustKitDemo/TrustKitDemo/ViewController.m b/TrustKitDemo/TrustKitDemo/ViewController.m index 8db09d43..b0d82931 100644 --- a/TrustKitDemo/TrustKitDemo/ViewController.m +++ b/TrustKitDemo/TrustKitDemo/ViewController.m @@ -15,7 +15,8 @@ @interface ViewController () @property (weak, nonatomic) IBOutlet UITextField *connectionTextfield; @property (weak, nonatomic) IBOutlet UIWebView *destinationWebView; - +@property NSURL *baseUrl; +@property NSURLSession *session; @end @@ -24,7 +25,28 @@ @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; self.destinationWebView.delegate = self; - self.connectionTextfield.text = @"https://www.datatheorem.com/"; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:self + delegateQueue:nil]; + self.session = session; + + // First demonstrate pinning failure + [self loadUrlWithPinningFailure]; +} + + +- (void)loadUrlWithPinningFailure { + // Load a URL with a bad pinning configuration to demonstrate a pinning failure with a report being sent + NSURLSessionDataTask *task = [self.session dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; + [task resume]; +} + +- (void)loadUrlWithPinningSuccess { + // Load a URL with a good pinning configuration + self.baseUrl = [NSURL URLWithString:@"https://www.datatheorem.com/"]; + NSURLSessionDataTask *task = [self.session dataTaskWithURL:self.baseUrl]; + [task resume]; } - (void)didReceiveMemoryWarning { @@ -32,29 +54,29 @@ - (void)didReceiveMemoryWarning { // Dispose of any resources that can be recreated. } -// connect to a website -- (IBAction)connectButton:(UIButton *)sender { - if (self.connectionTextfield.hasText) { - NSLog(@"connection field: %@", self.connectionTextfield.text); - NSString *urlString = self.connectionTextfield.text; - NSURL *url = [NSURL URLWithString:urlString]; - NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; - [self.destinationWebView loadRequest:urlRequest]; - } else { - NSLog(@"connection field is empty"); + +- (void)URLSession:(NSURLSession * _Nonnull)session + task:(NSURLSessionTask * _Nonnull)task +didCompleteWithError:(NSError * _Nullable)error +{ + if (error) + { + // An error will only be triggered when loading + NSLog(@"Received error %@", error); + // Now try a valid connection + [self loadUrlWithPinningSuccess]; } } -// show user an error dialog when webview cannot load -- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - NSLog(@"%s webview fail load error=%@", __FUNCTION__, error); - UIAlertView *infoMessage; - infoMessage = [[UIAlertView alloc] - initWithTitle:@"webview load failed" message:[error localizedDescription] - delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil]; - infoMessage.alertViewStyle = UIAlertViewStyleDefault; - [infoMessage show]; +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data +{ + // Display the content in the webview + NSLog(@"Loading content"); + [self.destinationWebView loadHTMLString:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] + baseURL:self.baseUrl]; } From befda61f5d0f6d346a0dc042317c7e1c820a1d2d Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 18:08:05 -0700 Subject: [PATCH 053/118] Re-enable NSURLSession warning --- .../Swizzling/TSKNSURLSessionDelegateProxy.m | 2 +- TrustKit/TrustKit.m | 23 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 50de5030..635deb9b 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -56,7 +56,7 @@ + (void)swizzleNSURLSessionConstructors if (delegate == nil) { // Just display a warning - //TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); + TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); session = RSSWCallOriginal(configuration, delegate, queue); } diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index cb093c03..a981b229 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -346,17 +346,8 @@ static void initializeTrustKit(NSDictionary *trustKitConfig) // Convert and store the SSL pins in our global variable _trustKitGlobalConfiguration = [[NSDictionary alloc]initWithDictionary:parseTrustKitArguments(trustKitConfig)]; - // Hook network APIs if needed - if ([_trustKitGlobalConfiguration[kTSKSwizzleNetworkDelegates] boolValue] == YES) - { - // NSURLConnection - [TSKNSURLConnectionDelegateProxy swizzleNSURLConnectionConstructors]; - - // NSURLSession - [TSKNSURLSessionDelegateProxy swizzleNSURLSessionConstructors]; - } - // Create our reporter for sending pin validation failures + // Create our reporter for sending pin validation failures; do this before hooking NSURLSession so we don't hook ourselves @try { // Create a reporter that uses the background transfer service to send pin failure reports @@ -376,6 +367,18 @@ static void initializeTrustKit(NSDictionary *trustKitConfig) _pinFailureReporterQueue = dispatch_queue_create(kTSKPinFailureReporterQueueLabel, DISPATCH_QUEUE_SERIAL); dispatch_set_target_queue(_pinFailureReporterQueue, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); + + // Hook network APIs if needed + if ([_trustKitGlobalConfiguration[kTSKSwizzleNetworkDelegates] boolValue] == YES) + { + // NSURLConnection + [TSKNSURLConnectionDelegateProxy swizzleNSURLConnectionConstructors]; + + // NSURLSession + [TSKNSURLSessionDelegateProxy swizzleNSURLSessionConstructors]; + } + + // All done _isTrustKitInitialized = YES; TSKLog(@"Successfully initialized with configuration %@", _trustKitGlobalConfiguration); From d42851823ad0d1d6d55bf135d41f125214cbb53a Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 18:14:13 -0700 Subject: [PATCH 054/118] Improve method mirroring in NSURLSession delegate proxy --- .../Swizzling/TSKNSURLSessionDelegateProxy.m | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 635deb9b..614fd99c 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -103,15 +103,23 @@ - (BOOL)respondsToSelector:(SEL)aSelector } else if (aSelector == @selector(URLSession:didReceiveChallenge:completionHandler:)) { - if ([originalDelegate respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)] == NO) + if ([originalDelegate respondsToSelector:@selector(URLSession:didReceiveChallenge:completionHandler:)] == YES) { - // If the task-level handler is not implemented in the delegate, we need to implement the session-level handler - // regardless of what the delegate implements, to ensure we get to handle auth challenges return YES; } else { - return [originalDelegate respondsToSelector:@selector(URLSession:didReceiveChallenge:completionHandler:)]; + if ([originalDelegate respondsToSelector:@selector(URLSession:task:didReceiveChallenge:completionHandler:)] == NO) + { + // If the task-level handler is not implemented in the delegate, we need to implement the session-level handler + // regardless of what the delegate implements, to ensure we get to handle auth challenges so we can do pinning validation + return YES; + } + else + { + // Let the task-level handler handle auth challenges + return NO; + } } } else From bc39395d135f0f510dec4dacdeb2f34baede93cf Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 18:35:42 -0700 Subject: [PATCH 055/118] Always re-use the same session --- TrustKit/Reporting/TSKSimpleReporter.m | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m index cc14a88f..ac10a36b 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ b/TrustKit/Reporting/TSKSimpleReporter.m @@ -19,11 +19,15 @@ @import UIKit; // For accessing the IDFV #endif + + + @interface TSKSimpleReporter() @property (nonatomic, strong) NSString * appBundleId; @property (nonatomic, strong) NSString * appVersion; @property (nonatomic, strong) NSString * appIdentifier; @property BOOL shouldRateLimitReports; +@property(nonatomic, strong) NSURLSession *session; @end @@ -60,6 +64,10 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports { self.appVersion = @"N/A"; } + + + // Create the session for sending the reports + self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; } return self; } @@ -112,19 +120,14 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname TSKLog(@"Pin failure report for %@ was not sent due to rate-limiting", serverHostname); return; } - - // Create the session for sending the report - NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; - NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration - delegate:self - delegateQueue:nil]; + // POST the report to all the configured report URIs for (NSURL *reportUri in reportURIs) { NSURLRequest *request = [report requestToUri:reportUri]; - NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { + NSURLSessionDataTask *postDataTask = [self.session dataTaskWithRequest:request + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // We don't do anything here as reports are meant to be sent // on a best-effort basis: even if we got an error, there's // nothing to do anyway. From 2619acd8f4f1f7f808a14edaf7f96a2fca95ab7a Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 18:36:02 -0700 Subject: [PATCH 056/118] Tweak demo App --- .../TrustKitDemo.xcodeproj/project.pbxproj | 2 ++ TrustKitDemo/TrustKitDemo/AppDelegate.m | 22 +++++++++---------- TrustKitDemo/TrustKitDemo/Info.plist | 5 +++++ TrustKitDemo/TrustKitDemo/ViewController.h | 4 +++- TrustKitDemo/TrustKitDemo/ViewController.m | 7 +++--- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj index 256aabd5..ef1eb506 100644 --- a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj +++ b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj @@ -498,6 +498,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = TrustKitDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -511,6 +512,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = TrustKitDemo/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; diff --git a/TrustKitDemo/TrustKitDemo/AppDelegate.m b/TrustKitDemo/TrustKitDemo/AppDelegate.m index 6ae26e2b..d3524fce 100644 --- a/TrustKitDemo/TrustKitDemo/AppDelegate.m +++ b/TrustKitDemo/TrustKitDemo/AppDelegate.m @@ -46,18 +46,18 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( kTSKReportUris: @[@"https://trustkit-reports-server.appspot.com/log_report"] }, + + // Pin valid SPKI hashes to *.datatheorem.com to demonstrate success + @"www.datatheorem.com" : @{ + kTSKEnforcePinning:@YES, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - // Pin valid SPKI hashes to *.datatheorem.com to demonstrate success - @"www.datatheorem.com" : @{ - kTSKEnforcePinning:@YES, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - - // Valid SPKI hashes to demonstrate success - kTSKPublicKeyHashes : @[ - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key - ] - }}}; + // Valid SPKI hashes to demonstrate success + kTSKPublicKeyHashes : @[ + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + ] + }}}; [TrustKit initializeWithConfiguration:trustKitConfig]; diff --git a/TrustKitDemo/TrustKitDemo/Info.plist b/TrustKitDemo/TrustKitDemo/Info.plist index 5c8fced7..1011bee5 100644 --- a/TrustKitDemo/TrustKitDemo/Info.plist +++ b/TrustKitDemo/TrustKitDemo/Info.plist @@ -22,6 +22,11 @@ 1 LSRequiresIPhoneOS + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + UILaunchStoryboardName Main UIMainStoryboardFile diff --git a/TrustKitDemo/TrustKitDemo/ViewController.h b/TrustKitDemo/TrustKitDemo/ViewController.h index 50c27fac..3ae96856 100644 --- a/TrustKitDemo/TrustKitDemo/ViewController.h +++ b/TrustKitDemo/TrustKitDemo/ViewController.h @@ -17,7 +17,9 @@ task:(NSURLSessionTask * _Nonnull)task didCompleteWithError:(NSError * _Nullable)error; - +- (void)URLSession:(NSURLSession * _Nonnull)session + dataTask:(NSURLSessionDataTask * _Nonnull)dataTask + didReceiveData:(NSData * _Nonnull)data; @end diff --git a/TrustKitDemo/TrustKitDemo/ViewController.m b/TrustKitDemo/TrustKitDemo/ViewController.m index b0d82931..0ce4d83e 100644 --- a/TrustKitDemo/TrustKitDemo/ViewController.m +++ b/TrustKitDemo/TrustKitDemo/ViewController.m @@ -69,9 +69,10 @@ - (void)URLSession:(NSURLSession * _Nonnull)session } } -- (void)URLSession:(NSURLSession *)session - dataTask:(NSURLSessionDataTask *)dataTask - didReceiveData:(NSData *)data + +- (void)URLSession:(NSURLSession * _Nonnull)session + dataTask:(NSURLSessionDataTask * _Nonnull)dataTask + didReceiveData:(NSData * _Nonnull)data { // Display the content in the webview NSLog(@"Loading content"); From 2b7dc66469b5af8aa83f53566bd0c0bad1b68327 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 20:54:17 -0700 Subject: [PATCH 057/118] Fix handling of kTSKIgnorePinningForUserDefinedTrustAnchors --- TrustKit/Pinning/TSKPinningValidator.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.m b/TrustKit/Pinning/TSKPinningValidator.m index dcf2187f..e319b85d 100644 --- a/TrustKit/Pinning/TSKPinningValidator.m +++ b/TrustKit/Pinning/TSKPinningValidator.m @@ -61,7 +61,7 @@ + (TSKTrustDecision) evaluateTrust:(SecTrustRef)serverTrust forHostname:(NSStrin TSKLog(@"Pin validation failed for %@", serverHostname); #if !TARGET_OS_IPHONE if ((validationResult == TSKPinValidationResultFailedUserDefinedTrustAnchor) - && ([domainConfig[kTSKIgnorePinningForUserDefinedTrustAnchors] boolValue] == YES)) + && ([trustKitConfig[kTSKIgnorePinningForUserDefinedTrustAnchors] boolValue] == YES)) { // OS-X only: user-defined trust anchors can be whitelisted (for corporate proxies, etc.) so don't send reports TSKLog(@"Ignoring pinning failure due to user-defined trust anchor for %@", serverHostname); From cc58239f64bb45e76414db3906c2ca2362973b87 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 12 Oct 2015 23:46:44 -0700 Subject: [PATCH 058/118] Update documentation for iOS 9 changes --- TrustKit/Pinning/TSKPinningValidator.h | 76 +++++++++++++++++++++++--- TrustKit/TrustKit.h | 51 ++++++++++++----- docs/api-doc-index.md | 5 +- 3 files changed, 108 insertions(+), 24 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.h b/TrustKit/Pinning/TSKPinningValidator.h index 05ebe2e7..59566074 100644 --- a/TrustKit/Pinning/TSKPinningValidator.h +++ b/TrustKit/Pinning/TSKPinningValidator.h @@ -19,8 +19,22 @@ */ typedef NS_ENUM(NSInteger, TSKTrustDecision) { +/** + Based on the server's certificate chain and the global pinning policy for this domain, the SSL connection should be allowed. + This return value does not necessarily mean that the pinning validation succeded (for example if `kTSKEnforcePinning` was set to `NO` for this domain). If a pinning validation failure occured and if a report URI was configured, a pin failure report was sent. + */ TSKTrustDecisionShouldAllowConnection, + +/** + Based on the server's certificate chain and the global pinning policy for this domain, the SSL connection should be blocked. + A pinning validation failure occured and if a report URI was configured, a pin failure report was sent. + */ TSKTrustDecisionShouldBlockConnection, + +/** + No pinning policy was configured for this domain and TrustKit did not validate the server's identity. + Because this will happen in an authentication handler, it means that the server's _serverTrust_ object __needs__ to be verified against the device's trust store using `SecTrustEvaluate()`. Failing to do so will __disable SSL certificate validation__. + */ TSKTrustDecisionDomainNotPinned, }; @@ -28,14 +42,60 @@ typedef NS_ENUM(NSInteger, TSKTrustDecision) /** `TSKPinningValidator` is a class for manually verifying a server's identity against the global SSL pinning policy. - In a few specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's trust object, which contains its certificate chain, needs to be retrieved or built before being passed to `TSKPinningValidator` for validation. + In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's trust object, which contains its certificate chain, needs to be retrieved or built before being passed to `TSKPinningValidator` for validation. The following scenarios require manual pin validation: - 1. Connections initiated from an external process, where TrustKit does not get loaded: - * `WKWebView` connections: the server's trust object can be retrieved within the `webView:didReceiveAuthenticationChallenge:completionHandler:` method. - * `NSURLSession` connections using the background transfer service: the server's trust object can be retrieved within the `application:handleEventsForBackgroundURLSession:completionHandler:` method. - 2. Connections initiated using a third-party SSL library such as OpenSSL, instead of Apple's SecureTransport. The server's trust object needs to be built using the received certificate chain. + 1. All connections within an App that disables TrustKit's network delegate swizzling by setting the `kTSKSwizzleNetworkDelegates` configuration key to `NO`. + 2. Connections that do not rely on the `NSURLConnection` or `NSURLSession` APIs: + * Connections leveraging lower-level APIs (such as `NSStream`). Instructions on how to retrieve the server's trust object are available at https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html. + * Connections initiated using a third-party SSL library such as OpenSSL. The server's trust object needs to be built using the received certificate chain. + 3. Connections happening within an external process: + * `WKWebView` connections: the server's trust object can be retrieved and validated within the `webView:didReceiveAuthenticationChallenge:completionHandler:` method. + * `NSURLSession` connections using the background transfer service: the server's trust object can be retrieved and validated within the `application:handleEventsForBackgroundURLSession:completionHandler:` method. + + For example, `TSKPinningValidator` should be used as follow when verifying the server's identity within an `NSURLSession` or `WKWebView` authentication handler: + + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) + { + // Check the trust object against the pinning policy + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + NSString *serverHostname = challenge.protectionSpace.host; + + TSKTrustDecision trustDecision = [TSKPinningValidator evaluateTrust:serverTrust + forHostname:serverHostname]; + + if (trustDecision == TSKTrustDecisionShouldAllowConnection) + { + // Success + completionHandler(NSURLSessionAuthChallengeUseCredential, + [NSURLCredential credentialForTrust:serverTrust]); + } + else if (trustDecision == TSKTrustDecisionDomainNotPinned) + { + // Domain was not pinned; we need to do the default validation ourselves to avoid disabling + // SSL validation for all non pinned domains + SecTrustResultType trustResult = 0; + SecTrustEvaluate(serverTrust, &trustResult); + if ((trustResult != kSecTrustResultUnspecified) && (trustResult != kSecTrustResultProceed)) + { + // Default SSL validation failed - block the connection + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL); + } + else + { + // Default SSL validation succeeded + completionHandler(NSURLSessionAuthChallengeUseCredential, + [NSURLCredential credentialForTrust:serverTrust]); + } + } + else + { + // Pinning validation failed - block the connection + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, NULL); + } + } + */ @interface TSKPinningValidator : NSObject @@ -51,9 +111,11 @@ typedef NS_ENUM(NSInteger, TSKTrustDecision) @param serverHostname The hostname of the server whose identity is being validated. - @return The result of the validation. See `TSKPinValidationResult` for possible values. + @return A `TSKTrustDecision` which describes whether the SSL connection should be allowed or blocked, based on the global pinning policy. + + @warning If no SSL pinning policy was configured for the supplied _serverHostname_, this method has no effect and will return `TSKTrustDecisionDomainNotPinned` without validating the supplied _serverTrust_ at all. - @warning If no SSL pinning policy was configured for the supplied _serverHostname_, this method has no effect and will return `TSKPinValidationResultDomainNotPinned` without validating the supplied _serverTrust_ at all. + Because this will happen in an authentication handler, it means that the server's _serverTrust_ object __needs__ to be verified against the device's trust store using `SecTrustEvaluate()`. Failing to do so will __disable SSL certificate validation__. @exception NSException Thrown when TrustKit has not been initialized with a pinning policy. */ diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 7f227486..4d645953 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -38,9 +38,11 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; /** - `TrustKit` is a class for configuring the global SSL pinning policy in an App that statically links TrustKit. + `TrustKit` is a class for programmatically configuring the global SSL pinning policy within an App. - Initializing TrustKit requires supplying a dictionary containing domain names as keys and dictionaries as values. Each domain dictionary should specify some configuration keys, which will specify the pinning policy for this domain. For example: + A TrustKit SSL pinning policy is a dictionary which contains some global, App-wide settings as well as domain-specific configuration keys. The policy can be set either by adding it to the App's Info.plist under the _TSKConfiguration_ key, or by programmatically supplying it using the `TrustKit` class described here. Throughout the App's lifecycle, TrustKit can only be initialized once so only one of the two techniques should be used. + + When setting the pinning policy programmatically, it has to be supplied to the `initializeWithConfiguration:` method as a dictionnary. For example: NSDictionary *trustKitConfig; trustKitConfig = @{ @@ -66,29 +68,44 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; [TrustKit initializeWithConfiguration:trustKitConfig]; - It is also possible to supply the pinning policy by adding these configuration keys to the App's _Info.plist_ under a `TSKConfiguration` dictionary key. When doing so, no method needs to be called and TrustKit will automatically be initialized with the policy. + The various configuration keys that can be specified in the policy are described below. + + + ### Required Global Configuration Keys + + #### `kTSKPinnedDomains` + A dictionary with domains (such as _www.domain.com_) as keys and dictionaries as values. + + Each entry should contain domain-specific settings for performing pinning validation when connecting to the domain, including for example the domain's public key hashes. A list of all domain-specific keys is available in the "Domain-specific Keys" sections. + + + ### Optional Global Configuration Keys + #### `kTSKSwizzleNetworkDelegates` + If set to `YES`, TrustKit will perform method swizzling on the App's `NSURLConnection` and `NSURLSession` delegates in order to automatically add SSL pinning validation to the App's connections; default value is `YES`. - ### Global Configuration Keys + Swizzling might clash with anti-tampering mechanisms, as well as analytics SDKs that also perform swizzling of the App's network delegates. In such scenarios or if the developer wants a tigher control on the App's networking behavior, `kTSKSwizzleNetworkDelegates` should be set to `NO`; the developer should then manually add pinning validation to the App's authentication handlers. - #### `kTSKPinnedDomains` (required) - TBD + See the `TSKPinningValidator` class for instructions on how to do so. - #### `kTSKSwizzleNetworkDelegates` (optional) - TBD - #### `kTSKIgnorePinningForUserDefinedTrustAnchors` (optional - OS X only) + #### `kTSKIgnorePinningForUserDefinedTrustAnchors` (OS X only) If set to `YES`, pinning validation will be skipped if the server's certificate chain terminates at a user-defined trust anchor (such as a root CA that isn't part of OS X's default trust store) and no pin failure reports will be sent; default value is `YES`. + This is useful for allowing SSL connections through corporate proxies or firewalls. See "How does key pinning interact with local proxies and filters?" within the Chromium security FAQ at https://www.chromium.org/Home/chromium-security/security-faq for more information. ### Required Domain-specific Keys #### `kTSKPublicKeyHashes` - An array of SSL pins; each pin is the base64-encoded SHA-256 hash of a certificate's Subject Public Key Info. TrustKit will verify that at least one of the specified pins is found in the server's evaluated certificate chain. + An array of SSL pins, where each pin is the base64-encoded SHA-256 hash of a certificate's Subject Public Key Info. + + TrustKit will verify that at least one of the specified pins is found in the server's evaluated certificate chain. #### `kTSKPublicKeyAlgorithms` - An array of `kTSKAlgorithm` constants to specify the public key algorithms for the keys to be pinned. TrustKit requires this information in order to compute SSL pins when validating a server's certificate chain, because there are no APIs to directly extract the key's algorithm from an SSL certificate. To minimize the performance impact of Trustkit, only one algorithm should be enabled. + An array of `kTSKAlgorithm` constants to specify the public key algorithms for the keys to be pinned. + + TrustKit requires this information in order to compute SSL pins when validating a server's certificate chain, because the `Security` framework does not provide APIs to extract the key's algorithm from an SSL certificate. To minimize the performance impact of Trustkit, only one algorithm should be enabled. ### Optional Domain-specific Keys @@ -97,14 +114,19 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; If set to `YES`, also pin all the subdomains of the specified domain; default value is `NO`. #### `kTSKEnforcePinning` - If set to `NO`, TrustKit will not block SSL connections that caused a pin or certificate validation error; default value is `YES`. When verifying a server's identity, TrustKit validates the server's certificate chain and also checks for the presence of one of the configured SSL pins. When a pinning failure occurs, pin failure reports will still be sent to the configured report URIs. + If set to `NO`, TrustKit will not block SSL connections that caused a pin or certificate validation error; default value is `YES`. + + When a pinning failure occurs, pin failure reports will always be sent to the configured report URIs regardless of the value of `kTSKEnforcePinning`. #### `kTSKReportUris` - An array of URLs to which pin validation failures should be reported. To minimize the performance impact of sending reports on each validation failure, the reports are uploaded using the background transfer service. For HTTPS report URLs, the HTTPS connections will ignore the SSL pinning policy and use the default certificate validation mechanisms, in order to maximize the chance of the reports reaching the server. The format of the reports is similar to the one described in RFC 7469 for the HPKP specification: + An array of URLs to which pin validation failures should be reported. + + To minimize the performance impact of sending reports on each validation failure, the reports are uploaded using the background transfer service and are also rate-limited to one per day and per type of failure. For HTTPS report URLs, the HTTPS connections will ignore the SSL pinning policy and use the default certificate validation mechanisms, in order to maximize the chance of the reports reaching the server. The format of the reports is similar to the one described in RFC 7469 for the HPKP specification: { "app-bundle-id":"com.example.ABC", "app-version":"1.0", + "app-identifier":"599F9C00-92DC-4B5C-9464-7971F01F8370", "date-time": "2015-07-10T20:03:14Z", "hostname": "mail.example.com", "port": 0, @@ -123,7 +145,8 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; #### `kTSKDisableDefaultReportUri` If set to `YES`, the default report URL for sending pin failure reports will be disabled; default value is `NO`. - By default, pin failure reports are sent to a report server hosted by Data Theorem, for detecting potential CA compromises and man-in-the-middle attacks, as well as providing a free dashboard for developers. Only pin failure reports are sent, which contain the App's bundle ID and the server's hostname and certificate chain that failed validation. + + By default, pin failure reports are sent to a report server hosted by Data Theorem, for detecting potential CA compromises and man-in-the-middle attacks, as well as providing a free dashboard for developers. Only pin failure reports are sent, which contain the App's bundle ID, the IDFV, and the server's hostname and certificate chain that failed validation. ### Public Key Algorithms Keys diff --git a/docs/api-doc-index.md b/docs/api-doc-index.md index f1775ed3..26f72009 100755 --- a/docs/api-doc-index.md +++ b/docs/api-doc-index.md @@ -8,7 +8,6 @@ https://datatheorem.github.io/TrustKit . TrustKit requires iOS 7+ or OS X 10.9+ as the minimum deployment target and provides two classes: -* TrustKit, for configuring the global SSL pinning policy within an App. +* TrustKit, for programmatically configuring the global SSL pinning policy within an App. * TSKPinningValidator, for manually validating a certificate chain against the -configured pinning policy. This class only needs to be used for connections -that are not automatically intercepted by TrustKit. +configured pinning policy. From 23ad10f93621e5bfa91af06f317c1940061ca4f5 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 13 Oct 2015 00:02:34 -0700 Subject: [PATCH 059/118] Tweak documentation --- TrustKit/Pinning/TSKPinningValidator.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.h b/TrustKit/Pinning/TSKPinningValidator.h index 59566074..b8afde12 100644 --- a/TrustKit/Pinning/TSKPinningValidator.h +++ b/TrustKit/Pinning/TSKPinningValidator.h @@ -42,9 +42,11 @@ typedef NS_ENUM(NSInteger, TSKTrustDecision) /** `TSKPinningValidator` is a class for manually verifying a server's identity against the global SSL pinning policy. - In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's trust object, which contains its certificate chain, needs to be retrieved or built before being passed to `TSKPinningValidator` for validation. + In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's trust object, which contains its certificate chain, needs to be retrieved or built before being passed to `TSKPinningValidator` for validation. - The following scenarios require manual pin validation: + `TSKPinningValidator` returns a `TSKTrustDecision` which describes whether the SSL connection should be allowed or blocked, based on the global pinning policy. + + The following connections require manual pin validation: 1. All connections within an App that disables TrustKit's network delegate swizzling by setting the `kTSKSwizzleNetworkDelegates` configuration key to `NO`. 2. Connections that do not rely on the `NSURLConnection` or `NSURLSession` APIs: @@ -74,7 +76,7 @@ typedef NS_ENUM(NSInteger, TSKTrustDecision) else if (trustDecision == TSKTrustDecisionDomainNotPinned) { // Domain was not pinned; we need to do the default validation ourselves to avoid disabling - // SSL validation for all non pinned domains + // SSL validation for all non-pinned domains SecTrustResultType trustResult = 0; SecTrustEvaluate(serverTrust, &trustResult); if ((trustResult != kSecTrustResultUnspecified) && (trustResult != kSecTrustResultProceed)) From 0824ef760f9466cd560aedb592656f05df431025 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 13 Oct 2015 18:24:03 -0700 Subject: [PATCH 060/118] Update documentation --- docs/getting-started.md | 110 +++++++++++++++++++++++++--------------- docs/sample_report.json | 1 + 2 files changed, 70 insertions(+), 41 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 60bc8886..7bd809ad 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -64,9 +64,15 @@ a pinning policy to TrustKit: * By storing the pinning policy in the App's _Info.plist_; this approach allows deploying TrustKit without having to modify the App's source code. -After initialization, TrustKit will intercept the App's outgoing SSL -connections, in order to perform additional validation against the server's -certificate chain based on the configured SSL pinning policy. +After initialization, TrustKit will by default perform method swizzling on the +App's `NSURLSession` and `NSURLConnection` delegates in order to perform additional +validation against the server's certificate chain, based on the configured SSL pinning +policy. + +If the developer wants a tighter control on the App's networking behavior or does +not want auto-swizzling, it can be disabled by setting `kTSKSwizzleNetworkDelegates` to `NO`. +Manual pinning validation can then be implemented in the App's authentication handlers' using the +[TSKPinningValidator class](https://datatheorem.github.io/TrustKit/documentation/Classes/TSKPinningValidator.html). ### Adding TrustKit as a Dependency - CocoaPods @@ -102,42 +108,61 @@ corresponding certificates' public key algorithms. For example: #import "TrustKit.h" - NSDictionary *trustKitConfig; - trustKitConfig = @{ - @"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[ - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", - @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" - ] - }, - @"yahoo.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[ - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", - ] - } - }; + NSDictionary *trustKitConfig = + @{ + // Auto-swizzle NSURLSession and NSURLConnection delegates to add pinning validation + kTSKSwizzleNetworkDelegates: @YES, + + // The list of domains we want to pin and their configuration + kTSKPinnedDomains: @{ + + @"yahoo.com" : @{ + // Pin all subdomains of yahoo.com + kTSKIncludeSubdomains:@YES, + + // Do not block connections if pinning validation failed so the App doesn't break + kTSKEnforcePinning:@YES, + + // Send reports for pin validation failures so we can track them + kTSKReportUris: @[@"https://trustkit-reports-server.appspot.com/log_report"], + + // The pinned public keys' algorithms + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + + // The pinned public keys' Subject Public Key Info hashes + kTSKPublicKeyHashes : @[ + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", + ], + }, + + @"www.datatheorem.com" : @{ + // Block connections if pinning validation failed + kTSKEnforcePinning:@YES, + + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + + kTSKPublicKeyHashes : @[ + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", + @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" + ] + }}}; To avoid locking out too many users from your App when deploying SSL pinning -for the first time, a more elaborate policy can be enabled using the following -configuration keys: +for the first time, it is advisable to set `kTSKEnforcePinning` to `NO`, so that SSL +connections will succeed regardless of pin validation. -* Setting `kTSKEnforcePinning` to `NO`, so that SSL connections will succeed -regardless of pin validation. -* Adding a report URL using the `kTSKReportUris` setting to receive pin -validation failure reports. +Also, adding a report URL using the `kTSKReportUris` setting to receive pin validation failure +reports will help track these failures. You can use your own report server or Data Theorem +(info@datatheorem.com) provides a dashboard to display these reports for free. -This will allow the App to work regardless of pin validation failures, but the -reports will give you an idea of how many users would be blocked, if pin -validation was to be enforced. +This will give you an idea of how many users would be blocked, if pin validation was to be enforced. The list of all the configuration keys is available in the [documentation](https://datatheorem.github.io/TrustKit/documentation/Classes/TrustKit.html). -After supplying the pinning policy, all of the App's SSL connections will enforce -the policy. +After supplying the pinning policy, and if `kTSKSwizzleNetworkDelegates` is set to `YES`, all of +the App's `NSURLConnection` and `NSURLSession` delegates will automatically enforce the policy. ### Adding TrustKit as a Dependency - Static Linking @@ -185,14 +210,17 @@ dynamically linked. Manual Pin Validation --------------------- -In a few specific scenarios, TrustKit cannot intercept outgoing SSL connections -and automatically validate the server's identity against the pinning policy. -This includes for example connections initiated by external processes (such as -`NSURLSession`'s background transfer service) or through third-party SSL -libraries (such as OpenSSL). - -For these connections, the pin validation must be -triggered manually; see the documentation for the [TSKPinningValidator -class](https://datatheorem.github.io/TrustKit/documentation/Classes/TSKPinningValidator.html) -for more details. +In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's trust object, which contains its certificate chain, needs to be retrieved or built before being passed to the [TSKPinningValidator class](https://datatheorem.github.io/TrustKit/documentation/Classes/TSKPinningValidator.html) for validation. + + `TSKPinningValidator` returns a `TSKTrustDecision` which describes whether the SSL connection should be allowed or blocked, based on the global pinning policy. + + The following connections require manual pin validation: + + 1. All connections within an App that disables TrustKit's network delegate swizzling by setting the `kTSKSwizzleNetworkDelegates` configuration key to `NO`. + 2. Connections that do not rely on the `NSURLConnection` or `NSURLSession` APIs: + * Connections leveraging lower-level APIs (such as `NSStream`). Instructions on how to retrieve the server's trust object are available at https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html. + * Connections initiated using a third-party SSL library such as OpenSSL. The server's trust object needs to be built using the received certificate chain. + 3. Connections happening within an external process: + * `WKWebView` connections: the server's trust object can be retrieved and validated within the `webView:didReceiveAuthenticationChallenge:completionHandler:` method. + * `NSURLSession` connections using the background transfer service: the server's trust object can be retrieved and validated within the `application:handleEventsForBackgroundURLSession:completionHandler:` method. diff --git a/docs/sample_report.json b/docs/sample_report.json index 190d9cf1..f23e81dd 100644 --- a/docs/sample_report.json +++ b/docs/sample_report.json @@ -14,5 +14,6 @@ "pin-sha256=\"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=\"" ], "app-bundle-id": "com.datatheorem.testtrustkit2", + "app-identifier": "599F9C00-92DC-4B5C-9464-7971F01F8370", "port": 443 } From 9e1a3ebfeb132c57fe2ae13d64f6f69fce1292eb Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 13 Oct 2015 22:19:51 -0700 Subject: [PATCH 061/118] Update documentation --- TrustKit/Pinning/TSKPinningValidator.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.h b/TrustKit/Pinning/TSKPinningValidator.h index b8afde12..f4fa223c 100644 --- a/TrustKit/Pinning/TSKPinningValidator.h +++ b/TrustKit/Pinning/TSKPinningValidator.h @@ -42,7 +42,7 @@ typedef NS_ENUM(NSInteger, TSKTrustDecision) /** `TSKPinningValidator` is a class for manually verifying a server's identity against the global SSL pinning policy. - In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's trust object, which contains its certificate chain, needs to be retrieved or built before being passed to `TSKPinningValidator` for validation. + In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's `SecTrustRef` object, which contains its certificate chain, needs to be retrieved or built before being passed to `TSKPinningValidator` for validation. `TSKPinningValidator` returns a `TSKTrustDecision` which describes whether the SSL connection should be allowed or blocked, based on the global pinning policy. @@ -51,10 +51,10 @@ typedef NS_ENUM(NSInteger, TSKTrustDecision) 1. All connections within an App that disables TrustKit's network delegate swizzling by setting the `kTSKSwizzleNetworkDelegates` configuration key to `NO`. 2. Connections that do not rely on the `NSURLConnection` or `NSURLSession` APIs: * Connections leveraging lower-level APIs (such as `NSStream`). Instructions on how to retrieve the server's trust object are available at https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html. - * Connections initiated using a third-party SSL library such as OpenSSL. The server's trust object needs to be built using the received certificate chain. + * Connections initiated using a third-party SSL library such as OpenSSL. The server's `SecTrustRef` object needs to be built using the received certificate chain. 3. Connections happening within an external process: - * `WKWebView` connections: the server's trust object can be retrieved and validated within the `webView:didReceiveAuthenticationChallenge:completionHandler:` method. - * `NSURLSession` connections using the background transfer service: the server's trust object can be retrieved and validated within the `application:handleEventsForBackgroundURLSession:completionHandler:` method. + * `WKWebView` connections: the server's `SecTrustRef` object can be retrieved and validated within the `webView:didReceiveAuthenticationChallenge:completionHandler:` method. + * `NSURLSession` connections using the background transfer service: the server's `SecTrustRef` object can be retrieved and validated within the `application:handleEventsForBackgroundURLSession:completionHandler:` method. For example, `TSKPinningValidator` should be used as follow when verifying the server's identity within an `NSURLSession` or `WKWebView` authentication handler: From 1cf9388064a128fe37eb7d8b82f0853a0e3b084b Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 13 Oct 2015 22:19:57 -0700 Subject: [PATCH 062/118] Clarify comment --- TrustKitDemo/TrustKitDemo/AppDelegate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKitDemo/TrustKitDemo/AppDelegate.m b/TrustKitDemo/TrustKitDemo/AppDelegate.m index d3524fce..ac512fcb 100644 --- a/TrustKitDemo/TrustKitDemo/AppDelegate.m +++ b/TrustKitDemo/TrustKitDemo/AppDelegate.m @@ -47,7 +47,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( }, - // Pin valid SPKI hashes to *.datatheorem.com to demonstrate success + // Pin valid SPKI hashes to www.datatheorem.com to demonstrate success @"www.datatheorem.com" : @{ kTSKEnforcePinning:@YES, kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], From a5745749e1db2c3f170c518a462d41a1ca783a35 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 13:09:07 -0700 Subject: [PATCH 063/118] Update documentation --- TrustKit/TrustKit.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 4d645953..f003c0af 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -39,8 +39,23 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; /** `TrustKit` is a class for programmatically configuring the global SSL pinning policy within an App. - - A TrustKit SSL pinning policy is a dictionary which contains some global, App-wide settings as well as domain-specific configuration keys. The policy can be set either by adding it to the App's Info.plist under the _TSKConfiguration_ key, or by programmatically supplying it using the `TrustKit` class described here. Throughout the App's lifecycle, TrustKit can only be initialized once so only one of the two techniques should be used. + + The policy can be set either by adding it to the App's _Info.plist_ under the `TSKConfiguration` key, or by programmatically supplying it using the `TrustKit` class described here. Throughout the App's lifecycle, TrustKit can only be initialized once so only one of the two techniques should be used. + + A TrustKit SSL pinning policy is a dictionary which contains some global, App-wide settings as well as domain-specific configuration keys. The following table shows the keys and their types, and uses indentation to indicate structure: + + | Key | Type | + |----------------------------------------------|------------| + | `TSKSwizzleNetworkDelegates` | Boolean | + | `TSKIgnorePinningForUserDefinedTrustAnchors` | Boolean | + | `TSKPinnedDomains` | Dictionary | + | ── `` | Dictionary | + | ──── `TSKPublicKeyHashes` | Array | + | ──── `TSKPublicKeyAlgorithms` | Array | + | ──── `TSKIncludeSubdomains` | Boolean | + | ──── `TSKEnforcePinning` | Boolean | + | ──── `TSKReportUris` | Array | + | ──── `kTSKDisableDefaultReportUri` | Boolean | When setting the pinning policy programmatically, it has to be supplied to the `initializeWithConfiguration:` method as a dictionnary. For example: From d4f3be4b8f308aed5dd1c6616d285e7068142b4f Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 17:32:41 -0700 Subject: [PATCH 064/118] Clarify documentation --- TrustKit/TrustKit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index f003c0af..84cb674d 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -99,7 +99,7 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; #### `kTSKSwizzleNetworkDelegates` If set to `YES`, TrustKit will perform method swizzling on the App's `NSURLConnection` and `NSURLSession` delegates in order to automatically add SSL pinning validation to the App's connections; default value is `YES`. - Swizzling might clash with anti-tampering mechanisms, as well as analytics SDKs that also perform swizzling of the App's network delegates. In such scenarios or if the developer wants a tigher control on the App's networking behavior, `kTSKSwizzleNetworkDelegates` should be set to `NO`; the developer should then manually add pinning validation to the App's authentication handlers. + Swizzling allows enabling pinning within an App without having to find and modify each and every instance of `NSURLConnection` or `NSURLSession` delegates. However, it might clash with anti-tampering mechanisms, as well as analytics SDKs that also perform swizzling of the App's network delegates. In such scenarios or if the developer wants a tigher control on the App's networking behavior, `kTSKSwizzleNetworkDelegates` should be set to `NO`; the developer should then manually add pinning validation to the App's authentication handlers. See the `TSKPinningValidator` class for instructions on how to do so. From 28239421ab3362528fca91111dbebead272c1775 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 18:11:04 -0700 Subject: [PATCH 065/118] Update podspec --- TrustKit.podspec | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/TrustKit.podspec b/TrustKit.podspec index 721dade3..649bf251 100644 --- a/TrustKit.podspec +++ b/TrustKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "TrustKit" - s.version = "1.1.3" + s.version = "1.2.0" s.summary = 'TrustKit is an open source framework that makes it easy to deploy SSL pinning in any iOS or OS X App.' s.homepage = "https://datatheorem.github.io/TrustKit" s.documentation_url = 'https://datatheorem.github.io/TrustKit/documentation/' @@ -12,6 +12,7 @@ Pod::Spec.new do |s| s.source_files = 'TrustKit', 'TrustKit/**/*.{h,m}', 'TrustKit/Dependencies/fishhook/*.{h,c}' s.public_header_files = 'TrustKit/TrustKit.h', 'TrustKit/Pinning/TSKPinningValidator.h' s.frameworks = 'Foundation', 'Security' - s.vendored_libraries = 'TrustKit/Dependencies/domain_registry/*.a' + s.ios.vendored_libraries = 'TrustKit/Dependencies/domain_registry/ios/*.a' + s.osx.vendored_libraries = 'TrustKit/Dependencies/domain_registry/osx/*.a' s.requires_arc = true end From 000742357ae861650db202bb90ef7b2a2e913f7e Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 18:15:50 -0700 Subject: [PATCH 066/118] Make TSKPinningValidator.h a public header --- TrustKit.xcodeproj/project.pbxproj | 4 ++-- TrustKit/TrustKit+Private.h | 2 +- TrustKit/TrustKit.h | 1 + TrustKit/TrustKit.m | 2 -- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 6bb42107..2070c69c 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -18,7 +18,7 @@ 6B032D401AF1AEC200EAFA69 /* TSKReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */; }; 6B2B06AD1B05154A00FC749E /* TSKBackgroundReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B2B06AC1B05154A00FC749E /* TSKBackgroundReporter.h */; }; 6B2B06AF1B05157400FC749E /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */; }; - 8C15F9931B132F9200F06C0E /* TSKPinningValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F9911B132F9200F06C0E /* TSKPinningValidator.h */; }; + 8C15F9931B132F9200F06C0E /* TSKPinningValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F9911B132F9200F06C0E /* TSKPinningValidator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8C15F9941B132F9200F06C0E /* TSKPinningValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F9921B132F9200F06C0E /* TSKPinningValidator.m */; }; 8C15F9A01B16094D00F06C0E /* TSKPinFailureReport.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F99E1B16094D00F06C0E /* TSKPinFailureReport.h */; }; 8C15F9A11B16094E00F06C0E /* TSKPinFailureReport.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F99F1B16094D00F06C0E /* TSKPinFailureReport.m */; }; @@ -476,6 +476,7 @@ buildActionMask = 2147483647; files = ( 8CE9192D1AEA0F7E002B29AE /* domain_registry.h in Headers */, + 8C15F9931B132F9200F06C0E /* TSKPinningValidator.h in Headers */, 8CD5F7491BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */, 8CE9191E1AEA073C002B29AE /* public_key_utils.h in Headers */, 6B2B06AD1B05154A00FC749E /* TSKBackgroundReporter.h in Headers */, @@ -483,7 +484,6 @@ 8C9EBE021B619BBE00CA7EE0 /* TSKReportsRateLimiter.h in Headers */, 6B032D3E1AF1A4AC00EAFA69 /* TSKSimpleReporter.h in Headers */, 8CD5F7421BCB06F4005801D8 /* RSSwizzle.h in Headers */, - 8C15F9931B132F9200F06C0E /* TSKPinningValidator.h in Headers */, 8C9492F61B2379A100F5DF38 /* reporting_utils.h in Headers */, 8C84804D1A896EE30017C155 /* TrustKit.h in Headers */, 8C15F9A01B16094D00F06C0E /* TSKPinFailureReport.h in Headers */, diff --git a/TrustKit/TrustKit+Private.h b/TrustKit/TrustKit+Private.h index 9c7e2d1e..6d7eb353 100644 --- a/TrustKit/TrustKit+Private.h +++ b/TrustKit/TrustKit+Private.h @@ -12,7 +12,7 @@ #ifndef TrustKit_TrustKit_Private____FILEEXTENSION___ #define TrustKit_TrustKit_Private____FILEEXTENSION___ -#import "TrustKit.h" +#import #import "ssl_pin_verifier.h" NSDictionary *parseTrustKitArguments(NSDictionary *TrustKitArguments); diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 84cb674d..f5db5b4a 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -10,6 +10,7 @@ */ #import +#import //! Project version number for TrustKit. FOUNDATION_EXPORT double TrustKitVersionNumber; diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index a981b229..4c847415 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -10,9 +10,7 @@ */ #import "TrustKit+Private.h" -#include #import -#import "fishhook.h" #import "public_key_utils.h" #import "domain_registry.h" #import "TSKBackgroundReporter.h" From d530d1fe03dd2ce79615fc2270425987d274cde0 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 18:52:46 -0700 Subject: [PATCH 067/118] Tweak documentation, add example in swift --- TrustKit/TrustKit.h | 30 ++++++++++++++++++++++-------- docs/getting-started.md | 2 +- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index f5db5b4a..b439a3c2 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -50,13 +50,13 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; | `TSKSwizzleNetworkDelegates` | Boolean | | `TSKIgnorePinningForUserDefinedTrustAnchors` | Boolean | | `TSKPinnedDomains` | Dictionary | - | ── `` | Dictionary | - | ──── `TSKPublicKeyHashes` | Array | - | ──── `TSKPublicKeyAlgorithms` | Array | - | ──── `TSKIncludeSubdomains` | Boolean | - | ──── `TSKEnforcePinning` | Boolean | - | ──── `TSKReportUris` | Array | - | ──── `kTSKDisableDefaultReportUri` | Boolean | + | __ `` | Dictionary | + | ____ `TSKPublicKeyHashes` | Array | + | ____ `TSKPublicKeyAlgorithms` | Array | + | ____ `TSKIncludeSubdomains` | Boolean | + | ____ `TSKEnforcePinning` | Boolean | + | ____ `TSKReportUris` | Array | + | ____ `kTSKDisableDefaultReportUri` | Boolean | When setting the pinning policy programmatically, it has to be supplied to the `initializeWithConfiguration:` method as a dictionnary. For example: @@ -82,7 +82,21 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; } }}; - [TrustKit initializeWithConfiguration:trustKitConfig]; + [TrustKit initializeWithConfiguration:trustKitConfig]; + + Similarly, TrustKit can be initialized in Swift: + + let trustKitConfig = [ + kTSKPinnedDomains: [ + "yahoo.com": [ + kTSKPublicKeyAlgorithms: [kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes: [ + "JbQbUG5JMJUoI6brnx0x3vZF6jilxsapbXGVfjhN8Fg=", + "WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=" + ],]]] + + TrustKit.initializeWithConfiguration(config) + The various configuration keys that can be specified in the policy are described below. diff --git a/docs/getting-started.md b/docs/getting-started.md index 7bd809ad..02e4d7e1 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -106,7 +106,7 @@ A pinning policy is a dictionary of domain names and pinning configuration keys. At a minimum, the configuration should specify a list of SSL pins and the corresponding certificates' public key algorithms. For example: - #import "TrustKit.h" + #import NSDictionary *trustKitConfig = @{ From 496db9fa226ad668749f22c472a8ae60a18930cc Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 18:58:33 -0700 Subject: [PATCH 068/118] Tweak travis file --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b6b01de8..153fa993 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: objective-c osx_image: xcode7 env: matrix: - - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" + - TEST_SDK=macosx10.11 TEST_SCHEME='TrustKit OS X' - TEST_SDK=iphonesimulator9.0 TEST_SCHEME="TrustKit" script: - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From 205468607944f3ea6e8e149acc2e20c692e85cad Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 19:01:04 -0700 Subject: [PATCH 069/118] Tweak travis file --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 153fa993..ed7729aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,8 @@ language: objective-c osx_image: xcode7 env: matrix: - - TEST_SDK=macosx10.11 TEST_SCHEME='TrustKit OS X' - - TEST_SDK=iphonesimulator9.0 TEST_SCHEME="TrustKit" + - TEST_SDK=macosx10.11 TEST_SCHEME=TrustKit OS X + - TEST_SDK=iphonesimulator9.0 TEST_SCHEME=TrustKit script: - - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - - xcodebuild build test -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild clean -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild build test -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From fd82904dec10ffc4d9e576cac2fae180facb97f8 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 19:10:14 -0700 Subject: [PATCH 070/118] Add utility test method --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 5 +++++ TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m | 6 ++++++ TrustKitTests/TSKNSURLConnectionTests.m | 4 ++++ TrustKitTests/TSKNSURLSessionTests.m | 4 ++++ 4 files changed, 19 insertions(+) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 869f7780..94637761 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -26,6 +26,11 @@ -(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChal @implementation TSKNSURLConnectionDelegateProxy +// Private methods used for tests ++(void)resetLastTrustDecision +{ + lastTrustDecision = -1;; +} +(TSKTrustDecision)getLastTrustDecision { diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 614fd99c..5f9ecc1b 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -18,6 +18,12 @@ @implementation TSKNSURLSessionDelegateProxy +// Private methods used for tests ++(void)resetLastTrustDecision +{ + lastTrustDecision = -1;; +} + +(TSKTrustDecision)getLastTrustDecision { return lastTrustDecision; diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index 401758cd..b935ea9a 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -13,7 +13,10 @@ #pragma mark Private test methods @interface TSKNSURLConnectionDelegateProxy(Private) + +(TSKPinValidationResult)getLastTrustDecision; ++(void)resetLastTrustDecision; + @end @@ -139,6 +142,7 @@ @implementation TSKNSURLConnectionTests - (void)setUp { [super setUp]; [TrustKit resetConfiguration]; + [TSKNSURLConnectionDelegateProxy resetLastTrustDecision]; } - (void)tearDown { diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index 70f06f47..70114731 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -13,7 +13,10 @@ #pragma mark Private test methods @interface TSKNSURLSessionDelegateProxy(Private) + +(TSKPinValidationResult)getLastTrustDecision; ++(void)resetLastTrustDecision; + @end @@ -138,6 +141,7 @@ @implementation TSKNSURLSessionTests - (void)setUp { [super setUp]; [TrustKit resetConfiguration]; + [TSKNSURLSessionDelegateProxy resetLastTrustDecision]; } - (void)tearDown { From f654c95865422ac24840a7317c6f50f2be16703a Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 19:20:34 -0700 Subject: [PATCH 071/118] Change test domains to deal with TLS caching issues --- TrustKitTests/TSKNSURLSessionTests.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index 70114731..fb152b7d 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -288,17 +288,17 @@ - (void)testNoDelegateWarnings NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil]; - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; [task resume]; // Start a session with +sessionWithConfiguration: NSURLSession *session2 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; - NSURLSessionDataTask *task2 = [session2 dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + NSURLSessionDataTask *task2 = [session2 dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; [task2 resume]; // Start a session with +sharedSession NSURLSession *session3 = [NSURLSession sharedSession]; - NSURLSessionDataTask *task3 = [session3 dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + NSURLSessionDataTask *task3 = [session3 dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; [task3 resume]; } @@ -327,7 +327,7 @@ - (void)testTaskDidReceiveChallengeGetsCalled delegate:delegate delegateQueue:nil]; - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; [task resume]; [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { @@ -364,7 +364,7 @@ - (void)testSessionDidReceiveChallengeGetsCalled delegate:delegate delegateQueue:nil]; - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; [task resume]; [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { From 543441234442877645ee643e7e016a8730772f03 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 19:33:24 -0700 Subject: [PATCH 072/118] Add nullability attributes --- TrustKit/Pinning/TSKPinningValidator.h | 2 +- TrustKit/Pinning/TSKPinningValidator.m | 2 +- TrustKit/TrustKit.h | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.h b/TrustKit/Pinning/TSKPinningValidator.h index f4fa223c..31c27704 100644 --- a/TrustKit/Pinning/TSKPinningValidator.h +++ b/TrustKit/Pinning/TSKPinningValidator.h @@ -121,6 +121,6 @@ typedef NS_ENUM(NSInteger, TSKTrustDecision) @exception NSException Thrown when TrustKit has not been initialized with a pinning policy. */ -+ (TSKTrustDecision) evaluateTrust:(SecTrustRef)serverTrust forHostname:(NSString *)serverHostname; ++ (TSKTrustDecision) evaluateTrust:(SecTrustRef _Nonnull)serverTrust forHostname:(NSString * _Nonnull)serverHostname; @end diff --git a/TrustKit/Pinning/TSKPinningValidator.m b/TrustKit/Pinning/TSKPinningValidator.m index e319b85d..dda17afa 100644 --- a/TrustKit/Pinning/TSKPinningValidator.m +++ b/TrustKit/Pinning/TSKPinningValidator.m @@ -17,7 +17,7 @@ @implementation TSKPinningValidator -+ (TSKTrustDecision) evaluateTrust:(SecTrustRef)serverTrust forHostname:(NSString *)serverHostname ++ (TSKTrustDecision) evaluateTrust:(SecTrustRef _Nonnull)serverTrust forHostname:(NSString * _Nonnull)serverHostname { if ([TrustKit wasTrustKitInitialized] == NO) { diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index b439a3c2..a018c9d4 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -21,21 +21,21 @@ FOUNDATION_EXPORT const unsigned char TrustKitVersionString[]; #pragma mark TrustKit Configuration Keys -FOUNDATION_EXPORT const NSString *kTSKSwizzleNetworkDelegates; -FOUNDATION_EXPORT const NSString *kTSKPinnedDomains; -FOUNDATION_EXPORT const NSString *kTSKPublicKeyHashes; -FOUNDATION_EXPORT const NSString *kTSKEnforcePinning; -FOUNDATION_EXPORT const NSString *kTSKIncludeSubdomains; -FOUNDATION_EXPORT const NSString *kTSKPublicKeyAlgorithms; -FOUNDATION_EXPORT const NSString *kTSKReportUris; -FOUNDATION_EXPORT const NSString *kTSKDisableDefaultReportUri; -FOUNDATION_EXPORT const NSString *kTSKIgnorePinningForUserDefinedTrustAnchors NS_AVAILABLE_MAC(10_9); +FOUNDATION_EXPORT const NSString * _Nonnull kTSKSwizzleNetworkDelegates; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKPinnedDomains; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKPublicKeyHashes; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKEnforcePinning; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKIncludeSubdomains; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKPublicKeyAlgorithms; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKReportUris; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKDisableDefaultReportUri; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKIgnorePinningForUserDefinedTrustAnchors NS_AVAILABLE_MAC(10_9); #pragma mark Supported Public Key Algorithm Keys -FOUNDATION_EXPORT const NSString *kTSKAlgorithmRsa2048; -FOUNDATION_EXPORT const NSString *kTSKAlgorithmRsa4096; -FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmRsa2048; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmRsa4096; +FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmEcDsaSecp256r1; /** @@ -205,7 +205,7 @@ FOUNDATION_EXPORT const NSString *kTSKAlgorithmEcDsaSecp256r1; @exception NSException Thrown when the supplied configuration is invalid or TrustKit has already been initialized. */ -+ (void) initializeWithConfiguration:(NSDictionary *)trustKitConfig; ++ (void) initializeWithConfiguration:(nonnull NSDictionary *)trustKitConfig; @end From dc2b4bedb1a84c1ef501b3f381d9c0e9e9e77402 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 19:49:25 -0700 Subject: [PATCH 073/118] Fix tests and always swizzle --- .../TSKNSURLConnectionDelegateProxy.m | 22 +++++++++++++------ .../Swizzling/TSKNSURLSessionDelegateProxy.m | 2 +- TrustKitTests/TSKNSURLConnectionTests.m | 8 +++---- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 94637761..99a078e8 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -40,8 +40,6 @@ +(TSKTrustDecision)getLastTrustDecision + (void)swizzleNSURLConnectionConstructors { - static const void *swizzleOncekey = &swizzleOncekey; - // - initWithRequest:delegate: RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @selector(initWithRequest:delegate:), @@ -49,11 +47,21 @@ + (void)swizzleNSURLConnectionConstructors RSSWArguments(NSURLRequest *request, id delegate), RSSWReplacement( { - // Replace the delegate with our own so we can intercept and handle authentication challenges - TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; - NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate); + NSURLConnection *connection; + + if ([NSStringFromClass([delegate class]) hasPrefix:@"TSK"]) + { + // Don't proxy ourselves + connection = RSSWCallOriginal(request, delegate); + } + else + { + // Replace the delegate with our own so we can intercept and handle authentication challenges + TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; + connection = RSSWCallOriginal(request, swizzledDelegate); + } return connection; - }), RSSwizzleModeOncePerClass, swizzleOncekey); + }), RSSwizzleModeAlways, NULL); @@ -68,7 +76,7 @@ + (void)swizzleNSURLConnectionConstructors TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate, startImmediately); return connection; - }), RSSwizzleModeOncePerClass, swizzleOncekey); + }), RSSwizzleModeAlways, NULL); // Not hooking + connectionWithRequest:delegate: as it ends up calling initWithRequest:delegate: diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 5f9ecc1b..75e55046 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -62,7 +62,7 @@ + (void)swizzleNSURLSessionConstructors if (delegate == nil) { // Just display a warning - TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); + //TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); session = RSSWCallOriginal(configuration, delegate, queue); } diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index b935ea9a..a7e5c0d2 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -295,7 +295,7 @@ - (void)testPinningValidationSucceeded // Use -initWithRequest:delegate:startstartImmediately: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.datatheorem.com:443/"]] + [NSURL URLWithString:@"https://www.datatheorem.com/"]] delegate:delegate startImmediately:YES]; [connection start]; @@ -321,7 +321,7 @@ - (void)testNoDelegateWarnings @{ kTSKPinnedDomains : @{ - @"www.yahoo.com" : @{ + @"www.google.com" : @{ kTSKEnforcePinning : @YES, kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key @@ -333,14 +333,14 @@ - (void)testNoDelegateWarnings // Run other NSURLConnection methods that we swizzle to display a warning, to ensure they don't crash XCTestExpectation *expectation = [self expectationWithDescription:@"Asynchronous request"]; [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.datatheorem.com/test"]] + [NSURL URLWithString:@"https://www.google.com/test"]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { [expectation fulfill]; }]; [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.datatheorem.com/test"]] + [NSURL URLWithString:@"https://www.google.com/test"]] returningResponse:nil error:nil]; From aa8768427912cc3c6728b6a12ac6ad47f19da85a Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 21:56:50 -0700 Subject: [PATCH 074/118] Add more tests for TSKPinningValidator --- TrustKit.xcodeproj/project.pbxproj | 12 +- TrustKitTests/TSKPinValidationOfflineTests.m | 306 -------------- TrustKitTests/TSKPinningValidatorTests.m | 413 +++++++++++++++++++ 3 files changed, 419 insertions(+), 312 deletions(-) delete mode 100644 TrustKitTests/TSKPinValidationOfflineTests.m create mode 100644 TrustKitTests/TSKPinningValidatorTests.m diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 2070c69c..806ecfcb 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -11,7 +11,7 @@ 070868B71ADFFADF00E5AFDC /* GoodIntermediateCA.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868B11ADFF67200E5AFDC /* GoodIntermediateCA.der */; }; 070868B81ADFFADF00E5AFDC /* www.good.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868B21ADFF67200E5AFDC /* www.good.com.der */; }; 070868BB1AE1672D00E5AFDC /* www.good.com.selfsigned.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868BA1AE1672D00E5AFDC /* www.good.com.selfsigned.der */; }; - 075AA1091AC985FD00178223 /* TSKPinValidationOfflineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */; }; + 075AA1091AC985FD00178223 /* TSKPinningValidatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinningValidatorTests.m */; }; 0E64A7601B867BA000CA164A /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */; }; 6B032D3A1AF1794D00EAFA69 /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; }; 6B032D3E1AF1A4AC00EAFA69 /* TSKSimpleReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B032D3D1AF1A4AC00EAFA69 /* TSKSimpleReporter.h */; }; @@ -67,7 +67,7 @@ 8CA6CC351BAE2C1100BDA419 /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC321BAE2C1100BDA419 /* libassert_lib.a */; settings = {ASSET_TAGS = (); }; }; 8CA6CC361BAE2C1100BDA419 /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC331BAE2C1100BDA419 /* libdomain_registry_lib.a */; settings = {ASSET_TAGS = (); }; }; 8CA6CC371BAE2C1100BDA419 /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC341BAE2C1100BDA419 /* libinit_registry_tables_lib.a */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC391BAE2C7200BDA419 /* TSKPinningValidatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinningValidatorTests.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC3A1BAE2C7C00BDA419 /* TSKReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC3B1BAE2C7E00BDA419 /* TSKPinConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F9A31B17564400F06C0E /* TSKPinConfigurationTests.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC3C1BAE2C8100BDA419 /* TSKPublicKeyAlgorithmTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC78B241B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m */; settings = {ASSET_TAGS = (); }; }; @@ -154,7 +154,7 @@ 070868B41ADFF6B000E5AFDC /* GoodRootCA.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = GoodRootCA.der; sourceTree = ""; }; 070868BA1AE1672D00E5AFDC /* www.good.com.selfsigned.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = www.good.com.selfsigned.der; sourceTree = ""; }; 2FA286123F801C437F35D240 /* TrustKit+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TrustKit+Private.h"; sourceTree = ""; }; - 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKPinValidationOfflineTests.m; sourceTree = ""; }; + 2FA2868CAFECA46ADE0B6E3E /* TSKPinningValidatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKPinningValidatorTests.m; sourceTree = ""; }; 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKSimpleReporter.m; path = Reporting/TSKSimpleReporter.m; sourceTree = ""; }; 6B032D3D1AF1A4AC00EAFA69 /* TSKSimpleReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKSimpleReporter.h; path = Reporting/TSKSimpleReporter.h; sourceTree = ""; }; 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TSKReporterTests.m; sourceTree = ""; }; @@ -328,7 +328,7 @@ 070868B31ADFF68200E5AFDC /* Certificates */, 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */, 8CD5F7561BCB7219005801D8 /* TSKNSURLSessionTests.m */, - 2FA2868CAFECA46ADE0B6E3E /* TSKPinValidationOfflineTests.m */, + 2FA2868CAFECA46ADE0B6E3E /* TSKPinningValidatorTests.m */, 8C8480571A896EE30017C155 /* Supporting Files */, 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */, 8C15F9A31B17564400F06C0E /* TSKPinConfigurationTests.m */, @@ -734,7 +734,7 @@ files = ( 8CD5F7381BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */, 8C15F9A41B17564400F06C0E /* TSKPinConfigurationTests.m in Sources */, - 075AA1091AC985FD00178223 /* TSKPinValidationOfflineTests.m in Sources */, + 075AA1091AC985FD00178223 /* TSKPinningValidatorTests.m in Sources */, 8CC78B251B1B616500523A25 /* TSKPublicKeyAlgorithmTests.m in Sources */, 6B032D401AF1AEC200EAFA69 /* TSKReporterTests.m in Sources */, 8CD5F7571BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */, @@ -787,7 +787,7 @@ files = ( 8CD5F7391BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */, 8CA6CC3A1BAE2C7C00BDA419 /* TSKReporterTests.m in Sources */, - 8CA6CC391BAE2C7200BDA419 /* TSKPinValidationOfflineTests.m in Sources */, + 8CA6CC391BAE2C7200BDA419 /* TSKPinningValidatorTests.m in Sources */, 8CA6CC3C1BAE2C8100BDA419 /* TSKPublicKeyAlgorithmTests.m in Sources */, 8CA6CC3B1BAE2C7E00BDA419 /* TSKPinConfigurationTests.m in Sources */, 8CD5F7581BCB7219005801D8 /* TSKNSURLSessionTests.m in Sources */, diff --git a/TrustKitTests/TSKPinValidationOfflineTests.m b/TrustKitTests/TSKPinValidationOfflineTests.m deleted file mode 100644 index 3d64da40..00000000 --- a/TrustKitTests/TSKPinValidationOfflineTests.m +++ /dev/null @@ -1,306 +0,0 @@ -/* - - TSKPinValidationOfflineTests.m - TrustKit - - Copyright 2015 The TrustKit Project Authors - Licensed under the MIT license, see associated LICENSE file for terms. - See AUTHORS file for the list of project authors. - - */ - -#import -#import "TrustKit+Private.h" -#import "ssl_pin_verifier.h" -#import "public_key_utils.h" -#import "TSKCertificateUtils.h" - - -@interface TSKPinValidationOfflineTests : XCTestCase -{ - -} -@end - -@implementation TSKPinValidationOfflineTests -{ - SecCertificateRef _rootCertificate; - SecCertificateRef _intermediateCertificate; - SecCertificateRef _selfSignedCertificate; - SecCertificateRef _leafCertificate; -} - - -- (void)setUp -{ - [super setUp]; - // Create our certificate objects - _rootCertificate = [TSKCertificateUtils createCertificateFromDer:@"GoodRootCA"]; - _intermediateCertificate = [TSKCertificateUtils createCertificateFromDer:@"GoodIntermediateCA"]; - _leafCertificate = [TSKCertificateUtils createCertificateFromDer:@"www.good.com"]; - _selfSignedCertificate = [TSKCertificateUtils createCertificateFromDer:@"www.good.com.selfsigned"]; -} - - -- (void)tearDown -{ - CFRelease(_rootCertificate); - CFRelease(_intermediateCertificate); - CFRelease(_leafCertificate); - [super tearDown]; -} - - -// Pin to any of CA, Intermediate CA and Leaf certificates public keys (all valid) and ensure it succeeds -- (void)testVerifyAgainstAnyPublicKey -{ - // Create a valid server trust - SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server key - @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key - ]}}}); - - - TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, - @"www.good.com", - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); -} - - -// Pin only to the Intermediate CA certificate public key and ensure it succeeds -- (void)testVerifyAgainstIntermediateCAPublicKey -{ - // Create a valid server trust - SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate Key - @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=" // Intermediate Key - ]}}}); - - - TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, - @"www.good.com", - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); -} - - -// Pin only to the CA certificate public key and ensure it succeeds -- (void)testVerifyAgainstCAPublicKey -{ - // Create a valid server trust - SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key - ]}}}); - - TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, - @"www.good.com", - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); -} - - -// Pin only to the leaf certificate public key and ensure it succeeds -- (void)testVerifyAgainstLeafPublicKey -{ - // Create a valid server trust - SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Leaf Key - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf Key - ]}}}); - - TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, - @"www.good.com", - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); -} - - -// Pin a bad key and ensure validation fails -- (void)testVerifyAgainstBadPublicKey -{ - // Create a valid server trust - SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad Key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Bad key - ]}}}); - - TSKPinValidationResult verificationResult = TSKPinValidationResultSuccess; - verificationResult = verifyPublicKeyPin(trust, - @"www.good.com", - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultFailed, @"Validation must NOT pass against invalid public key pins"); -} - - -// Pin a bad key and a good key and ensure validation succeeds -- (void)testVerifyAgainstLeafPublicKeyAndBadPublicKey -{ - // Create a valid server trust - SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad key - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf key - ]}}}); - - TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, - @"www.good.com", - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against a good and an invalid public key pins"); -} - - -// Pin the valid CA key with an invalid certificate chain and ensure validation fails -- (void)testVerifyAgainstCaPublicKeyAndBadCertificateChain -{ - // The leaf certificate is self-signed - SecCertificateRef certChainArray[2] = {_selfSignedCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.good.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key - ]}}}); - - TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, - @"www.good.com", - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultFailedCertificateChainNotTrusted, @"Validation must fail against an invalid certificate chain"); -} - - -// Pin the valid CA key with an valid certificate chain but a wrong hostname and ensure validation fails -- (void)testVerifyAgainstCaPublicKeyAndBadHostname -{ - // The certificate chain is valid for www.good.com but we are connecting to www.bad.com - SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; - SecCertificateRef trustStoreArray[1] = {_rootCertificate}; - SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray - arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) - anchorCertificates:(const void **)trustStoreArray - arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; - - // Create a configuration and parse it so we get the right format - NSDictionary *trustKitConfig; - trustKitConfig = parseTrustKitArguments(@{kTSKPinnedDomains : - @{@"www.bad.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key - @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key - ]}}}); - - TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; - verificationResult = verifyPublicKeyPin(trust, - @"www.bad.com", - trustKitConfig[kTSKPinnedDomains][@"www.bad.com"][kTSKPublicKeyAlgorithms], - trustKitConfig[kTSKPinnedDomains][@"www.bad.com"][kTSKPublicKeyHashes]); - CFRelease(trust); - - XCTAssert(verificationResult == TSKPinValidationResultFailedCertificateChainNotTrusted, @"Validation must fail against an invalid hostname"); -} - - -@end diff --git a/TrustKitTests/TSKPinningValidatorTests.m b/TrustKitTests/TSKPinningValidatorTests.m new file mode 100644 index 00000000..5d0f8cfa --- /dev/null +++ b/TrustKitTests/TSKPinningValidatorTests.m @@ -0,0 +1,413 @@ +/* + + TSKPinningValidatorTests.m + TrustKit + + Copyright 2015 The TrustKit Project Authors + Licensed under the MIT license, see associated LICENSE file for terms. + See AUTHORS file for the list of project authors. + + */ + +#import +#import "TrustKit+Private.h" +#import "ssl_pin_verifier.h" +#import "public_key_utils.h" +#import "TSKCertificateUtils.h" + + +@interface TSKPinningValidatorTests : XCTestCase +{ + +} +@end + +@implementation TSKPinningValidatorTests +{ + SecCertificateRef _rootCertificate; + SecCertificateRef _intermediateCertificate; + SecCertificateRef _selfSignedCertificate; + SecCertificateRef _leafCertificate; +} + + +- (void)setUp +{ + [super setUp]; + // Create our certificate objects + _rootCertificate = [TSKCertificateUtils createCertificateFromDer:@"GoodRootCA"]; + _intermediateCertificate = [TSKCertificateUtils createCertificateFromDer:@"GoodIntermediateCA"]; + _leafCertificate = [TSKCertificateUtils createCertificateFromDer:@"www.good.com"]; + _selfSignedCertificate = [TSKCertificateUtils createCertificateFromDer:@"www.good.com.selfsigned"]; + + [TrustKit resetConfiguration]; +} + + +- (void)tearDown +{ + CFRelease(_rootCertificate); + CFRelease(_intermediateCertificate); + CFRelease(_leafCertificate); + [super tearDown]; +} + + +// Pin to any of CA, Intermediate CA and Leaf certificates public keys (all valid) and ensure it succeeds +- (void)testVerifyAgainstAnyPublicKey +{ + // Create a valid server trust + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Server key + @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); + + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldAllowConnection); + + CFRelease(trust); +} + + +// Pin only to the Intermediate CA certificate public key and ensure it succeeds +- (void)testVerifyAgainstIntermediateCAPublicKey +{ + // Create a valid server trust + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=", // Intermediate Key + @"khKI6ae4micEvX74MB/BZ4u15WCWGXPD6Gjg6iIRVeE=" // Intermediate Key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldAllowConnection); + CFRelease(trust); +} + + +// Pin only to the CA certificate public key and ensure it succeeds +- (void)testVerifyAgainstCAPublicKey +{ + // Create a valid server trust + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldAllowConnection); + CFRelease(trust); +} + + +// Pin only to the leaf certificate public key and ensure it succeeds +- (void)testVerifyAgainstLeafPublicKey +{ + // Create a valid server trust + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", // Leaf Key + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf Key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldAllowConnection); + CFRelease(trust); +} + + +// Pin a bad key and ensure validation fails +- (void)testVerifyAgainstBadPublicKey +{ + // Create a valid server trust + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad Key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Bad key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultFailed, @"Validation must fail against bad public key pins"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldBlockConnection); + CFRelease(trust); +} + + +// Pin a bad key but do not enforce pinning and ensure the connection is allowed +- (void)testVerifyAgainstBadPublicKeyPinningNotEnforced +{ + // Create a valid server trust + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKEnforcePinning: @NO, + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad Key + @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Bad key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultFailed, @"Validation must fail against bad public key pins"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldAllowConnection); + CFRelease(trust); +} + + + +// Pin a bad key and a good key and ensure validation succeeds +- (void)testVerifyAgainstLeafPublicKeyAndBadPublicKey +{ + // Create a valid server trust + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Bad key + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=" // Leaf key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultSuccess, @"Validation must pass against valid public key pins"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldAllowConnection); + CFRelease(trust); +} + + +// Pin the valid CA key with an invalid certificate chain and ensure validation fails +- (void)testVerifyAgainstCaPublicKeyAndBadCertificateChain +{ + // The leaf certificate is self-signed + SecCertificateRef certChainArray[2] = {_selfSignedCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.good.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.good.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultFailedCertificateChainNotTrusted, @"Validation must fail against bad certificate chain"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.good.com"] == TSKTrustDecisionShouldBlockConnection); + CFRelease(trust); +} + + +// Pin the valid CA key with an valid certificate chain but a wrong hostname and ensure validation fails +- (void)testVerifyAgainstCaPublicKeyAndBadHostname +{ + // The certificate chain is valid for www.good.com but we are connecting to www.bad.com + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.bad.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key + ]}}}; + + // First test the verifyPublicKeyPin() function + NSDictionary *parsedTrustKitConfig = parseTrustKitArguments(trustKitConfig); + + TSKPinValidationResult verificationResult = TSKPinValidationResultFailed; + verificationResult = verifyPublicKeyPin(trust, + @"www.bad.com", + parsedTrustKitConfig[kTSKPinnedDomains][@"www.bad.com"][kTSKPublicKeyAlgorithms], + parsedTrustKitConfig[kTSKPinnedDomains][@"www.bad.com"][kTSKPublicKeyHashes]); + + + XCTAssert(verificationResult == TSKPinValidationResultFailedCertificateChainNotTrusted, @"Validation must fail against bad hostname"); + + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.bad.com"] == TSKTrustDecisionShouldBlockConnection); + CFRelease(trust); +} + + +@end From c014864d46ef43346c9f6bc583f9a47a5f319a15 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Wed, 14 Oct 2015 21:57:00 -0700 Subject: [PATCH 075/118] Minor tweaks --- .../Swizzling/TSKNSURLConnectionDelegateProxy.m | 16 +++++++++++++--- TrustKitTests/TSKNSURLSessionTests.m | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 99a078e8..118ac412 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -72,9 +72,19 @@ + (void)swizzleNSURLConnectionConstructors RSSWArguments(NSURLRequest *request, id delegate, BOOL startImmediately), RSSWReplacement( { - // Replace the delegate with our own so we can intercept and handle authentication challenges - TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; - NSURLConnection *connection = RSSWCallOriginal(request, swizzledDelegate, startImmediately); + NSURLConnection *connection; + + if ([NSStringFromClass([delegate class]) hasPrefix:@"TSK"]) + { + // Don't proxy ourselves + connection = RSSWCallOriginal(request, delegate, startImmediately); + } + else + { + // Replace the delegate with our own so we can intercept and handle authentication challenges + TSKNSURLConnectionDelegateProxy *swizzledDelegate = [[TSKNSURLConnectionDelegateProxy alloc]initWithDelegate:delegate]; + connection = RSSWCallOriginal(request, swizzledDelegate, startImmediately); + } return connection; }), RSSwizzleModeAlways, NULL); diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index fb152b7d..d36f2d9a 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -195,7 +195,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning @{ kTSKPinnedDomains : @{ - @"www.yahoo.com" : @{ + @"www.datatheorem.com" : @{ kTSKEnforcePinning : @NO, kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key @@ -212,7 +212,7 @@ - (void)testPinningValidationFailedDoNotEnforcePinning delegate:delegate delegateQueue:nil]; - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; [task resume]; [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) From 2ce9805d1f4cc7e97491dcd3b890d442b5383493 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 00:31:53 -0700 Subject: [PATCH 076/118] Reduce the number of online tests --- TrustKitTests/TSKNSURLConnectionTests.m | 54 ++++---------------- TrustKitTests/TSKNSURLSessionTests.m | 64 +++++------------------- TrustKitTests/TSKPinningValidatorTests.m | 27 ++++++++++ 3 files changed, 48 insertions(+), 97 deletions(-) diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index a7e5c0d2..a0224042 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -54,6 +54,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection {} - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + NSLog(@"Received error, %@", error); _lastError = error; [testExpectation fulfill]; } @@ -133,6 +134,9 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio // As a hacky workaround, every test that connects to an endpoint uses a different domain. // https://developer.apple.com/library/mac/qa/qa1727/_index.html +// WARNING 2: If the domain sends a redirection, two pinning validation will occur, thereby setting the +// lastTrustDecision to an unexpected value + @interface TSKNSURLConnectionTests : XCTestCase @end @@ -234,57 +238,17 @@ - (void)testPinningValidationFailed } -// Tests a secure connection to https://www.yahoo.com and forces validation to fail by providing a fake hash, but do not enforce pinning -- (void)testPinningValidationFailedDoNotEnforcePinning -{ - NSDictionary *trustKitConfig = - @{ - kTSKPinnedDomains : - @{ - @"www.yahoo.com" : @{ - kTSKEnforcePinning : @NO, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key - ]}}}; - - [TrustKit initializeWithConfiguration:trustKitConfig]; - - - XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLConnectionDelegate"]; - TestNSURLConnectionDelegateNoAuthHandler *delegate = [[TestNSURLConnectionDelegateNoAuthHandler alloc] initWithExpectation:expectation]; - // Use +connectionWithRequest:delegate: - NSURLConnection *connection = [NSURLConnection - connectionWithRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.yahoo.com/"]] - delegate:delegate]; - [connection start]; - - [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) - { - if (error) - { - NSLog(@"Timeout Error: %@", error); - } - }]; - - XCTAssert(([TSKNSURLConnectionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); - XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); - XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); -} - - -// Tests a secure connection to https://www.datatheorem.com by pinning only to the CA public key +// Tests a secure connection to https://www.cloudflare.com by pinning only to the CA public key - (void)testPinningValidationSucceeded { NSDictionary *trustKitConfig = @{ kTSKPinnedDomains : @{ - @"www.datatheorem.com" : @{ + @"www.cloudflare.com" : @{ kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + kTSKPublicKeyHashes : @[@"AG1751Vd2CAmRCxPGieoDomhmJy4ezREjtIZTBgZbV4=", // CA key + @"AG1751Vd2CAmRCxPGieoDomhmJy4ezREjtIZTBgZbV4=" // CA key ]}}}; [TrustKit initializeWithConfiguration:trustKitConfig]; @@ -295,7 +259,7 @@ - (void)testPinningValidationSucceeded // Use -initWithRequest:delegate:startstartImmediately: NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL: - [NSURL URLWithString:@"https://www.datatheorem.com/"]] + [NSURL URLWithString:@"https://www.cloudflare.com/"]] delegate:delegate startImmediately:YES]; [connection start]; diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index d36f2d9a..6e8ad62a 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -59,6 +59,7 @@ - (void)URLSession:(NSURLSession * _Nonnull)session task:(NSURLSessionTask * _Nonnull)task didCompleteWithError:(NSError * _Nullable)error { + NSLog(@"Received error, %@", error); _lastError = error; [testExpectation fulfill]; } @@ -188,47 +189,6 @@ - (void)testPinningValidationFailed } -// Tests a secure connection to https://www.yahoo.com and forces validation to fail by providing a fake hash, but do not enforce pinning -- (void)testPinningValidationFailedDoNotEnforcePinning -{ - NSDictionary *trustKitConfig = - @{ - kTSKPinnedDomains : - @{ - @"www.datatheorem.com" : @{ - kTSKEnforcePinning : @NO, - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key - @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key - ]}}}; - - [TrustKit initializeWithConfiguration:trustKitConfig]; - - - XCTestExpectation *expectation = [self expectationWithDescription:@"TestNSURLSessionTaskDelegate"]; - TestNSURLSessionDelegate* delegate = [[TestNSURLSessionDelegate alloc] initWithExpectation:expectation]; - - NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] - delegate:delegate - delegateQueue:nil]; - - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.datatheorem.com/"]]; - [task resume]; - - [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) - { - if (error) - { - NSLog(@"Timeout Error: %@", error); - } - }]; - - XCTAssert(([TSKNSURLSessionDelegateProxy getLastTrustDecision] == TSKTrustDecisionShouldAllowConnection), @"TrustKit blocked a connection although pinning was not enforced"); - XCTAssertNil(delegate.lastError, @"TrustKit triggered an error"); - XCTAssertNotNil(delegate.lastResponse, @"TrustKit did not return a response although pinning was not enforced"); -} - - - (void)testPinningValidationSucceeded { NSDictionary *trustKitConfig = @@ -273,7 +233,7 @@ - (void)testNoDelegateWarnings @{ kTSKPinnedDomains : @{ - @"www.yahoo.com" : @{ + @"www.google.com" : @{ kTSKEnforcePinning : @YES, kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], kTSKPublicKeyHashes : @[@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Fake key @@ -288,12 +248,12 @@ - (void)testNoDelegateWarnings NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] delegate:nil delegateQueue:nil]; - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; [task resume]; // Start a session with +sessionWithConfiguration: NSURLSession *session2 = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; - NSURLSessionDataTask *task2 = [session2 dataTaskWithURL:[NSURL URLWithString:@"https://www.yahoo.com/"]]; + NSURLSessionDataTask *task2 = [session2 dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; [task2 resume]; // Start a session with +sharedSession @@ -311,10 +271,10 @@ - (void)testTaskDidReceiveChallengeGetsCalled @{ kTSKPinnedDomains : @{ - @"www.datatheorem.com" : @{ + @"www.apple.com" : @{ kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + kTSKPublicKeyHashes : @[@"gMxWOrX4PMQesK9qFNbYBxjBfjUvlkn/vN1n+L9lE5E=", // CA key + @"gMxWOrX4PMQesK9qFNbYBxjBfjUvlkn/vN1n+L9lE5E=" // CA key ]}}}; [TrustKit initializeWithConfiguration:trustKitConfig]; @@ -327,7 +287,7 @@ - (void)testTaskDidReceiveChallengeGetsCalled delegate:delegate delegateQueue:nil]; - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.apple.com/"]]; [task resume]; [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { @@ -348,10 +308,10 @@ - (void)testSessionDidReceiveChallengeGetsCalled @{ kTSKPinnedDomains : @{ - @"www.datatheorem.com" : @{ + @"www.fastmail.fm" : @{ kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[@"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", // CA key - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=" // CA key + kTSKPublicKeyHashes : @[@"k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws=", // CA key + @"k2v657xBsOVe1PQRwOsHsw3bsGT2VzIqz5K+59sNQws=" // CA key ]}}}; [TrustKit initializeWithConfiguration:trustKitConfig]; @@ -364,7 +324,7 @@ - (void)testSessionDidReceiveChallengeGetsCalled delegate:delegate delegateQueue:nil]; - NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.google.com/"]]; + NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.fastmail.fm/"]]; [task resume]; [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { diff --git a/TrustKitTests/TSKPinningValidatorTests.m b/TrustKitTests/TSKPinningValidatorTests.m index 5d0f8cfa..a566abad 100644 --- a/TrustKitTests/TSKPinningValidatorTests.m +++ b/TrustKitTests/TSKPinningValidatorTests.m @@ -410,4 +410,31 @@ - (void)testVerifyAgainstCaPublicKeyAndBadHostname } +- (void)testDomainNotPinned +{ + // The certificate chain is valid for www.good.com but we are connecting to www.bad.com + SecCertificateRef certChainArray[2] = {_leafCertificate, _intermediateCertificate}; + SecCertificateRef trustStoreArray[1] = {_rootCertificate}; + SecTrustRef trust = [TSKCertificateUtils createTrustWithCertificates:(const void **)certChainArray + arrayLength:sizeof(certChainArray)/sizeof(certChainArray[0]) + anchorCertificates:(const void **)trustStoreArray + arrayLength:sizeof(trustStoreArray)/sizeof(trustStoreArray[0])]; + + + // Create a configuration + NSDictionary *trustKitConfig = @{kTSKPinnedDomains : + @{@"www.good.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=", // CA Key + @"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=" // CA Key + ]}}}; + + // Then test TSKPinningValidator + [TrustKit initializeWithConfiguration:trustKitConfig]; + XCTAssert([TSKPinningValidator evaluateTrust:trust forHostname:@"www.bad.com"] == TSKTrustDecisionDomainNotPinned); + CFRelease(trust); +} + + + @end From 115d8c1ad29f9ffc0b5173b5b640a20987f373b7 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 00:37:02 -0700 Subject: [PATCH 077/118] Tweak travis file --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index ed7729aa..bb329bd0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,9 @@ language: objective-c osx_image: xcode7 env: matrix: - - TEST_SDK=macosx10.11 TEST_SCHEME=TrustKit OS X + - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" - TEST_SDK=iphonesimulator9.0 TEST_SCHEME=TrustKit + - TEST_SDK=iphonesimulator8.4 TEST_SCHEME=TrustKit script: - - xcodebuild clean -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - - xcodebuild build test -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild build test -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From 082b1066e61ea538f633faac2d5a683862ef32ac Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 00:58:23 -0700 Subject: [PATCH 078/118] Make OS X scheme shared --- .travis.yml | 1 - .../xcschemes/TrustKit OS X.xcscheme | 99 +++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit OS X.xcscheme diff --git a/.travis.yml b/.travis.yml index bb329bd0..1cfe2021 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,6 @@ env: matrix: - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" - TEST_SDK=iphonesimulator9.0 TEST_SCHEME=TrustKit - - TEST_SDK=iphonesimulator8.4 TEST_SCHEME=TrustKit script: - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - xcodebuild build test -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK diff --git a/TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit OS X.xcscheme b/TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit OS X.xcscheme new file mode 100644 index 00000000..a9d69df4 --- /dev/null +++ b/TrustKit.xcodeproj/xcshareddata/xcschemes/TrustKit OS X.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From abeb43b214091c1f76bacb304cb0b6c450faf43a Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 01:05:31 -0700 Subject: [PATCH 079/118] Tweak travis file --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1cfe2021..82a6c9cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,5 @@ env: - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" - TEST_SDK=iphonesimulator9.0 TEST_SCHEME=TrustKit script: - - xcodebuild clean -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - - xcodebuild build test -project TrustKit.xcodeproj -scheme $TEST_SCHEME -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild clean -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK + - xcodebuild build test -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From 3a85f47bd1f1e942e7d72d55d3b913cc146eb353 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 01:11:41 -0700 Subject: [PATCH 080/118] tweak --- TrustKit/Reporting/TSKSimpleReporter.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m index ac10a36b..90c4db5a 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ b/TrustKit/Reporting/TSKSimpleReporter.m @@ -77,7 +77,7 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname port:(NSNumber *) serverPort trust:(SecTrustRef) serverTrust notedHostname:(NSString *) notedHostname - reportURIs:(NSArray *) reportURIs + reportURIs:(NSArray *) reportURIs includeSubdomains:(BOOL) includeSubdomains knownPins:(NSArray *) knownPins validationResult:(TSKPinValidationResult) validationResult; From 813e3a04a58b97db259f627d72a79a642885f83d Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 08:38:03 -0700 Subject: [PATCH 081/118] Prevent redirections in the test suite --- TrustKitTests/TSKNSURLConnectionTests.m | 22 ++++++++++++++++------ TrustKitTests/TSKNSURLSessionTests.m | 12 ++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/TrustKitTests/TSKNSURLConnectionTests.m b/TrustKitTests/TSKNSURLConnectionTests.m index a0224042..6265fc14 100644 --- a/TrustKitTests/TSKNSURLConnectionTests.m +++ b/TrustKitTests/TSKNSURLConnectionTests.m @@ -32,8 +32,11 @@ @interface TestNSURLConnectionDelegateNoAuthHandler : NSObject Date: Thu, 15 Oct 2015 13:00:31 -0700 Subject: [PATCH 082/118] Coding style --- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 10 +++++----- TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 118ac412..46c293f5 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -13,7 +13,7 @@ // Useful for the tests -static TSKTrustDecision lastTrustDecision = -1; +static TSKTrustDecision _lastTrustDecision = -1; typedef void (^AsyncCompletionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError); @@ -29,12 +29,12 @@ @implementation TSKNSURLConnectionDelegateProxy // Private methods used for tests +(void)resetLastTrustDecision { - lastTrustDecision = -1;; + _lastTrustDecision = -1;; } +(TSKTrustDecision)getLastTrustDecision { - return lastTrustDecision; + return _lastTrustDecision; } @@ -129,7 +129,7 @@ - (instancetype)initWithDelegate:(id)delegate originalDelegate = delegate; } TSKLog(@"Proxy-ing NSURLConnectionDelegate: %@", NSStringFromClass([delegate class])); - lastTrustDecision = -1; + _lastTrustDecision = -1; return self; } @@ -198,7 +198,7 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio // Check the trust object against the pinning policy trustDecision = [TSKPinningValidator evaluateTrust:serverTrust forHostname:serverHostname]; - lastTrustDecision = trustDecision; + _lastTrustDecision = trustDecision; if (trustDecision == TSKTrustDecisionShouldAllowConnection) { // Success - don't do anything and forward the challenge to the original delegate diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 75e55046..32331518 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -12,7 +12,7 @@ // Useful for the tests -static TSKTrustDecision lastTrustDecision = -1; +static TSKTrustDecision _lastTrustDecision = -1; @implementation TSKNSURLSessionDelegateProxy @@ -21,12 +21,12 @@ @implementation TSKNSURLSessionDelegateProxy // Private methods used for tests +(void)resetLastTrustDecision { - lastTrustDecision = -1;; + _lastTrustDecision = -1;; } +(TSKTrustDecision)getLastTrustDecision { - return lastTrustDecision; + return _lastTrustDecision; } @@ -95,7 +95,7 @@ - (instancetype)initWithDelegate:(id)delegate originalDelegate = delegate; } TSKLog(@"Proxy-ing NSURLSessionDelegate: %@", NSStringFromClass([delegate class])); - lastTrustDecision = -1; + _lastTrustDecision = -1; return self; } @@ -176,7 +176,7 @@ - (void)URLSession:(NSURLSession * _Nonnull)session // Check the trust object against the pinning policy trustDecision = [TSKPinningValidator evaluateTrust:serverTrust forHostname:serverHostname]; - lastTrustDecision = trustDecision; + _lastTrustDecision = trustDecision; if (trustDecision == TSKTrustDecisionShouldAllowConnection) { // Success - don't do anything and forward the challenge to the original delegate @@ -242,7 +242,7 @@ - (void)URLSession:(NSURLSession * _Nonnull)session // Check the trust object against the pinning policy trustDecision = [TSKPinningValidator evaluateTrust:challenge.protectionSpace.serverTrust forHostname:challenge.protectionSpace.host]; - lastTrustDecision = trustDecision; + _lastTrustDecision = trustDecision; if ((trustDecision == TSKTrustDecisionShouldAllowConnection) || (trustDecision == TSKTrustDecisionDomainNotPinned)) { // Don't do anything and forward the challenge to the original delegate From 17684d8bcb3aa37568a28326549da86e80a7f6c0 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 13:30:34 -0700 Subject: [PATCH 083/118] Clarify the name of the identifier --- TrustKit/Reporting/TSKBackgroundReporter.m | 6 +++--- TrustKit/Reporting/TSKPinFailureReport.h | 4 ++-- TrustKit/Reporting/TSKPinFailureReport.m | 6 +++--- TrustKit/Reporting/TSKSimpleReporter.m | 6 +++--- TrustKit/TrustKit.h | 2 +- TrustKitTests/TSKReporterTests.m | 8 ++++---- docs/sample_report.json | 2 +- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index 28945216..5510aab5 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -29,7 +29,7 @@ @interface TSKBackgroundReporter() @property (nonatomic, strong) NSString * appBundleId; @property (nonatomic, strong) NSString * appVersion; -@property (nonatomic, strong) NSString * appIdentifier; +@property (nonatomic, strong) NSString * appVendorId; @property BOOL shouldRateLimitReports; @end @@ -49,7 +49,7 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports // Retrieve the App's information #if TARGET_OS_IPHONE // On iOS use the IDFV - self.appIdentifier = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; + self.appVendorId = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; #else // On OS X, don't use anything for now self.appIdentifier = @"OS-X"; @@ -161,7 +161,7 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname validatedCertificateChain:certificateChain knownPins:formattedPins validationResult:validationResult - appIdentifier:self.appIdentifier]; + appVendorId:self.appVendorId]; // Should we rate-limit this report? diff --git a/TrustKit/Reporting/TSKPinFailureReport.h b/TrustKit/Reporting/TSKPinFailureReport.h index 64acde6f..50d802ed 100644 --- a/TrustKit/Reporting/TSKPinFailureReport.h +++ b/TrustKit/Reporting/TSKPinFailureReport.h @@ -17,7 +17,7 @@ @property (readonly, nonatomic) NSString *appBundleId; // Not part of the HPKP spec @property (readonly, nonatomic) NSString *appVersion; // Not part of the HPKP spec -@property (readonly, nonatomic) NSString *appIdentifier; // Not part of the HPKP spec +@property (readonly, nonatomic) NSString *appVendorId; // Not part of the HPKP spec @property (readonly, nonatomic) NSString *notedHostname; @property (readonly, nonatomic) NSString *hostname; @property (readonly, nonatomic) NSNumber *port; @@ -39,7 +39,7 @@ validatedCertificateChain:(NSArray *)validatedCertificateChain knownPins:(NSArray *)knownPins validationResult:(TSKPinValidationResult) validationResult - appIdentifier:(NSString *)appIdentifier; + appVendorId:(NSString *)appVendorId; // Return the report in JSON format for POSTing it - (NSData *)json; diff --git a/TrustKit/Reporting/TSKPinFailureReport.m b/TrustKit/Reporting/TSKPinFailureReport.m index 500e2378..7148158c 100644 --- a/TrustKit/Reporting/TSKPinFailureReport.m +++ b/TrustKit/Reporting/TSKPinFailureReport.m @@ -24,7 +24,7 @@ - (instancetype) initWithAppBundleId:(NSString *) appBundleId validatedCertificateChain:(NSArray *)validatedCertificateChain knownPins:(NSArray *)knownPins validationResult:(TSKPinValidationResult) validationResult - appIdentifier:(NSString *)appIdentifier + appVendorId:(NSString *)appVendorId { self = [super init]; if (self) @@ -39,7 +39,7 @@ - (instancetype) initWithAppBundleId:(NSString *) appBundleId _validatedCertificateChain = validatedCertificateChain; _knownPins = knownPins; _validationResult = validationResult; - _appIdentifier = appIdentifier; + _appVendorId = appVendorId; } return self; } @@ -65,7 +65,7 @@ - (NSData *)json; @"validated-certificate-chain" : self.validatedCertificateChain, @"known-pins" : self.knownPins, @"validation-result": [NSNumber numberWithInt:self.validationResult], - @"app-identifier": self.appIdentifier + @"app-vendor-id": self.appVendorId }; NSError *error; diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m index 90c4db5a..a72da224 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ b/TrustKit/Reporting/TSKSimpleReporter.m @@ -25,7 +25,7 @@ @interface TSKSimpleReporter() @property (nonatomic, strong) NSString * appBundleId; @property (nonatomic, strong) NSString * appVersion; -@property (nonatomic, strong) NSString * appIdentifier; +@property (nonatomic, strong) NSString * appVendorId; @property BOOL shouldRateLimitReports; @property(nonatomic, strong) NSURLSession *session; @end @@ -44,7 +44,7 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports // Retrieve the App's information #if TARGET_OS_IPHONE // On iOS use the IDFV - self.appIdentifier = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; + self.appVendorId = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; #else // On OS X, don't use anything for now self.appIdentifier = @"OS-X"; @@ -110,7 +110,7 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname validatedCertificateChain:certificateChain knownPins:formattedPins validationResult:validationResult - appIdentifier:self.appIdentifier]; + appVendorId:self.appVendorId]; // Should we rate-limit this report? diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index a018c9d4..217c86a6 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -156,7 +156,7 @@ FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmEcDsaSecp256r1; { "app-bundle-id":"com.example.ABC", "app-version":"1.0", - "app-identifier":"599F9C00-92DC-4B5C-9464-7971F01F8370", + "app-vendor-id":"599F9C00-92DC-4B5C-9464-7971F01F8370", "date-time": "2015-07-10T20:03:14Z", "hostname": "mail.example.com", "port": 0, diff --git a/TrustKitTests/TSKReporterTests.m b/TrustKitTests/TSKReporterTests.m index ff952f35..55352e9c 100644 --- a/TrustKitTests/TSKReporterTests.m +++ b/TrustKitTests/TSKReporterTests.m @@ -97,7 +97,7 @@ - (void)testReportsRateLimiter validatedCertificateChain:certificateChain knownPins:formattedPins validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted - appIdentifier:@"test"]; + appVendorId:@"test"]; // Ensure the same report will not be sent twice in a row XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); @@ -119,7 +119,7 @@ - (void)testReportsRateLimiter validatedCertificateChain:certificateChain knownPins:formattedPins validationResult:TSKPinValidationResultFailed - appIdentifier:@"test"]; + appVendorId:@"test"]; XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == YES, @"Did not rate-limit an identical report"); @@ -135,7 +135,7 @@ - (void)testReportsRateLimiter validatedCertificateChain:certificateChain knownPins:formattedPins validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted - appIdentifier:@"test"]; + appVendorId:@"test"]; XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == YES, @"Did not rate-limit an identical report"); @@ -151,7 +151,7 @@ - (void)testReportsRateLimiter validatedCertificateChain:[certificateChain subarrayWithRange:NSMakeRange(1, 2)] knownPins:formattedPins validationResult:TSKPinValidationResultFailedCertificateChainNotTrusted - appIdentifier:@"test"]; + appVendorId:@"test"]; XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == NO, @"Wrongly rate-limited a new report"); XCTAssert([TSKReportsRateLimiter shouldRateLimitReport:report] == YES, @"Did not rate-limit an identical report"); } diff --git a/docs/sample_report.json b/docs/sample_report.json index f23e81dd..788960ef 100644 --- a/docs/sample_report.json +++ b/docs/sample_report.json @@ -14,6 +14,6 @@ "pin-sha256=\"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=\"" ], "app-bundle-id": "com.datatheorem.testtrustkit2", - "app-identifier": "599F9C00-92DC-4B5C-9464-7971F01F8370", + "app-vendor-id”: "599F9C00-92DC-4B5C-9464-7971F01F8370", "port": 443 } From 693af8694057e7add448fc73a4ab6f6dda348744 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Thu, 15 Oct 2015 17:21:57 -0700 Subject: [PATCH 084/118] Clarify log --- TrustKit/Reporting/TSKBackgroundReporter.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index 5510aab5..276a6a5c 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -203,7 +203,7 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didComp { if (error == nil) { - TSKLog(@"Background upload - task %@ completed successfully", task); + TSKLog(@"Background upload - task %@ completed successfully; pinning failure report sent", task); } else { From b3561608d1c59b47a7cbc17290710a197394cd74 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 17 Oct 2015 09:12:15 -0700 Subject: [PATCH 085/118] Fix build error on OS X --- TrustKit/Reporting/TSKBackgroundReporter.m | 2 +- TrustKit/Reporting/TSKSimpleReporter.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index 276a6a5c..b2bed6d7 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -52,7 +52,7 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports self.appVendorId = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; #else // On OS X, don't use anything for now - self.appIdentifier = @"OS-X"; + self.appVendorId = @"OS-X"; #endif CFBundleRef appBundle = CFBundleGetMainBundle(); diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m index a72da224..b75ae67f 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ b/TrustKit/Reporting/TSKSimpleReporter.m @@ -47,7 +47,7 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports self.appVendorId = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; #else // On OS X, don't use anything for now - self.appIdentifier = @"OS-X"; + self.appVendorId = @"OS-X"; #endif CFBundleRef appBundle = CFBundleGetMainBundle(); From 0516c33320d220d90acd550353705789c0d6ae2f Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sat, 17 Oct 2015 22:15:59 -0700 Subject: [PATCH 086/118] Add idfv specific to unit tests --- TrustKit/Reporting/TSKSimpleReporter.m | 1 + 1 file changed, 1 insertion(+) diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m index b75ae67f..a31d8311 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ b/TrustKit/Reporting/TSKSimpleReporter.m @@ -58,6 +58,7 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports { // Should only happen when running tests self.appBundleId = @"N/A"; + self.appVendorId = @"unit-tests"; } if (self.appVersion == nil) From 9479d41a279437ed80c83b70c44961a242d32caf Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 10:25:49 -0700 Subject: [PATCH 087/118] Fix badges --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 60e15881..cfd21cf9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ TrustKit ======== -[![Build Status](https://travis-ci.org/datatheorem/TrustKit.svg)](https://travis-ci.org/datatheorem/TrustKit) [![Version Status](https://img.shields.io/cocoapods/v/TrustKit.svg?style=flat)](https://cocoapods.org/pods/TrustKit) [![Platform](http://img.shields.io/cocoapods/p/TrustKit.svg?style=flat)](https://cocoapods.org/pods/TrustKit) [![License MIT](https://img.shields.io/github/license/datatheorem/trustkit.svg?style=flat)](https://en.wikipedia.org/wiki/MIT_License) +[![Build Status](https://travis-ci.org/datatheorem/TrustKit.svg)](https://travis-ci.org/datatheorem/TrustKit) [![Version Status](https://img.shields.io/cocoapods/v/TrustKit.svg?style=flat)](https://cocoapods.org/pods/TrustKit) [![Platform](https://img.shields.io/cocoapods/p/TrustKit.svg?style=flat)](https://cocoapods.org/pods/TrustKit) [![License MIT](https://img.shields.io/cocoapods/l/TrustKit.svg?style=flat)](https://en.wikipedia.org/wiki/MIT_License) **TrustKit** is an open source framework that makes it easy to deploy SSL public key pinning in any iOS or OS X App. @@ -141,3 +141,4 @@ License [bh2015-pdf]: https://datatheorem.github.io/TrustKit/files/TrustKit-BH2015.pdf [bh2015-conf]: https://www.blackhat.com/us-15/briefings.html#trustkit-code-injection-on-ios-8-for-the-greater-good [api-doc]: https://datatheorem.github.io/TrustKit/documentation + From 4764b579326146e69effc77cb5544b228bc98b4d Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 10:34:05 -0700 Subject: [PATCH 088/118] Clarify error message --- TrustKit/TrustKit.m | 1 + 1 file changed, 1 insertion(+) diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 4c847415..d5f2e075 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -169,6 +169,7 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus { [NSException raise:@"TrustKit configuration invalid" format:@"TrustKit was initialized with zero pinned domains; ensure your domain pinning policies are under the TSKPinnedDomains key."]; + format:@"TrustKit was initialized with no pinned domains. The configuration format has changed: ensure your domain pinning policies are under the TSKPinnedDomains key within TSKConfiguration."]; } From 2f21173a95e6c2082c83fd78b32e9e0494750db2 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 10:40:51 -0700 Subject: [PATCH 089/118] Fix issues found by infer --- TrustKit/TrustKit.m | 31 ++++++++++++++-------------- TrustKitTests/TSKCertificateUtils.m | 16 +++++++++++--- TrustKitTests/TSKNSURLSessionTests.m | 5 ++++- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index d5f2e075..dc19a58b 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -138,28 +138,28 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus // Should we auto-swizzle network delegates NSNumber *shouldSwizzleNetworkDelegates = TrustKitArguments[kTSKSwizzleNetworkDelegates]; - if (shouldSwizzleNetworkDelegates) + if (shouldSwizzleNetworkDelegates == nil) { - finalConfiguration[kTSKSwizzleNetworkDelegates] = shouldSwizzleNetworkDelegates; + // Default setting is YES + finalConfiguration[kTSKSwizzleNetworkDelegates] = [NSNumber numberWithBool:YES]; } else { - // Default setting is YES - finalConfiguration[kTSKSwizzleNetworkDelegates] = [NSNumber numberWithBool:YES]; + finalConfiguration[kTSKSwizzleNetworkDelegates] = shouldSwizzleNetworkDelegates; } #if !TARGET_OS_IPHONE // OS X only: extract the optional ignorePinningForUserDefinedTrustAnchors setting NSNumber *shouldIgnorePinningForUserDefinedTrustAnchors = TrustKitArguments[kTSKIgnorePinningForUserDefinedTrustAnchors]; - if (shouldIgnorePinningForUserDefinedTrustAnchors) + if (shouldIgnorePinningForUserDefinedTrustAnchors == nil) { - finalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = shouldIgnorePinningForUserDefinedTrustAnchors; + // Default setting is YES + finalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = [NSNumber numberWithBool:YES]; } else { - // Default setting is YES - finalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = [NSNumber numberWithBool:YES]; + finalConfiguration[kTSKIgnorePinningForUserDefinedTrustAnchors] = shouldIgnorePinningForUserDefinedTrustAnchors; } #endif @@ -168,7 +168,6 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus if ((TrustKitArguments[kTSKPinnedDomains] == nil) || ([TrustKitArguments[kTSKPinnedDomains] count] < 1)) { [NSException raise:@"TrustKit configuration invalid" - format:@"TrustKit was initialized with zero pinned domains; ensure your domain pinning policies are under the TSKPinnedDomains key."]; format:@"TrustKit was initialized with no pinned domains. The configuration format has changed: ensure your domain pinning policies are under the TSKPinnedDomains key within TSKConfiguration."]; } @@ -190,7 +189,12 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus // Extract the optional includeSubdomains setting NSNumber *shouldIncludeSubdomains = domainPinningPolicy[kTSKIncludeSubdomains]; - if (shouldIncludeSubdomains) + if (shouldIncludeSubdomains == nil) + { + // Default setting is NO + domainFinalConfiguration[kTSKIncludeSubdomains] = [NSNumber numberWithBool:NO]; + } + else { if ([shouldIncludeSubdomains boolValue] == YES) { @@ -205,13 +209,8 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus domainFinalConfiguration[kTSKIncludeSubdomains] = shouldIncludeSubdomains; } - else - { - // Default setting is NO - domainFinalConfiguration[kTSKIncludeSubdomains] = [NSNumber numberWithBool:NO]; - } - + // Extract the optional enforcePinning setting NSNumber *shouldEnforcePinning = domainPinningPolicy[kTSKEnforcePinning]; if (shouldEnforcePinning) diff --git a/TrustKitTests/TSKCertificateUtils.m b/TrustKitTests/TSKCertificateUtils.m index 6a4e70f4..d00aa12c 100644 --- a/TrustKitTests/TSKCertificateUtils.m +++ b/TrustKitTests/TSKCertificateUtils.m @@ -39,7 +39,10 @@ + (SecTrustRef)createTrustWithCertificates:(const void **)certArray if (SecTrustCreateWithCertificates(certificateChain, policy, &trust) != errSecSuccess) { - CFRelease(certificateChain); + if (certificateChain) + { + CFRelease(certificateChain); + } CFRelease(policy); [NSException raise:@"Test error" format:@"SecTrustCreateWithCertificates did not return errSecSuccess"]; } @@ -51,8 +54,15 @@ + (SecTrustRef)createTrustWithCertificates:(const void **)certArray if (SecTrustSetAnchorCertificates(trust, trustStore) != errSecSuccess) { - CFRelease(certificateChain); - CFRelease(trust); + if (certificateChain) + { + CFRelease(certificateChain); + } + + if (trust) + { + CFRelease(trust); + } [NSException raise:@"Test error" format:@"SecTrustCreateWithCertificates did not return errSecSuccess"]; } CFRelease(trustStore); diff --git a/TrustKitTests/TSKNSURLSessionTests.m b/TrustKitTests/TSKNSURLSessionTests.m index 00a19c03..3ec283c6 100644 --- a/TrustKitTests/TSKNSURLSessionTests.m +++ b/TrustKitTests/TSKNSURLSessionTests.m @@ -82,7 +82,10 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPer [testExpectation fulfill]; // Do not follow redirections as they cause two pinning validations, thereby changing the lastTrustDecision - completionHandler(nil); + if (completionHandler) + { + completionHandler(nil); + } } @end From 9d53e93146130be50169e910a69711297225206d Mon Sep 17 00:00:00 2001 From: Chuck Shnider Date: Sun, 18 Oct 2015 13:42:51 -0400 Subject: [PATCH 090/118] fix compiler warnings for -Wmissing-prototypes --- TrustKit/Reporting/reporting_utils.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TrustKit/Reporting/reporting_utils.m b/TrustKit/Reporting/reporting_utils.m index 758e87c6..12044ff6 100644 --- a/TrustKit/Reporting/reporting_utils.m +++ b/TrustKit/Reporting/reporting_utils.m @@ -11,6 +11,8 @@ #import +#import "reporting_utils.h" + NSArray *convertTrustToPemArray(SecTrustRef serverTrust) { From e094c4fb2b58182510b49ee8aacfd975d1fb3c87 Mon Sep 17 00:00:00 2001 From: Chuck Shnider Date: Sun, 18 Oct 2015 13:44:29 -0400 Subject: [PATCH 091/118] fix compler warnings for -Wnewline-eof --- TrustKit/Pinning/TSKPinningValidator.m | 2 +- TrustKit/Reporting/TSKReportsRateLimiter.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.m b/TrustKit/Pinning/TSKPinningValidator.m index dda17afa..3d86c8bb 100644 --- a/TrustKit/Pinning/TSKPinningValidator.m +++ b/TrustKit/Pinning/TSKPinningValidator.m @@ -94,4 +94,4 @@ + (TSKTrustDecision) evaluateTrust:(SecTrustRef _Nonnull)serverTrust forHostname return finalTrustDecision; } -@end \ No newline at end of file +@end diff --git a/TrustKit/Reporting/TSKReportsRateLimiter.h b/TrustKit/Reporting/TSKReportsRateLimiter.h index 436912fb..697dbf10 100644 --- a/TrustKit/Reporting/TSKReportsRateLimiter.h +++ b/TrustKit/Reporting/TSKReportsRateLimiter.h @@ -30,4 +30,4 @@ @interface TSKReportsRateLimiter(Private) // Helper method for running tests + (void) setLastReportsCacheResetDate:(NSDate *)date; -@end \ No newline at end of file +@end From 722cc545f90208157cc0e73528a30a30eb7d058b Mon Sep 17 00:00:00 2001 From: Chuck Shnider Date: Sun, 18 Oct 2015 13:50:19 -0400 Subject: [PATCH 092/118] silence a couple of "shadows local vairable" warnings --- .../Swizzling/TSKNSURLConnectionDelegateProxy.m | 3 +++ TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m | 13 +++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index 46c293f5..a3d79ca8 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -40,6 +40,8 @@ +(TSKTrustDecision)getLastTrustDecision + (void)swizzleNSURLConnectionConstructors { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow" // - initWithRequest:delegate: RSSwizzleInstanceMethod(NSClassFromString(@"NSURLConnection"), @selector(initWithRequest:delegate:), @@ -118,6 +120,7 @@ + (void)swizzleNSURLConnectionConstructors NSData *data = RSSWCallOriginal(request, response, error); return data; })); +#pragma clang diagnostic pop } diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 32331518..0362f79a 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -49,8 +49,11 @@ + (void)swizzleNSURLSessionConstructors TSKLog(@"ERROR: Could not find NSURLSession's class"); return; } - + + // + sessionWithConfiguration:delegate:delegateQueue: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wshadow" RSSwizzleClassMethod(NSClassFromString(NSURLSessionClass), @selector(sessionWithConfiguration:delegate:delegateQueue:), RSSWReturnType(NSURLSession *), @@ -58,14 +61,14 @@ + (void)swizzleNSURLSessionConstructors RSSWReplacement( { NSURLSession *session; - + if (delegate == nil) { // Just display a warning //TSKLog(@"WARNING: +sessionWithConfiguration:delegate:delegateQueue: was called with a nil delegate; TrustKit cannot enforce SSL pinning for any connection initiated by this session"); session = RSSWCallOriginal(configuration, delegate, queue); } - + // Do not swizzle TrustKit objects (such as the reporter) else if ([NSStringFromClass([delegate class]) hasPrefix:@"TSK"]) { @@ -77,12 +80,14 @@ + (void)swizzleNSURLSessionConstructors TSKNSURLSessionDelegateProxy *swizzledDelegate = [[TSKNSURLSessionDelegateProxy alloc]initWithDelegate:delegate]; session = RSSWCallOriginal(configuration, swizzledDelegate, queue); } - + return session; })); // Not hooking the following methods as they end up calling +sessionWithConfiguration:delegate:delegateQueue: // +sessionWithConfiguration: // +sharedSession + +#pragma clang diagnostic pop } From 0c08e781004a1b54ee7cf144ca42ae8628beb87c Mon Sep 17 00:00:00 2001 From: Chuck Shnider Date: Sun, 18 Oct 2015 13:58:10 -0400 Subject: [PATCH 093/118] remove references to thirdparty lib "fishhook" as it appears unused at this pooint --- ATTRIBUTIONS | 27 --- TrustKit.podspec | 2 +- TrustKit.xcodeproj/project.pbxproj | 22 --- TrustKit/Dependencies/fishhook/fishhook.c | 204 ---------------------- TrustKit/Dependencies/fishhook/fishhook.h | 67 ------- 5 files changed, 1 insertion(+), 321 deletions(-) delete mode 100755 TrustKit/Dependencies/fishhook/fishhook.c delete mode 100755 TrustKit/Dependencies/fishhook/fishhook.h diff --git a/ATTRIBUTIONS b/ATTRIBUTIONS index d5a52b33..14dc7535 100644 --- a/ATTRIBUTIONS +++ b/ATTRIBUTIONS @@ -1,30 +1,3 @@ -fishhook - https://github.com/facebook/fishhook ------------------------------------------------ - -// Copyright (c) 2013, Facebook, Inc. -// All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name Facebook nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific -// prior written permission. -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - domain-registry-provider - https://code.google.com/p/domain-registry-provider/ ------------------------------------------------------------------------------ diff --git a/TrustKit.podspec b/TrustKit.podspec index 649bf251..6b0d10a4 100644 --- a/TrustKit.podspec +++ b/TrustKit.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| s.source = { :git => "https://github.com/datatheorem/TrustKit.git", :tag => "#{s.version}" } s.ios.deployment_target = '7.0' s.osx.deployment_target = '10.9' - s.source_files = 'TrustKit', 'TrustKit/**/*.{h,m}', 'TrustKit/Dependencies/fishhook/*.{h,c}' + s.source_files = 'TrustKit', 'TrustKit/**/*.{h,m}' s.public_header_files = 'TrustKit/TrustKit.h', 'TrustKit/Pinning/TSKPinningValidator.h' s.frameworks = 'Foundation', 'Security' s.ios.vendored_libraries = 'TrustKit/Dependencies/domain_registry/ios/*.a' diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 806ecfcb..373b9ccd 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -26,7 +26,6 @@ 8C84804D1A896EE30017C155 /* TrustKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C84804C1A896EE30017C155 /* TrustKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8C8480531A896EE30017C155 /* TrustKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C8480471A896EE30017C155 /* TrustKit.framework */; }; 8C84806D1A896F660017C155 /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C84806C1A896F660017C155 /* TrustKit.m */; }; - 8C8716AD1B23A9D200267E1D /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919311AEA0F8B002B29AE /* fishhook.c */; }; 8C8716B11B23A9F000267E1D /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; }; 8C8716B21B23A9F400267E1D /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */; }; 8C8716B31B23A9F700267E1D /* TSKPinFailureReport.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F99F1B16094D00F06C0E /* TSKPinFailureReport.m */; }; @@ -59,8 +58,6 @@ 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C84804C1A896EE30017C155 /* TrustKit.h */; settings = {ASSET_TAGS = (); }; }; 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C84806C1A896F660017C155 /* TrustKit.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC271BAE2B7000BDA419 /* domain_registry.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919291AEA0F7E002B29AE /* domain_registry.h */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC281BAE2B7500BDA419 /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919311AEA0F8B002B29AE /* fishhook.c */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC291BAE2B7500BDA419 /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919321AEA0F8B002B29AE /* fishhook.h */; settings = {ASSET_TAGS = (); }; }; 8CA6CC2F1BAE2C0700BDA419 /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC2C1BAE2C0700BDA419 /* libassert_lib.a */; settings = {ASSET_TAGS = (); }; }; 8CA6CC301BAE2C0700BDA419 /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC2D1BAE2C0700BDA419 /* libdomain_registry_lib.a */; settings = {ASSET_TAGS = (); }; }; 8CA6CC311BAE2C0700BDA419 /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC2E1BAE2C0700BDA419 /* libinit_registry_tables_lib.a */; settings = {ASSET_TAGS = (); }; }; @@ -115,8 +112,6 @@ 8CE919251AEA07C5002B29AE /* ssl_pin_verifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919241AEA07C5002B29AE /* ssl_pin_verifier.h */; }; 8CE919271AEA0991002B29AE /* TSKReporterDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919261AEA0991002B29AE /* TSKReporterDelegate.h */; }; 8CE9192D1AEA0F7E002B29AE /* domain_registry.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919291AEA0F7E002B29AE /* domain_registry.h */; }; - 8CE919351AEA0F8B002B29AE /* fishhook.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919311AEA0F8B002B29AE /* fishhook.c */; }; - 8CE919361AEA0F8B002B29AE /* fishhook.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919321AEA0F8B002B29AE /* fishhook.h */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -207,8 +202,6 @@ 8CE919241AEA07C5002B29AE /* ssl_pin_verifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ssl_pin_verifier.h; path = Pinning/ssl_pin_verifier.h; sourceTree = ""; }; 8CE919261AEA0991002B29AE /* TSKReporterDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKReporterDelegate.h; path = Reporting/TSKReporterDelegate.h; sourceTree = ""; }; 8CE919291AEA0F7E002B29AE /* domain_registry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = domain_registry.h; path = Dependencies/domain_registry/domain_registry.h; sourceTree = ""; }; - 8CE919311AEA0F8B002B29AE /* fishhook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fishhook.c; path = Dependencies/fishhook/fishhook.c; sourceTree = ""; }; - 8CE919321AEA0F8B002B29AE /* fishhook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fishhook.h; path = Dependencies/fishhook/fishhook.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -347,15 +340,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 8C84806B1A896F3C0017C155 /* fishhook */ = { - isa = PBXGroup; - children = ( - 8CE919311AEA0F8B002B29AE /* fishhook.c */, - 8CE919321AEA0F8B002B29AE /* fishhook.h */, - ); - name = fishhook; - sourceTree = ""; - }; 8CA6CC2A1BAE2BEA00BDA419 /* iOS */ = { isa = PBXGroup; children = ( @@ -462,7 +446,6 @@ isa = PBXGroup; children = ( 8CD5F73F1BCB06E8005801D8 /* RSSwizzle */, - 8C84806B1A896F3C0017C155 /* fishhook */, 8C3492901ADCA059001849FD /* domain_registry */, ); name = Dependencies; @@ -489,7 +472,6 @@ 8C15F9A01B16094D00F06C0E /* TSKPinFailureReport.h in Headers */, 8CE919271AEA0991002B29AE /* TSKReporterDelegate.h in Headers */, 8CE919251AEA07C5002B29AE /* ssl_pin_verifier.h in Headers */, - 8CE919361AEA0F8B002B29AE /* fishhook.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -511,7 +493,6 @@ 8CA6CC231BAE2B6A00BDA419 /* TSKPinningValidator.h in Headers */, 8CA6CC1D1BAE2B6600BDA419 /* reporting_utils.h in Headers */, 8CA6CC1F1BAE2B6A00BDA419 /* public_key_utils.h in Headers */, - 8CA6CC291BAE2B7500BDA419 /* fishhook.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -718,7 +699,6 @@ 8CD5F74B1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */, 6B032D3A1AF1794D00EAFA69 /* TSKSimpleReporter.m in Sources */, 8CE9191F1AEA073C002B29AE /* public_key_utils.m in Sources */, - 8CE919351AEA0F8B002B29AE /* fishhook.c in Sources */, 8C15F9A11B16094E00F06C0E /* TSKPinFailureReport.m in Sources */, 8C15F9941B132F9200F06C0E /* TSKPinningValidator.m in Sources */, 8CD5F7331BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, @@ -748,7 +728,6 @@ files = ( 8C8716B71B23AA0B00267E1D /* TSKPinningValidator.m in Sources */, 8C8716B51B23AA0600267E1D /* public_key_utils.m in Sources */, - 8C8716AD1B23A9D200267E1D /* fishhook.c in Sources */, 8C8716B31B23A9F700267E1D /* TSKPinFailureReport.m in Sources */, 8C8716B41B23A9FA00267E1D /* reporting_utils.m in Sources */, 8C8716B81B23AA0D00267E1D /* TrustKit.m in Sources */, @@ -772,7 +751,6 @@ 8CA6CC241BAE2B6A00BDA419 /* TSKPinningValidator.m in Sources */, 8CA6CC1E1BAE2B6600BDA419 /* reporting_utils.m in Sources */, 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */, - 8CA6CC281BAE2B7500BDA419 /* fishhook.c in Sources */, 8CA6CC151BAE2B6600BDA419 /* TSKReportsRateLimiter.m in Sources */, 8CD5F7351BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, 8CA6CC181BAE2B6600BDA419 /* TSKSimpleReporter.m in Sources */, diff --git a/TrustKit/Dependencies/fishhook/fishhook.c b/TrustKit/Dependencies/fishhook/fishhook.c deleted file mode 100755 index 7d6a1588..00000000 --- a/TrustKit/Dependencies/fishhook/fishhook.c +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright (c) 2013, Facebook, Inc. -// All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name Facebook nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific -// prior written permission. -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#import "fishhook.h" - -#import -#import -#import -#import -#import -#import -#import - -#ifdef __LP64__ -typedef struct mach_header_64 mach_header_t; -typedef struct segment_command_64 segment_command_t; -typedef struct section_64 section_t; -typedef struct nlist_64 nlist_t; -#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT_64 -#else -typedef struct mach_header mach_header_t; -typedef struct segment_command segment_command_t; -typedef struct section section_t; -typedef struct nlist nlist_t; -#define LC_SEGMENT_ARCH_DEPENDENT LC_SEGMENT -#endif - -#ifndef SEG_DATA_CONST -#define SEG_DATA_CONST "__DATA_CONST" -#endif - -struct rebindings_entry { - struct rebinding *rebindings; - size_t rebindings_nel; - struct rebindings_entry *next; -}; - -static struct rebindings_entry *_rebindings_head; - -static int prepend_rebindings(struct rebindings_entry **rebindings_head, - struct rebinding rebindings[], - size_t nel) { - struct rebindings_entry *new_entry = malloc(sizeof(struct rebindings_entry)); - if (!new_entry) { - return -1; - } - new_entry->rebindings = malloc(sizeof(struct rebinding) * nel); - if (!new_entry->rebindings) { - free(new_entry); - return -1; - } - memcpy(new_entry->rebindings, rebindings, sizeof(struct rebinding) * nel); - new_entry->rebindings_nel = nel; - new_entry->next = *rebindings_head; - *rebindings_head = new_entry; - return 0; -} - -static void perform_rebinding_with_section(struct rebindings_entry *rebindings, - section_t *section, - intptr_t slide, - nlist_t *symtab, - char *strtab, - uint32_t *indirect_symtab) { - uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1; - void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr); - for (uint i = 0; i < section->size / sizeof(void *); i++) { - uint32_t symtab_index = indirect_symbol_indices[i]; - if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL || - symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) { - continue; - } - uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx; - char *symbol_name = strtab + strtab_offset; - struct rebindings_entry *cur = rebindings; - while (cur) { - for (uint j = 0; j < cur->rebindings_nel; j++) { - if (strlen(symbol_name) > 1 && - strcmp(&symbol_name[1], cur->rebindings[j].name) == 0) { - indirect_symbol_bindings[i] = cur->rebindings[j].replacement; - goto symbol_loop; - } - } - cur = cur->next; - } - symbol_loop:; - } -} - -static void rebind_symbols_for_image(struct rebindings_entry *rebindings, - const struct mach_header *header, - intptr_t slide) { - Dl_info info; - if (dladdr(header, &info) == 0) { - return; - } - - segment_command_t *cur_seg_cmd; - segment_command_t *linkedit_segment = NULL; - struct symtab_command* symtab_cmd = NULL; - struct dysymtab_command* dysymtab_cmd = NULL; - - uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t); - for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { - cur_seg_cmd = (segment_command_t *)cur; - if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { - if (strcmp(cur_seg_cmd->segname, SEG_LINKEDIT) == 0) { - linkedit_segment = cur_seg_cmd; - } - } else if (cur_seg_cmd->cmd == LC_SYMTAB) { - symtab_cmd = (struct symtab_command*)cur_seg_cmd; - } else if (cur_seg_cmd->cmd == LC_DYSYMTAB) { - dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd; - } - } - - if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment || - !dysymtab_cmd->nindirectsyms) { - return; - } - - // Find base symbol/string table addresses - uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff; - nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff); - char *strtab = (char *)(linkedit_base + symtab_cmd->stroff); - - // Get indirect symbol table (array of uint32_t indices into symbol table) - uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff); - - cur = (uintptr_t)header + sizeof(mach_header_t); - for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) { - cur_seg_cmd = (segment_command_t *)cur; - if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) { - if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 && - strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) { - continue; - } - for (uint j = 0; j < cur_seg_cmd->nsects; j++) { - section_t *sect = - (section_t *)(cur + sizeof(segment_command_t)) + j; - if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) { - perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); - } - if ((sect->flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS) { - perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab); - } - } - } - } -} - -static void _rebind_symbols_for_image(const struct mach_header *header, - intptr_t slide) { - rebind_symbols_for_image(_rebindings_head, header, slide); -} - -int rebind_symbols_image(void *header, - intptr_t slide, - struct rebinding rebindings[], - size_t rebindings_nel) { - struct rebindings_entry *rebindings_head = NULL; - int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel); - rebind_symbols_for_image(rebindings_head, header, slide); - free(rebindings_head); - return retval; -} - -int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) { - int retval = prepend_rebindings(&_rebindings_head, rebindings, rebindings_nel); - if (retval < 0) { - return retval; - } - // If this was the first call, register callback for image additions (which is also invoked for - // existing images, otherwise, just run on existing images - if (!_rebindings_head->next) { - _dyld_register_func_for_add_image(_rebind_symbols_for_image); - } else { - uint32_t c = _dyld_image_count(); - for (uint32_t i = 0; i < c; i++) { - _rebind_symbols_for_image(_dyld_get_image_header(i), _dyld_get_image_vmaddr_slide(i)); - } - } - return retval; -} \ No newline at end of file diff --git a/TrustKit/Dependencies/fishhook/fishhook.h b/TrustKit/Dependencies/fishhook/fishhook.h deleted file mode 100755 index 6a7af766..00000000 --- a/TrustKit/Dependencies/fishhook/fishhook.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) 2013, Facebook, Inc. -// All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name Facebook nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific -// prior written permission. -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef fishhook_h -#define fishhook_h - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif //__cplusplus - -/* - * A structure representing a particular intended rebinding from a symbol - * name to its replacement - */ -struct rebinding { - char *name; - void *replacement; -}; - -/* - * For each rebinding in rebindings, rebinds references to external, indirect - * symbols with the specified name to instead point at replacement for each - * image in the calling process as well as for all future images that are loaded - * by the process. If rebind_functions is called more than once, the symbols to - * rebind are added to the existing list of rebindings, and if a given symbol - * is rebound more than once, the later rebinding will take precedence. - */ -int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel); - -/* - * Rebinds as above, but only in the specified image. The header should point - * to the mach-o header, the slide should be the slide offset. Others as above. - */ -int rebind_symbols_image(void *header, - intptr_t slide, - struct rebinding rebindings[], - size_t rebindings_nel); - -#ifdef __cplusplus -} -#endif //__cplusplus - -#endif //fishhook_h - From ff0348ae5d3d43d3d1c5a2c6127f037ac2eeea18 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 12:28:48 -0700 Subject: [PATCH 094/118] Add stricter warning flags --- TrustKit.xcodeproj/project.pbxproj | 14 ++++++++++++-- TrustKitTests/TSKPinConfigurationTests.m | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 373b9ccd..2dadc923 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -93,8 +93,8 @@ 8CD5F7391BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */; settings = {ASSET_TAGS = (); }; }; 8CD5F7421BCB06F4005801D8 /* RSSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7431BCB06F4005801D8 /* RSSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */; settings = {ASSET_TAGS = (); }; }; - 8CD5F7441BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); }; }; - 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); }; }; + 8CD5F7441BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion"; }; }; + 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion"; }; }; 8CD5F7491BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F74A1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F74B1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; @@ -803,6 +803,7 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -822,7 +823,11 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -852,6 +857,7 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_UNREACHABLE_CODE = YES; @@ -864,7 +870,11 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; + GCC_WARN_SHADOW = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; diff --git a/TrustKitTests/TSKPinConfigurationTests.m b/TrustKitTests/TSKPinConfigurationTests.m index 8b1d5ffd..54e05003 100644 --- a/TrustKitTests/TSKPinConfigurationTests.m +++ b/TrustKitTests/TSKPinConfigurationTests.m @@ -219,4 +219,4 @@ - (void)testGlobalSettings XCTAssert([trustKitConfig[kTSKSwizzleNetworkDelegates] boolValue] == NO, @"kTSKSwizzleNetworkDelegates was not saved in the configuration"); } -@end \ No newline at end of file +@end From 3b2ecb22684532d12ac12cf8cfa8e645200be7ed Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 12:29:35 -0700 Subject: [PATCH 095/118] Add missing file in static target --- TrustKit.xcodeproj/project.pbxproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 2dadc923..3b11a1ee 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -84,6 +84,7 @@ 8CC78B281B1B696D00523A25 /* sni41871.cloudflaressl.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1D1B1B55EC00523A25 /* sni41871.cloudflaressl.com.der */; }; 8CC78B291B1B697000523A25 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1C1B1B55EC00523A25 /* COMODOECCDomainValidationSecureServerCA2.der */; }; 8CCBD15B1B186D1100CB88AF /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCBD15A1B186D1100CB88AF /* reporting_utils.m */; }; + 8CD0D4171BD42A7D004478C0 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion"; }; }; 8CD5F7311BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7321BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7331BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; @@ -737,6 +738,7 @@ 8CD5F7341BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, 8C8716B11B23A9F000267E1D /* TSKSimpleReporter.m in Sources */, 8C8716B61B23AA0800267E1D /* ssl_pin_verifier.m in Sources */, + 8CD0D4171BD42A7D004478C0 /* RSSwizzle.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 5b300007f107aacf39870947ef688ef2f772f795 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 12:40:57 -0700 Subject: [PATCH 096/118] Enable stricter warnings --- TrustKit.xcodeproj/project.pbxproj | 2 ++ TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 12 +++++++++--- TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m | 12 +++++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 3b11a1ee..c6c5d722 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -800,6 +800,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_ASSIGN_ENUM = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; @@ -854,6 +855,7 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_ASSIGN_ENUM = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index a3d79ca8..d0539fc5 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -13,9 +13,10 @@ // Useful for the tests +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wassign-enum" static TSKTrustDecision _lastTrustDecision = -1; - typedef void (^AsyncCompletionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError); @@ -26,7 +27,8 @@ -(BOOL)forwardToOriginalDelegateAuthenticationChallenge:(NSURLAuthenticationChal @implementation TSKNSURLConnectionDelegateProxy -// Private methods used for tests + +#pragma mark Private methods used for tests +(void)resetLastTrustDecision { _lastTrustDecision = -1;; @@ -36,7 +38,10 @@ +(TSKTrustDecision)getLastTrustDecision { return _lastTrustDecision; } +#pragma clang diagnostic pop + +#pragma mark Public methods + (void)swizzleNSURLConnectionConstructors { @@ -132,11 +137,12 @@ - (instancetype)initWithDelegate:(id)delegate originalDelegate = delegate; } TSKLog(@"Proxy-ing NSURLConnectionDelegate: %@", NSStringFromClass([delegate class])); - _lastTrustDecision = -1; return self; } +#pragma mark Delegate methods + - (BOOL)respondsToSelector:(SEL)aSelector { if (aSelector == @selector(connection:willSendRequestForAuthenticationChallenge:)) diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 0362f79a..0a0a0120 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -12,13 +12,14 @@ // Useful for the tests +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wassign-enum" static TSKTrustDecision _lastTrustDecision = -1; - @implementation TSKNSURLSessionDelegateProxy -// Private methods used for tests +#pragma mark Private methods used for tests +(void)resetLastTrustDecision { _lastTrustDecision = -1;; @@ -28,8 +29,12 @@ +(TSKTrustDecision)getLastTrustDecision { return _lastTrustDecision; } +#pragma clang diagnostic pop + +#pragma mark Public methods + + (void)swizzleNSURLSessionConstructors { // Figure out NSURLSession's "real" class @@ -100,11 +105,12 @@ - (instancetype)initWithDelegate:(id)delegate originalDelegate = delegate; } TSKLog(@"Proxy-ing NSURLSessionDelegate: %@", NSStringFromClass([delegate class])); - _lastTrustDecision = -1; return self; } +#pragma mark Delegate methods + - (BOOL)respondsToSelector:(SEL)aSelector { if (aSelector == @selector(URLSession:task:didReceiveChallenge:completionHandler:)) From 79cfbcd2ec864776f172e4061c54dc7e41de28c3 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 12:47:41 -0700 Subject: [PATCH 097/118] Fix new warnings brought by stricter Xcode settings --- TrustKit/Reporting/TSKPinFailureReport.m | 2 +- TrustKit/Reporting/reporting_utils.m | 2 +- TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m | 10 ++++------ TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m | 12 ++++-------- TrustKit/TrustKit.m | 2 +- TrustKitTests/TSKReporterTests.m | 8 ++++---- 6 files changed, 15 insertions(+), 21 deletions(-) diff --git a/TrustKit/Reporting/TSKPinFailureReport.m b/TrustKit/Reporting/TSKPinFailureReport.m index 7148158c..ce1e5d2e 100644 --- a/TrustKit/Reporting/TSKPinFailureReport.m +++ b/TrustKit/Reporting/TSKPinFailureReport.m @@ -69,7 +69,7 @@ - (NSData *)json; }; NSError *error; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:requestData options:0 error:&error]; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:requestData options:(NSJSONWritingOptions)0 error:&error]; return jsonData; } diff --git a/TrustKit/Reporting/reporting_utils.m b/TrustKit/Reporting/reporting_utils.m index 12044ff6..2070c261 100644 --- a/TrustKit/Reporting/reporting_utils.m +++ b/TrustKit/Reporting/reporting_utils.m @@ -37,7 +37,7 @@ NSMutableArray *formattedPins = [NSMutableArray array]; for (NSData *pin in knownPins) { - [formattedPins addObject:[NSString stringWithFormat:@"pin-sha256=\"%@\"", [pin base64EncodedStringWithOptions:0]]]; + [formattedPins addObject:[NSString stringWithFormat:@"pin-sha256=\"%@\"", [pin base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0]]]; } return formattedPins; } diff --git a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m index d0539fc5..5d1a9f9f 100644 --- a/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLConnectionDelegateProxy.m @@ -12,10 +12,6 @@ #import "RSSwizzle.h" -// Useful for the tests -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wassign-enum" -static TSKTrustDecision _lastTrustDecision = -1; typedef void (^AsyncCompletionHandler)(NSURLResponse *response, NSData *data, NSError *connectionError); @@ -29,16 +25,18 @@ @implementation TSKNSURLConnectionDelegateProxy #pragma mark Private methods used for tests + +static TSKTrustDecision _lastTrustDecision = (TSKTrustDecision)-1; + +(void)resetLastTrustDecision { - _lastTrustDecision = -1;; + _lastTrustDecision = (TSKTrustDecision)-1; } +(TSKTrustDecision)getLastTrustDecision { return _lastTrustDecision; } -#pragma clang diagnostic pop #pragma mark Public methods diff --git a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m index 0a0a0120..7f7ecb97 100644 --- a/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m +++ b/TrustKit/Swizzling/TSKNSURLSessionDelegateProxy.m @@ -11,26 +11,22 @@ #import "TrustKit+Private.h" -// Useful for the tests -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wassign-enum" -static TSKTrustDecision _lastTrustDecision = -1; - @implementation TSKNSURLSessionDelegateProxy #pragma mark Private methods used for tests + +static TSKTrustDecision _lastTrustDecision = (TSKTrustDecision)-1; + +(void)resetLastTrustDecision { - _lastTrustDecision = -1;; + _lastTrustDecision = (TSKTrustDecision)-1; } +(TSKTrustDecision)getLastTrustDecision { return _lastTrustDecision; } -#pragma clang diagnostic pop - #pragma mark Public methods diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index dc19a58b..af5eb608 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -299,7 +299,7 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus NSMutableArray *serverSslPinsData = [[NSMutableArray alloc] init]; for (NSString *pinnedKeyHashBase64 in serverSslPinsBase64) { - NSData *pinnedKeyHash = [[NSData alloc] initWithBase64EncodedString:pinnedKeyHashBase64 options:0]; + NSData *pinnedKeyHash = [[NSData alloc] initWithBase64EncodedString:pinnedKeyHashBase64 options:(NSDataBase64DecodingOptions)0]; if ([pinnedKeyHash length] != CC_SHA256_DIGEST_LENGTH) { diff --git a/TrustKitTests/TSKReporterTests.m b/TrustKitTests/TSKReporterTests.m index 55352e9c..45ad7083 100644 --- a/TrustKitTests/TSKReporterTests.m +++ b/TrustKitTests/TSKReporterTests.m @@ -68,8 +68,8 @@ - (void)testSimpleReporter reportURIs:@[[NSURL URLWithString:@"http://127.0.0.1:8080/log_report"]] includeSubdomains:YES knownPins:@[ - [[NSData alloc]initWithBase64EncodedString:@"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" options:0], - [[NSData alloc]initWithBase64EncodedString:@"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" options:0], + [[NSData alloc]initWithBase64EncodedString:@"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" options:(NSDataBase64DecodingOptions)0], + [[NSData alloc]initWithBase64EncodedString:@"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" options:(NSDataBase64DecodingOptions)0], ] validationResult:TSKPinValidationResultFailed]; @@ -83,8 +83,8 @@ - (void)testReportsRateLimiter { // Create the pin validation failure report NSArray *certificateChain = convertTrustToPemArray(_testTrust); - NSArray *formattedPins = convertPinsToHpkpPins(@[[[NSData alloc]initWithBase64EncodedString:@"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" options:0], - [[NSData alloc]initWithBase64EncodedString:@"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" options:0],]); + NSArray *formattedPins = convertPinsToHpkpPins(@[[[NSData alloc]initWithBase64EncodedString:@"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" options:(NSDataBase64DecodingOptions)0], + [[NSData alloc]initWithBase64EncodedString:@"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" options:(NSDataBase64DecodingOptions)0],]); TSKPinFailureReport *report = [[TSKPinFailureReport alloc] initWithAppBundleId:@"test" From 9d5b0263f7cc56c61d2362667f68183c52db98a5 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 13:24:50 -0700 Subject: [PATCH 098/118] Enable stricter warnings --- TrustKit.xcodeproj/project.pbxproj | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index c6c5d722..aa7795cd 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -84,7 +84,7 @@ 8CC78B281B1B696D00523A25 /* sni41871.cloudflaressl.com.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1D1B1B55EC00523A25 /* sni41871.cloudflaressl.com.der */; }; 8CC78B291B1B697000523A25 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1C1B1B55EC00523A25 /* COMODOECCDomainValidationSecureServerCA2.der */; }; 8CCBD15B1B186D1100CB88AF /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCBD15A1B186D1100CB88AF /* reporting_utils.m */; }; - 8CD0D4171BD42A7D004478C0 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion"; }; }; + 8CD0D4171BD42A7D004478C0 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion -Wno-sign-compare"; }; }; 8CD5F7311BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7321BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7331BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; @@ -94,8 +94,8 @@ 8CD5F7391BCB02A7005801D8 /* TSKNSURLConnectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7371BCB02A7005801D8 /* TSKNSURLConnectionTests.m */; settings = {ASSET_TAGS = (); }; }; 8CD5F7421BCB06F4005801D8 /* RSSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7431BCB06F4005801D8 /* RSSwizzle.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7401BCB06F4005801D8 /* RSSwizzle.h */; settings = {ASSET_TAGS = (); }; }; - 8CD5F7441BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion"; }; }; - 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion"; }; }; + 8CD5F7441BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion -Wno-sign-compare"; }; }; + 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion -Wno-sign-compare"; }; }; 8CD5F7491BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F74A1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F7471BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F74B1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7481BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; @@ -809,6 +809,7 @@ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -831,6 +832,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; @@ -864,6 +866,7 @@ CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -879,6 +882,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; + GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; From 2527acc4b338e90a7034db215028d1645183321c Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 20:15:37 -0700 Subject: [PATCH 099/118] Last pass on enabling compiler warnings --- TrustKit.xcodeproj/project.pbxproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index aa7795cd..477a90e9 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -827,14 +827,17 @@ ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MTL_ENABLE_DEBUG_INFO = YES; @@ -877,14 +880,17 @@ ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; GCC_WARN_SHADOW = YES; GCC_WARN_SIGN_COMPARE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNKNOWN_PRAGMAS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MTL_ENABLE_DEBUG_INFO = NO; From b0e1ed32cad3f29a394f73325e1e3d2243c8f508 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 21:15:19 -0700 Subject: [PATCH 100/118] Update default report URI --- TrustKit/TrustKit.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index af5eb608..4f7c0c84 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -58,7 +58,7 @@ // Default report URI - can be disabled with TSKDisableDefaultReportUri -static NSString * const kTSKDefaultReportUri = @"https://trustkit-reports-server.appspot.com/log_report"; +static NSString * const kTSKDefaultReportUri = @"https://overmind.datatheorem.com/trustkit/report"; #pragma mark Logging Function From 0c8b295f9d58084bd704f2288e489cb028511632 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 23:39:47 -0700 Subject: [PATCH 101/118] Update README --- README.md | 122 +++++++++++++++++--------------------------- TrustKit/TrustKit.h | 3 +- 2 files changed, 50 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index cfd21cf9..890fda98 100644 --- a/README.md +++ b/README.md @@ -3,59 +3,18 @@ TrustKit [![Build Status](https://travis-ci.org/datatheorem/TrustKit.svg)](https://travis-ci.org/datatheorem/TrustKit) [![Version Status](https://img.shields.io/cocoapods/v/TrustKit.svg?style=flat)](https://cocoapods.org/pods/TrustKit) [![Platform](https://img.shields.io/cocoapods/p/TrustKit.svg?style=flat)](https://cocoapods.org/pods/TrustKit) [![License MIT](https://img.shields.io/cocoapods/l/TrustKit.svg?style=flat)](https://en.wikipedia.org/wiki/MIT_License) -**TrustKit** is an open source framework that makes it easy to deploy SSL public key -pinning in any iOS or OS X App. - - -iOS 9 FAQ ---------- - -### Does **TrustKit** work on iOS 9? - -* Explicit pinning validation using the `TSKPinningValidator` class in your -authentication handlers will work fine. -* Implicit pinning validation, where **TrustKit** automatically "hooks" and -validates the App's 'outgoing SSL connections does not work with the current -version (1.1.3) on iOS 9, on some devices (including the iPhone 6). This -means that the App will still work fine but the pinning validation will not -be performed automatically. - - -### What should I do? - -For pinning to work right now on iOS 9 devices, you can use the -`TSKPinningValidator` class to manually check the server's certificate chain -against your App's pinning policy. - -Apple has made changes in how function calls happen within and across Apple -frameworks, which break the technique we used in **TrustKit** to intercept outgoing -SSL connections. The next release of **TrustKit** (1.2.0) will address this as much -as technically possible, and a blog post with technical details on what has changed -will be available shortly. +**TrustKit** is an open source framework that makes it easy to deploy SSL public key pinning in any iOS or OS X App; it supports both Swift and Objective-C Apps. Overview -------- -At a high level, **TrustKit** intercepts all outgoing SSL connections initiated by -SecureTransport in order to perform additional validation against the server's -certificate chain, based on an App-wide SSL pinning policy. This novel approach -to SSL pinning gives us the following benefits: - -* Easy to use: **TrustKit** can be deployed in minutes in any App. For iOS8+ and OS -X Apps, **TrustKit** can be used without even modifying the App's source code. -* API-independent pinning by directly hooking Apple's SecureTransport: **TrustKit** -works on `NSURLSession`, `UIWebView`, `NSStream`, etc. all the way down to BSD -sockets. +**TrustKit** provides the following features: -Additionally, **TrustKit** provides the following features: - -* Subject Public Key Info pinning, [as opposed to certificate pinning or pinning -the public key bits](https://www.imperialviolet.org/2011/05/04/pinning.html). -* Mechanism to report pinning failures, which allows Apps to send reports -when an unexpected certificate chain is detected, similarly to the _report-uri_ -directive described in the [HTTP Public Key Pinning -specification](https://tools.ietf.org/html/rfc7469). +* Simple API to configure an SSL pinning policy and enforce it within an App. The policy settings are heavily based on the [HTTP Public Key Pinning specification](https://tools.ietf.org/html/rfc7469). +* Auto-pinning functionality by swizzling the App's _NSURLConnection_ and _NSURLSession_ delegates in order to automatically add pinning validation to the App's HTTPS connections; this allows deploying **TrustKit** without even modifying the App's source code. +* Sane implementation by pinning the certificate's Subject Public Key Info, [as opposed to the certificate itself or the public key bits](https://www.imperialviolet.org/2011/05/04/pinning.html). +* Reporting mechanism to notify a server about pinning validation failures happening within the App, when an unexpected certificate chain is detected. This is similar to the _report-uri_ directive described in the HPKP specification. **TrustKit** was open-sourced at [Black Hat 2015 USA][bh2015-conf]. @@ -63,9 +22,9 @@ specification](https://tools.ietf.org/html/rfc7469). Getting Started --------------- -* Have a look at the Black Hat USA 2015 [presentation][bh2015-pdf]. * Read the [Getting Started][getting-started] guide. * Check out the [API documentation][api-doc]. +* Have a look at the [Black Hat USA 2015 presentation][bh2015-pdf] and the [significant changes][ios9-post] that subsequently happened with iOS 9. Sample Usage @@ -83,7 +42,7 @@ Then run: $ pod install ``` -Then, enabling SSL pinning globally in the App only requires initializing **TrustKit** +Then, the deploying SSL pinning in the App requires initializing **TrustKit** with a pinning policy (domains, Subject Public Key Info hashes, and additional settings). The policy can be configured within the App's `Info.plist`: @@ -95,32 +54,48 @@ Alternatively, the pinning policy can be set programmatically: ```objc NSDictionary *trustKitConfig; trustKitConfig = @{ - @"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[ - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", - @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" - ], - kTSKEnforcePinning : @NO, - kTSKReportUris : @[@"http://report.datatheorem.com/log_report"], - }, - @"yahoo.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[ - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", - ], - kTSKIncludeSubdomains : @YES - } - }; + kTSKSwizzleNetworkDelegates: @YES, + kTSKPinnedDomains : @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[ + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", + @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" + ], + kTSKEnforcePinning : @NO, + kTSKReportUris : @[@"http://report.datatheorem.com/log_report"], + }, + @"yahoo.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[ + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", + ], + kTSKIncludeSubdomains : @YES + } + }}; [TrustKit initializeWithConfiguration:trustKitConfig]; ``` -Once **TrustKit** has been initialized, all SSL connections initiated by Apple -frameworks within the App will verify the server' certificate chains against the -supplied pinning policy. If report URIs have been configured, the App will also -send reports to the specified URIs whenever a pin validation failure occurred. +The policy can also be set programmatically in Swift Apps: + +```swift +let trustKitConfig = [ + kTSKPinnedDomains: [ + "yahoo.com": [ + kTSKPublicKeyAlgorithms: [kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes: [ + "JbQbUG5JMJUoI6brnx0x3vZF6jilxsapbXGVfjhN8Fg=", + "WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=" + ],]]] + +TrustKit.initializeWithConfiguration(config) +``` + +Once **TrustKit** has been initialized, it will by default swizzle the App's _NSURLSession_ and _NSURLConnection_ delegates to verify the server's certificate against the configured pinning policy, whenever an HTTPS connection is initiated. If report URIs have been configured, the App will also send reports to the specified URIs whenever a pin validation failure occurred. + +The swizzling behavior can be disabled via the `kTSKSwizzleNetworkDelegates` setting, and a server's certificate chain can easily be checked against the App's SSL pinning policy using the `TSKPinningValidator` class (for example to implement an authentication handler). For more information, see the [Getting Started][getting-started] guide. @@ -128,8 +103,7 @@ For more information, see the [Getting Started][getting-started] guide. Credits ------- -**TrustKit** is a joint-effort between the security teams at Data Theorem and Yahoo. -See `AUTHORS` for details. +**TrustKit** is a joint-effort between the security teams at Data Theorem and Yahoo. See `AUTHORS` for details. License @@ -141,4 +115,4 @@ License [bh2015-pdf]: https://datatheorem.github.io/TrustKit/files/TrustKit-BH2015.pdf [bh2015-conf]: https://www.blackhat.com/us-15/briefings.html#trustkit-code-injection-on-ios-8-for-the-greater-good [api-doc]: https://datatheorem.github.io/TrustKit/documentation - +[ios9-post]: https://datatheorem.github.io/ios/2015/10/17/trustkit-ios-9-shared-cache/ \ No newline at end of file diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 217c86a6..646a2e59 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -62,6 +62,7 @@ FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmEcDsaSecp256r1; NSDictionary *trustKitConfig; trustKitConfig = @{ + kTSKSwizzleNetworkDelegates: @YES, kTSKPinnedDomains : @{ @"www.datatheorem.com" : @{ kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], @@ -70,7 +71,7 @@ FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmEcDsaSecp256r1; @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" ], kTSKEnforcePinning : @NO, - kTSKReportUris : @[@"http://report.datatheorem.com/log_hpkp_report"], + kTSKReportUris : @[@"http://report.datatheorem.com/log_report"], }, @"yahoo.com" : @{ kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], From 6b6e0ce275907363d8af4efbca4b3a1cbbbae639 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Sun, 18 Oct 2015 23:44:20 -0700 Subject: [PATCH 102/118] Tweak formatting --- README.md | 48 ++++++++++++++++++++++----------------------- TrustKit/TrustKit.h | 44 ++++++++++++++++++++--------------------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 890fda98..5c674506 100644 --- a/README.md +++ b/README.md @@ -52,28 +52,28 @@ The policy can be configured within the App's `Info.plist`: Alternatively, the pinning policy can be set programmatically: ```objc -NSDictionary *trustKitConfig; -trustKitConfig = @{ - kTSKSwizzleNetworkDelegates: @YES, - kTSKPinnedDomains : @{ - @"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[ - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", - @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" - ], - kTSKEnforcePinning : @NO, - kTSKReportUris : @[@"http://report.datatheorem.com/log_report"], - }, - @"yahoo.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[ - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", - ], - kTSKIncludeSubdomains : @YES - } - }}; +NSDictionary *trustKitConfig = +@{ + kTSKSwizzleNetworkDelegates: @YES, + kTSKPinnedDomains : @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[ + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", + @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" + ], + kTSKEnforcePinning : @NO, + kTSKReportUris : @[@"http://report.datatheorem.com/log_report"], + }, + @"yahoo.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[ + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", + ], + kTSKIncludeSubdomains : @YES + } + }}; [TrustKit initializeWithConfiguration:trustKitConfig]; ``` @@ -95,7 +95,7 @@ TrustKit.initializeWithConfiguration(config) Once **TrustKit** has been initialized, it will by default swizzle the App's _NSURLSession_ and _NSURLConnection_ delegates to verify the server's certificate against the configured pinning policy, whenever an HTTPS connection is initiated. If report URIs have been configured, the App will also send reports to the specified URIs whenever a pin validation failure occurred. -The swizzling behavior can be disabled via the `kTSKSwizzleNetworkDelegates` setting, and a server's certificate chain can easily be checked against the App's SSL pinning policy using the `TSKPinningValidator` class (for example to implement an authentication handler). +The swizzling behavior can be disabled via the `kTSKSwizzleNetworkDelegates` setting, and a server's certificate chain can easily be checked against the App's SSL pinning policy using the `TSKPinningValidator` class, for example to implement an authentication handler. For more information, see the [Getting Started][getting-started] guide. @@ -115,4 +115,4 @@ License [bh2015-pdf]: https://datatheorem.github.io/TrustKit/files/TrustKit-BH2015.pdf [bh2015-conf]: https://www.blackhat.com/us-15/briefings.html#trustkit-code-injection-on-ios-8-for-the-greater-good [api-doc]: https://datatheorem.github.io/TrustKit/documentation -[ios9-post]: https://datatheorem.github.io/ios/2015/10/17/trustkit-ios-9-shared-cache/ \ No newline at end of file +[ios9-post]: https://datatheorem.github.io/ios/2015/10/17/trustkit-ios-9-shared-cache/ diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 646a2e59..80316fd6 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -60,28 +60,28 @@ FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmEcDsaSecp256r1; When setting the pinning policy programmatically, it has to be supplied to the `initializeWithConfiguration:` method as a dictionnary. For example: - NSDictionary *trustKitConfig; - trustKitConfig = @{ - kTSKSwizzleNetworkDelegates: @YES, - kTSKPinnedDomains : @{ - @"www.datatheorem.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], - kTSKPublicKeyHashes : @[ - @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", - @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" - ], - kTSKEnforcePinning : @NO, - kTSKReportUris : @[@"http://report.datatheorem.com/log_report"], - }, - @"yahoo.com" : @{ - kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], - kTSKPublicKeyHashes : @[ - @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", - @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", - ], - kTSKIncludeSubdomains : @YES - } - }}; + NSDictionary *trustKitConfig = + @{ + kTSKSwizzleNetworkDelegates: @YES, + kTSKPinnedDomains : @{ + @"www.datatheorem.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa2048], + kTSKPublicKeyHashes : @[ + @"HXXQgxueCIU5TTLHob/bPbwcKOKw6DkfsTWYHbxbqTY=", + @"0SDf3cRToyZJaMsoS17oF72VMavLxj/N7WBNasNuiR8=" + ], + kTSKEnforcePinning : @NO, + kTSKReportUris : @[@"http://report.datatheorem.com/log_report"], + }, + @"yahoo.com" : @{ + kTSKPublicKeyAlgorithms : @[kTSKAlgorithmRsa4096], + kTSKPublicKeyHashes : @[ + @"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=", + @"rFjc3wG7lTZe43zeYTvPq8k4xdDEutCmIhI5dn4oCeE=", + ], + kTSKIncludeSubdomains : @YES + } + }}; [TrustKit initializeWithConfiguration:trustKitConfig]; From 447d3fd2964fb34d56a42d986a737918f82024fc Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 19 Oct 2015 14:45:11 -0700 Subject: [PATCH 103/118] Update the getting started guide --- docs/getting-started.md | 60 +++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 02e4d7e1..9fc9046d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -165,6 +165,49 @@ After supplying the pinning policy, and if `kTSKSwizzleNetworkDelegates` is set the App's `NSURLConnection` and `NSURLSession` delegates will automatically enforce the policy. +Manual Pin Validation +--------------------- + +In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically +validate the server's identity against the pinning policy. For these connections, the pin validation +must be manually triggered: the server's trust object, which contains its certificate chain, needs to +be retrieved or built before being passed to the +[`TSKPinningValidator` class](https://datatheorem.github.io/TrustKit/documentation/Classes/TSKPinningValidator.html) +for validation. + +`TSKPinningValidator` returns a `TSKTrustDecision` which describes whether the SSL connection +should be allowed or blocked, based on the App's SSL pinning policy. + + The following connections require manual pin validation: + + 1. All connections within an App that disables TrustKit's network delegate swizzling by setting the `kTSKSwizzleNetworkDelegates` configuration key to `NO`. + 2. Connections that do not rely on the `NSURLConnection` or `NSURLSession` APIs: + * Connections leveraging different network APIs (such as `NSStream`). Instructions on how to retrieve the server's trust object are available in the [Apple documentation](https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html). + * Connections initiated using a third-party SSL library such as OpenSSL. The server's trust object needs to be built using the received certificate chain. + 3. Connections happening within an external process: + * `WKWebView` connections: the server's trust object can be retrieved and validated within the `webView:didReceiveAuthenticationChallenge:completionHandler:` method. + * `NSURLSession` connections using the background transfer service: the server's trust object can be retrieved and validated within the `application:handleEventsForBackgroundURLSession:completionHandler:` method. + + +Pinning in WebViews +------------------- + +Adding SSL pinning to connections initiated within a `UIWebView` is difficult as the class does not +provide direct APIs to handle authentication challenges. As mentionned in +[Apple's technical note about HTTPS trust evaluation](https://developer.apple.com/library/ios/technotes/tn2232/_index.html), +customizing certificate validation in a `UIWebView` can still be achieved using `NSURLProtocol` to intercept all outgoing +connections. However, implemeting this technique is a complex and significant engineering effort. + +Overall, the best approach to implementing SSL pinning in webviews seems to be by migrating to +the `WKWebView` class introduced in iOS 8, which provides +[delegate methods](https://developer.apple.com/library/ios/documentation/WebKit/Reference/WKNavigationDelegate_Ref/) to handle authentication challenges (such as server SSL certificate +validation). However, this approach still requires some testing as it seems like the +`webView:didReceiveAuthenticationChallenge:completionHandler:` delegate method [only works reliably on iOS 9](https://bugs.webkit.org/show_bug.cgi?id=135327). + + +Other Ways to Embed TrustKit +---------------------------- + ### Adding TrustKit as a Dependency - Static Linking If CocoaPods can't be used and for Apps targeting iOS 7, TrustKit can be statically @@ -207,20 +250,3 @@ dynamically linked. 3. Lastly, initialize TrustKit with your pinning policy. -Manual Pin Validation ---------------------- - -In specific scenarios, TrustKit cannot intercept outgoing SSL connections and automatically validate the server's identity against the pinning policy. For these connections, the pin validation must be manually triggered: the server's trust object, which contains its certificate chain, needs to be retrieved or built before being passed to the [TSKPinningValidator class](https://datatheorem.github.io/TrustKit/documentation/Classes/TSKPinningValidator.html) for validation. - - `TSKPinningValidator` returns a `TSKTrustDecision` which describes whether the SSL connection should be allowed or blocked, based on the global pinning policy. - - The following connections require manual pin validation: - - 1. All connections within an App that disables TrustKit's network delegate swizzling by setting the `kTSKSwizzleNetworkDelegates` configuration key to `NO`. - 2. Connections that do not rely on the `NSURLConnection` or `NSURLSession` APIs: - * Connections leveraging lower-level APIs (such as `NSStream`). Instructions on how to retrieve the server's trust object are available at https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html. - * Connections initiated using a third-party SSL library such as OpenSSL. The server's trust object needs to be built using the received certificate chain. - 3. Connections happening within an external process: - * `WKWebView` connections: the server's trust object can be retrieved and validated within the `webView:didReceiveAuthenticationChallenge:completionHandler:` method. - * `NSURLSession` connections using the background transfer service: the server's trust object can be retrieved and validated within the `application:handleEventsForBackgroundURLSession:completionHandler:` method. - From e84abf91876f6377386070efe06649f243264c62 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 19 Oct 2015 17:43:06 -0700 Subject: [PATCH 104/118] Fix import --- TrustKitDemo/TrustKitDemo/AppDelegate.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TrustKitDemo/TrustKitDemo/AppDelegate.m b/TrustKitDemo/TrustKitDemo/AppDelegate.m index ac512fcb..bca54d1a 100644 --- a/TrustKitDemo/TrustKitDemo/AppDelegate.m +++ b/TrustKitDemo/TrustKitDemo/AppDelegate.m @@ -10,7 +10,7 @@ */ #import "AppDelegate.h" -#import "TrustKit.h" +#import @interface AppDelegate () From 93729663c8e7da45900a430d8f9ab59dd03ffa3e Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Mon, 19 Oct 2015 17:43:30 -0700 Subject: [PATCH 105/118] Update Xcode project to recommended settings --- TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj | 7 ++++++- TrustKitDemo/TrustKitDemo/Info.plist | 2 +- TrustKitDemo/TrustKitDemoTests/Info.plist | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj index ef1eb506..bc3644ed 100644 --- a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj +++ b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj @@ -246,7 +246,7 @@ 6B6B474C1B1EECB3007757EE /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0630; + LastUpgradeCheck = 0700; ORGANIZATIONNAME = "Data Theorem"; TargetAttributes = { 6B6B47531B1EECB3007757EE = { @@ -422,6 +422,7 @@ COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -500,6 +501,7 @@ INFOPLIST_FILE = TrustKitDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; }; @@ -514,6 +516,7 @@ INFOPLIST_FILE = TrustKitDemo/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 7.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; }; @@ -533,6 +536,7 @@ ); INFOPLIST_FILE = TrustKitDemoTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TrustKitDemo.app/TrustKitDemo"; }; @@ -548,6 +552,7 @@ ); INFOPLIST_FILE = TrustKitDemoTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TrustKitDemo.app/TrustKitDemo"; }; diff --git a/TrustKitDemo/TrustKitDemo/Info.plist b/TrustKitDemo/TrustKitDemo/Info.plist index 1011bee5..803dbc22 100644 --- a/TrustKitDemo/TrustKitDemo/Info.plist +++ b/TrustKitDemo/TrustKitDemo/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.datatheorem.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/TrustKitDemo/TrustKitDemoTests/Info.plist b/TrustKitDemo/TrustKitDemoTests/Info.plist index eeb14bac..ba72822e 100644 --- a/TrustKitDemo/TrustKitDemoTests/Info.plist +++ b/TrustKitDemo/TrustKitDemoTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.datatheorem.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName From abc4f337b1a63c6aa0ae5c5f81f09b9177854d1f Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 10:25:29 -0700 Subject: [PATCH 106/118] Explicitly declare methods in reporters --- TrustKit/Reporting/TSKBackgroundReporter.h | 12 ++++++++++++ TrustKit/Reporting/TSKBackgroundReporter.m | 2 +- TrustKit/Reporting/TSKSimpleReporter.h | 9 +++++++++ TrustKit/Reporting/TSKSimpleReporter.m | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.h b/TrustKit/Reporting/TSKBackgroundReporter.h index dd095918..84789931 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.h +++ b/TrustKit/Reporting/TSKBackgroundReporter.h @@ -31,5 +31,17 @@ */ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports; + +- (void) pinValidationFailedForHostname:(NSString *) serverHostname + port:(NSNumber *) serverPort + trust:(SecTrustRef) serverTrust + notedHostname:(NSString *) notedHostname + reportURIs:(NSArray *) reportURIs + includeSubdomains:(BOOL) includeSubdomains + knownPins:(NSArray *) knownPins + validationResult:(TSKPinValidationResult) validationResult; + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error; + @end diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index b2bed6d7..d730ec99 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -133,7 +133,7 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname reportURIs:(NSArray *) reportURIs includeSubdomains:(BOOL) includeSubdomains knownPins:(NSArray *) knownPins - validationResult:(TSKPinValidationResult) validationResult; + validationResult:(TSKPinValidationResult) validationResult { // Default port to 0 if not specified if (serverPort == nil) diff --git a/TrustKit/Reporting/TSKSimpleReporter.h b/TrustKit/Reporting/TSKSimpleReporter.h index 317ffe66..2c5b1e8e 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.h +++ b/TrustKit/Reporting/TSKSimpleReporter.h @@ -33,5 +33,14 @@ */ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports; +- (void) pinValidationFailedForHostname:(NSString *) serverHostname + port:(NSNumber *) serverPort + trust:(SecTrustRef) serverTrust + notedHostname:(NSString *) notedHostname + reportURIs:(NSArray *) reportURIs + includeSubdomains:(BOOL) includeSubdomains + knownPins:(NSArray *) knownPins + validationResult:(TSKPinValidationResult) validationResult; + @end diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m index a31d8311..d7c51988 100644 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ b/TrustKit/Reporting/TSKSimpleReporter.m @@ -81,7 +81,7 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname reportURIs:(NSArray *) reportURIs includeSubdomains:(BOOL) includeSubdomains knownPins:(NSArray *) knownPins - validationResult:(TSKPinValidationResult) validationResult; + validationResult:(TSKPinValidationResult) validationResult { // Pin validation failed for a connection to a pinned domain From 46299ff73bb3f3e56418a6b7702f4c5fbdba57e1 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 15:15:30 -0700 Subject: [PATCH 107/118] Remove TSKSimpleReporter as it serves no real purpose --- TrustKit.xcodeproj/project.pbxproj | 14 -- TrustKit/Reporting/TSKBackgroundReporter.m | 93 ++++++++------ TrustKit/Reporting/TSKSimpleReporter.h | 46 ------- TrustKit/Reporting/TSKSimpleReporter.m | 141 --------------------- TrustKit/TrustKit.m | 22 +--- TrustKitTests/TSKReporterTests.m | 5 +- 6 files changed, 58 insertions(+), 263 deletions(-) delete mode 100644 TrustKit/Reporting/TSKSimpleReporter.h delete mode 100644 TrustKit/Reporting/TSKSimpleReporter.m diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 477a90e9..cc970717 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -13,8 +13,6 @@ 070868BB1AE1672D00E5AFDC /* www.good.com.selfsigned.der in Resources */ = {isa = PBXBuildFile; fileRef = 070868BA1AE1672D00E5AFDC /* www.good.com.selfsigned.der */; }; 075AA1091AC985FD00178223 /* TSKPinningValidatorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FA2868CAFECA46ADE0B6E3E /* TSKPinningValidatorTests.m */; }; 0E64A7601B867BA000CA164A /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */; }; - 6B032D3A1AF1794D00EAFA69 /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; }; - 6B032D3E1AF1A4AC00EAFA69 /* TSKSimpleReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B032D3D1AF1A4AC00EAFA69 /* TSKSimpleReporter.h */; }; 6B032D401AF1AEC200EAFA69 /* TSKReporterTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */; }; 6B2B06AD1B05154A00FC749E /* TSKBackgroundReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B2B06AC1B05154A00FC749E /* TSKBackgroundReporter.h */; }; 6B2B06AF1B05157400FC749E /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */; }; @@ -26,7 +24,6 @@ 8C84804D1A896EE30017C155 /* TrustKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C84804C1A896EE30017C155 /* TrustKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8C8480531A896EE30017C155 /* TrustKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C8480471A896EE30017C155 /* TrustKit.framework */; }; 8C84806D1A896F660017C155 /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C84806C1A896F660017C155 /* TrustKit.m */; }; - 8C8716B11B23A9F000267E1D /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; }; 8C8716B21B23A9F400267E1D /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */; }; 8C8716B31B23A9F700267E1D /* TSKPinFailureReport.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F99F1B16094D00F06C0E /* TSKPinFailureReport.m */; }; 8C8716B41B23A9FA00267E1D /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCBD15A1B186D1100CB88AF /* reporting_utils.m */; }; @@ -41,8 +38,6 @@ 8CA6CC141BAE2B6600BDA419 /* TSKReportsRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C9EBE001B619BBE00CA7EE0 /* TSKReportsRateLimiter.h */; settings = {ASSET_TAGS = (); }; }; 8CA6CC151BAE2B6600BDA419 /* TSKReportsRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC161BAE2B6600BDA419 /* TSKReporterDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919261AEA0991002B29AE /* TSKReporterDelegate.h */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC171BAE2B6600BDA419 /* TSKSimpleReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B032D3D1AF1A4AC00EAFA69 /* TSKSimpleReporter.h */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC181BAE2B6600BDA419 /* TSKSimpleReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC191BAE2B6600BDA419 /* TSKBackgroundReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6B2B06AC1B05154A00FC749E /* TSKBackgroundReporter.h */; settings = {ASSET_TAGS = (); }; }; 8CA6CC1A1BAE2B6600BDA419 /* TSKBackgroundReporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC1B1BAE2B6600BDA419 /* TSKPinFailureReport.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F99E1B16094D00F06C0E /* TSKPinFailureReport.h */; settings = {ASSET_TAGS = (); }; }; @@ -151,8 +146,6 @@ 070868BA1AE1672D00E5AFDC /* www.good.com.selfsigned.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = www.good.com.selfsigned.der; sourceTree = ""; }; 2FA286123F801C437F35D240 /* TrustKit+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "TrustKit+Private.h"; sourceTree = ""; }; 2FA2868CAFECA46ADE0B6E3E /* TSKPinningValidatorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSKPinningValidatorTests.m; sourceTree = ""; }; - 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKSimpleReporter.m; path = Reporting/TSKSimpleReporter.m; sourceTree = ""; }; - 6B032D3D1AF1A4AC00EAFA69 /* TSKSimpleReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKSimpleReporter.h; path = Reporting/TSKSimpleReporter.h; sourceTree = ""; }; 6B032D3F1AF1AEB600EAFA69 /* TSKReporterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TSKReporterTests.m; sourceTree = ""; }; 6B2B06AC1B05154A00FC749E /* TSKBackgroundReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TSKBackgroundReporter.h; path = Reporting/TSKBackgroundReporter.h; sourceTree = ""; }; 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TSKBackgroundReporter.m; path = Reporting/TSKBackgroundReporter.m; sourceTree = ""; }; @@ -431,8 +424,6 @@ 8C9EBE001B619BBE00CA7EE0 /* TSKReportsRateLimiter.h */, 8C9EBE011B619BBE00CA7EE0 /* TSKReportsRateLimiter.m */, 8CE919261AEA0991002B29AE /* TSKReporterDelegate.h */, - 6B032D3D1AF1A4AC00EAFA69 /* TSKSimpleReporter.h */, - 6B032D391AF1794D00EAFA69 /* TSKSimpleReporter.m */, 6B2B06AC1B05154A00FC749E /* TSKBackgroundReporter.h */, 6B2B06AE1B05157400FC749E /* TSKBackgroundReporter.m */, 8C15F99E1B16094D00F06C0E /* TSKPinFailureReport.h */, @@ -466,7 +457,6 @@ 6B2B06AD1B05154A00FC749E /* TSKBackgroundReporter.h in Headers */, 8CD5F7311BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */, 8C9EBE021B619BBE00CA7EE0 /* TSKReportsRateLimiter.h in Headers */, - 6B032D3E1AF1A4AC00EAFA69 /* TSKSimpleReporter.h in Headers */, 8CD5F7421BCB06F4005801D8 /* RSSwizzle.h in Headers */, 8C9492F61B2379A100F5DF38 /* reporting_utils.h in Headers */, 8C84804D1A896EE30017C155 /* TrustKit.h in Headers */, @@ -480,7 +470,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 8CA6CC171BAE2B6600BDA419 /* TSKSimpleReporter.h in Headers */, 8CD5F74A1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */, 8CA6CC1B1BAE2B6600BDA419 /* TSKPinFailureReport.h in Headers */, 8CA6CC141BAE2B6600BDA419 /* TSKReportsRateLimiter.h in Headers */, @@ -698,7 +687,6 @@ 8C9EBE031B619BBE00CA7EE0 /* TSKReportsRateLimiter.m in Sources */, 6B2B06AF1B05157400FC749E /* TSKBackgroundReporter.m in Sources */, 8CD5F74B1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */, - 6B032D3A1AF1794D00EAFA69 /* TSKSimpleReporter.m in Sources */, 8CE9191F1AEA073C002B29AE /* public_key_utils.m in Sources */, 8C15F9A11B16094E00F06C0E /* TSKPinFailureReport.m in Sources */, 8C15F9941B132F9200F06C0E /* TSKPinningValidator.m in Sources */, @@ -736,7 +724,6 @@ 0E64A7601B867BA000CA164A /* TSKReportsRateLimiter.m in Sources */, 8CD5F74C1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.m in Sources */, 8CD5F7341BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, - 8C8716B11B23A9F000267E1D /* TSKSimpleReporter.m in Sources */, 8C8716B61B23AA0800267E1D /* ssl_pin_verifier.m in Sources */, 8CD0D4171BD42A7D004478C0 /* RSSwizzle.m in Sources */, ); @@ -755,7 +742,6 @@ 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */, 8CA6CC151BAE2B6600BDA419 /* TSKReportsRateLimiter.m in Sources */, 8CD5F7351BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */, - 8CA6CC181BAE2B6600BDA419 /* TSKSimpleReporter.m in Sources */, 8CA6CC221BAE2B6A00BDA419 /* ssl_pin_verifier.m in Sources */, 8CD5F7451BCB06F4005801D8 /* RSSwizzle.m in Sources */, ); diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index d730ec99..fa11e3db 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -59,63 +59,72 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports self.appBundleId = (__bridge NSString *)CFBundleGetIdentifier(appBundle); self.appVersion = (__bridge NSString *)CFBundleGetValueForInfoDictionaryKey(appBundle, kCFBundleVersionKey); - if (self.appBundleId == nil) - { - // The bundle ID we get is nil if we're running tests on Travis. If the bundle ID is nil, background sessions can't be used - // backgroundSessionConfigurationWithIdentifier: will throw an exception within dispatch_once() which can't be handled - // Throw an exception here instead - [NSException raise:@"Null Bundle ID" format:@"Application must have a bundle identifier to use a background NSURLSession"]; - } - if (self.appVersion == nil) { self.appVersion = @"N/A"; } - /* - Using dispatch_once here ensures that multiple background sessions with the same identifier are not created - in this instance of the application. If you want to support multiple background sessions within a single process, - you should create each session with its own identifier. - */ - dispatch_once(&dispatchOnceBackgroundSession, ^{ - NSURLSessionConfiguration *backgroundConfiguration = nil; + if (self.appBundleId == nil) + { + // The bundle ID we get is nil if we're running tests on Travis. If the bundle ID is nil, background sessions can't be used + // backgroundSessionConfigurationWithIdentifier: will throw an exception within dispatch_once() which can't be handled + // Use a regular session instead + TSKLog(@"Null bundle ID: we are running the test suite; falling back to a normal session."); + self.appBundleId = @"N/A"; + self.appVendorId = @"unit-tests"; - // The API for creating background sessions changed between iOS 7 and iOS 8 and OS X 10.9 and 10.10 + dispatch_once(&dispatchOnceBackgroundSession, ^{ + _backgroundSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + }); + } + else + { + // We're not running unit tests - use a background session + /* + Using dispatch_once here ensures that multiple background sessions with the same identifier are not created + in this instance of the application. If you want to support multiple background sessions within a single process, + you should create each session with its own identifier. + */ + dispatch_once(&dispatchOnceBackgroundSession, ^{ + NSURLSessionConfiguration *backgroundConfiguration = nil; + + // The API for creating background sessions changed between iOS 7 and iOS 8 and OS X 10.9 and 10.10 #if (TARGET_OS_IPHONE &&__IPHONE_OS_VERSION_MAX_ALLOWED < 80000) || (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MAX_ALLOWED < 1100) - // iOS 7 or OS X 10.9 as the max SDK: awlays use the deprecated/iOS 7 API - backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:[NSString stringWithFormat:kTSKBackgroundSessionIdentifierFormat, self.appBundleId]]; + // iOS 7 or OS X 10.9 as the max SDK: awlays use the deprecated/iOS 7 API + backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:[NSString stringWithFormat:kTSKBackgroundSessionIdentifierFormat, self.appBundleId]]; #else - // iOS 8+ or OS X 10.10+ as the max SDK + // iOS 8+ or OS X 10.10+ as the max SDK #if (TARGET_OS_IPHONE &&__IPHONE_OS_VERSION_MIN_REQUIRED < 80000) || (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED < 1100) - // iOS 7 or OS X 10.9 as the min SDK - // Try to use the new API if available at runtime - if (![NSURLSessionConfiguration respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) - { - // Device runs on iOS 7 or OS X 10.9 - backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:[NSString stringWithFormat:kTSKBackgroundSessionIdentifierFormat, self.appBundleId]]; - } - else + // iOS 7 or OS X 10.9 as the min SDK + // Try to use the new API if available at runtime + if (![NSURLSessionConfiguration respondsToSelector:@selector(backgroundSessionConfigurationWithIdentifier:)]) + { + // Device runs on iOS 7 or OS X 10.9 + backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:[NSString stringWithFormat:kTSKBackgroundSessionIdentifierFormat, self.appBundleId]]; + } + else #endif - { - // Device runs on iOS 8+ or OS X 10.10+ or min SDK is iOS 8+ or OS X 10.10+ - backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: [NSString stringWithFormat:kTSKBackgroundSessionIdentifierFormat, self.appBundleId]]; - } + { + // Device runs on iOS 8+ or OS X 10.10+ or min SDK is iOS 8+ or OS X 10.10+ + backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: [NSString stringWithFormat:kTSKBackgroundSessionIdentifierFormat, self.appBundleId]]; + } #endif - - - + + + #if TARGET_OS_IPHONE - // iOS-only settings - // Do not wake up the App after completing the upload - backgroundConfiguration.sessionSendsLaunchEvents = NO; + // iOS-only settings + // Do not wake up the App after completing the upload + backgroundConfiguration.sessionSendsLaunchEvents = NO; #endif - + #if (TARGET_OS_IPHONE) || ((!TARGET_OS_IPHONE) && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1100)) - // On OS X discretionary is only available on 10.10 - backgroundConfiguration.discretionary = YES; + // On OS X discretionary is only available on 10.10 + backgroundConfiguration.discretionary = YES; #endif - _backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration delegate:self delegateQueue:nil]; - }); + _backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration delegate:self delegateQueue:nil]; + }); + } } return self; } diff --git a/TrustKit/Reporting/TSKSimpleReporter.h b/TrustKit/Reporting/TSKSimpleReporter.h deleted file mode 100644 index 2c5b1e8e..00000000 --- a/TrustKit/Reporting/TSKSimpleReporter.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - - TSKSimpleReporter.h - TrustKit - - Copyright 2015 The TrustKit Project Authors - Licensed under the MIT license, see associated LICENSE file for terms. - See AUTHORS file for the list of project authors. - - */ - -#import -#import "TSKReporterDelegate.h" - - -/** - `TSKSimpleReporter` is a class for uploading pin failure reports. - - While TSKSimpleBackgroundReporter is a better implementation in most scenarios as it has a smaller performance impact on the App, the background transfer service cannot be used when running the test suite. Therefore, and only when we run the tests, we fall back to using TSKSimpleReporter. - - */ -@interface TSKSimpleReporter : NSObject - -///--------------------- -/// @name Initialization -///--------------------- - -/** - Initializes a simple reporter. - - @param shouldRateLimitReports Prevent identical pin failure reports from being sent more than once per day. - - */ -- (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports; - -- (void) pinValidationFailedForHostname:(NSString *) serverHostname - port:(NSNumber *) serverPort - trust:(SecTrustRef) serverTrust - notedHostname:(NSString *) notedHostname - reportURIs:(NSArray *) reportURIs - includeSubdomains:(BOOL) includeSubdomains - knownPins:(NSArray *) knownPins - validationResult:(TSKPinValidationResult) validationResult; - -@end - diff --git a/TrustKit/Reporting/TSKSimpleReporter.m b/TrustKit/Reporting/TSKSimpleReporter.m deleted file mode 100644 index d7c51988..00000000 --- a/TrustKit/Reporting/TSKSimpleReporter.m +++ /dev/null @@ -1,141 +0,0 @@ -/* - - TSKSimpleReporter.m - TrustKit - - Copyright 2015 The TrustKit Project Authors - Licensed under the MIT license, see associated LICENSE file for terms. - See AUTHORS file for the list of project authors. - - */ - -#import "TSKSimpleReporter.h" -#import "TrustKit+Private.h" -#import "TSKPinFailureReport.h" -#import "reporting_utils.h" -#import "TSKReportsRateLimiter.h" - -#if TARGET_OS_IPHONE -@import UIKit; // For accessing the IDFV -#endif - - - - -@interface TSKSimpleReporter() -@property (nonatomic, strong) NSString * appBundleId; -@property (nonatomic, strong) NSString * appVersion; -@property (nonatomic, strong) NSString * appVendorId; -@property BOOL shouldRateLimitReports; -@property(nonatomic, strong) NSURLSession *session; -@end - - -@implementation TSKSimpleReporter - - -- (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports -{ - self = [super init]; - if (self) - { - self.shouldRateLimitReports = shouldRateLimitReports; - - // Retrieve the App's information -#if TARGET_OS_IPHONE - // On iOS use the IDFV - self.appVendorId = [[[UIDevice currentDevice] identifierForVendor]UUIDString]; -#else - // On OS X, don't use anything for now - self.appVendorId = @"OS-X"; -#endif - - CFBundleRef appBundle = CFBundleGetMainBundle(); - self.appBundleId = (__bridge NSString *)CFBundleGetIdentifier(appBundle); - self.appVersion = (__bridge NSString *)CFBundleGetValueForInfoDictionaryKey(appBundle, kCFBundleVersionKey); - - if (self.appBundleId == nil) - { - // Should only happen when running tests - self.appBundleId = @"N/A"; - self.appVendorId = @"unit-tests"; - } - - if (self.appVersion == nil) - { - self.appVersion = @"N/A"; - } - - - // Create the session for sending the reports - self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; - } - return self; -} - - -- (void) pinValidationFailedForHostname:(NSString *) serverHostname - port:(NSNumber *) serverPort - trust:(SecTrustRef) serverTrust - notedHostname:(NSString *) notedHostname - reportURIs:(NSArray *) reportURIs - includeSubdomains:(BOOL) includeSubdomains - knownPins:(NSArray *) knownPins - validationResult:(TSKPinValidationResult) validationResult -{ - // Pin validation failed for a connection to a pinned domain - - // Default port to 0 if not specified - if (serverPort == nil) - { - serverPort = [NSNumber numberWithInt:0]; - } - - if (reportURIs == nil) - { - [NSException raise:@"TrustKit Simple Reporter configuration invalid" - format:@"Reporter was given an invalid value for reportURIs: %@ for domain %@", - reportURIs, notedHostname]; - } - - // Create the pin validation failure report - NSArray *certificateChain = convertTrustToPemArray(serverTrust); - NSArray *formattedPins = convertPinsToHpkpPins(knownPins); - TSKPinFailureReport *report = [[TSKPinFailureReport alloc]initWithAppBundleId:self.appBundleId - appVersion:self.appVersion - notedHostname:notedHostname - hostname:serverHostname - port:serverPort - dateTime:[NSDate date] // Use the current time - includeSubdomains:includeSubdomains - validatedCertificateChain:certificateChain - knownPins:formattedPins - validationResult:validationResult - appVendorId:self.appVendorId]; - - - // Should we rate-limit this report? - if (self.shouldRateLimitReports && [TSKReportsRateLimiter shouldRateLimitReport:report]) - { - // We recently sent the exact same report; do not send this report - TSKLog(@"Pin failure report for %@ was not sent due to rate-limiting", serverHostname); - return; - } - - - // POST the report to all the configured report URIs - for (NSURL *reportUri in reportURIs) - { - NSURLRequest *request = [report requestToUri:reportUri]; - NSURLSessionDataTask *postDataTask = [self.session dataTaskWithRequest:request - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - // We don't do anything here as reports are meant to be sent - // on a best-effort basis: even if we got an error, there's - // nothing to do anyway. - }]; - [postDataTask resume]; - } -} - - -@end diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index 4f7c0c84..ae63309d 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -14,7 +14,6 @@ #import "public_key_utils.h" #import "domain_registry.h" #import "TSKBackgroundReporter.h" -#import "TSKSimpleReporter.h" #import "TSKNSURLConnectionDelegateProxy.h" #import "TSKNSURLSessionDelegateProxy.h" @@ -87,13 +86,11 @@ void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrus // Pin validation failed: retrieve the list of configured report URLs NSMutableArray *reportUris = [NSMutableArray arrayWithArray:notedHostnameConfig[kTSKReportUris]]; -#if !DEBUG - // For release builds, also enable the default reporting URL + // Also enable the default reporting URL if ([notedHostnameConfig[kTSKDisableDefaultReportUri] boolValue] == NO) { [reportUris addObject:[NSURL URLWithString:kTSKDefaultReportUri]]; } -#endif // If some report URLs have been defined, send the pin failure report if ((reportUris != nil) && ([reportUris count] > 0)) @@ -344,20 +341,11 @@ static void initializeTrustKit(NSDictionary *trustKitConfig) // Convert and store the SSL pins in our global variable _trustKitGlobalConfiguration = [[NSDictionary alloc]initWithDictionary:parseTrustKitArguments(trustKitConfig)]; - + // Create our reporter for sending pin validation failures; do this before hooking NSURLSession so we don't hook ourselves - @try - { - // Create a reporter that uses the background transfer service to send pin failure reports - _pinFailureReporter = [[TSKBackgroundReporter alloc]initAndRateLimitReports:YES]; - - } - @catch (NSException *e) - { - // The bundle ID we get is nil if we're running tests on Travis so we have to use the simple reporter for unit tests - TSKLog(@"Null bundle ID: we are running the test suite; falling back to TSKSimpleReporter"); - _pinFailureReporter = [[TSKSimpleReporter alloc]initAndRateLimitReports:YES]; - } + // Create a reporter that uses the background transfer service to send pin failure reports + _pinFailureReporter = [[TSKBackgroundReporter alloc]initAndRateLimitReports:YES]; + // Create a dispatch queue for activating the reporter // We use a serial queue targetting the global default queue in order to ensure reports are sent one by one diff --git a/TrustKitTests/TSKReporterTests.m b/TrustKitTests/TSKReporterTests.m index 45ad7083..69a1f42a 100644 --- a/TrustKitTests/TSKReporterTests.m +++ b/TrustKitTests/TSKReporterTests.m @@ -10,7 +10,6 @@ */ #import -#import "TSKSimpleReporter.h" #import "TSKBackgroundReporter.h" #import "TSKPinFailureReport.h" #import "TSKCertificateUtils.h" @@ -56,10 +55,10 @@ - (void)tearDown [super tearDown]; } -- (void)testSimpleReporter +- (void)testReporter { // Just try a simple valid case to see if we can post this to the server - TSKSimpleReporter *reporter = [[TSKSimpleReporter alloc] initAndRateLimitReports:NO]; + TSKBackgroundReporter *reporter = [[TSKBackgroundReporter alloc] initAndRateLimitReports:NO]; [reporter pinValidationFailedForHostname:@"mail.example.com" port:[NSNumber numberWithInt:443] From 269645cc981fd85b9f5e813c8e16912729d0256b Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 15:15:41 -0700 Subject: [PATCH 108/118] Add static scheme to travis matrix --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 82a6c9cc..e5506ad9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ env: matrix: - TEST_SDK=macosx10.11 TEST_SCHEME="TrustKit OS X" - TEST_SDK=iphonesimulator9.0 TEST_SCHEME=TrustKit + - TEST_SDK=iphonesimulator9.0 TEST_SCHEME=TrustKit_Static script: - xcodebuild clean -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK - xcodebuild build test -project TrustKit.xcodeproj -scheme "$TEST_SCHEME" -configuration Release CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO -sdk $TEST_SDK From 25ccb922518f9b76d977b7748760288334209432 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 15:15:50 -0700 Subject: [PATCH 109/118] Remove unneeded headers --- TrustKit/Pinning/TSKPinningValidator.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/TrustKit/Pinning/TSKPinningValidator.m b/TrustKit/Pinning/TSKPinningValidator.m index 3d86c8bb..d857c56f 100644 --- a/TrustKit/Pinning/TSKPinningValidator.m +++ b/TrustKit/Pinning/TSKPinningValidator.m @@ -9,12 +9,9 @@ */ -#import "TSKPinningValidator.h" -#import "ssl_pin_verifier.h" #import "TrustKit+Private.h" - @implementation TSKPinningValidator + (TSKTrustDecision) evaluateTrust:(SecTrustRef _Nonnull)serverTrust forHostname:(NSString * _Nonnull)serverHostname From 595528c59ca05973f6f2cf71c385e9ecfba39b5c Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 15:29:29 -0700 Subject: [PATCH 110/118] Add contact info --- TrustKit/TrustKit.h | 2 +- TrustKit/TrustKit.m | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/TrustKit/TrustKit.h b/TrustKit/TrustKit.h index 80316fd6..64149e33 100644 --- a/TrustKit/TrustKit.h +++ b/TrustKit/TrustKit.h @@ -177,7 +177,7 @@ FOUNDATION_EXPORT const NSString * _Nonnull kTSKAlgorithmEcDsaSecp256r1; #### `kTSKDisableDefaultReportUri` If set to `YES`, the default report URL for sending pin failure reports will be disabled; default value is `NO`. - By default, pin failure reports are sent to a report server hosted by Data Theorem, for detecting potential CA compromises and man-in-the-middle attacks, as well as providing a free dashboard for developers. Only pin failure reports are sent, which contain the App's bundle ID, the IDFV, and the server's hostname and certificate chain that failed validation. + By default, pin failure reports are sent to a report server hosted by Data Theorem, for detecting potential CA compromises and man-in-the-middle attacks, as well as providing a free dashboard for developers; email info@datatheorem.com if you'd like a dashboard for your App. Only pin failure reports are sent, which contain the App's bundle ID, the IDFV, and the server's hostname and certificate chain that failed validation. ### Public Key Algorithms Keys diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index ae63309d..faa1b8b2 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -57,6 +57,7 @@ // Default report URI - can be disabled with TSKDisableDefaultReportUri +// Email info@datatheorem.com if you need a free dashboard to see your App's reports static NSString * const kTSKDefaultReportUri = @"https://overmind.datatheorem.com/trustkit/report"; From 576adbbcdb9b0397c86f2796f9773246086abe9a Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 15:48:30 -0700 Subject: [PATCH 111/118] Simplify background reporter - do not use a delegate --- TrustKit/Reporting/TSKBackgroundReporter.h | 4 +-- TrustKit/Reporting/TSKBackgroundReporter.m | 29 +++++++++++----------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.h b/TrustKit/Reporting/TSKBackgroundReporter.h index 84789931..5660ad87 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.h +++ b/TrustKit/Reporting/TSKBackgroundReporter.h @@ -17,7 +17,7 @@ `TSKSimpleBackgroundReporter` is a class for uploading pin failure reports using the background transfer service. */ -@interface TSKBackgroundReporter : NSObject +@interface TSKBackgroundReporter : NSObject ///--------------------- /// @name Initialization @@ -41,7 +41,5 @@ knownPins:(NSArray *) knownPins validationResult:(TSKPinValidationResult) validationResult; -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error; - @end diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index fa11e3db..2acf6b57 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -122,7 +122,7 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports // On OS X discretionary is only available on 10.10 backgroundConfiguration.discretionary = YES; #endif - _backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration delegate:self delegateQueue:nil]; + _backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration]; }); } } @@ -202,23 +202,22 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname // Pass the URL and the temporary file to the background upload task and start uploading NSURLSessionUploadTask *uploadTask = [_backgroundSession uploadTaskWithRequest:request - fromFile:tmpFileURL]; + fromFile:tmpFileURL + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) + { + if (error == nil) + { + TSKLog(@"Background upload - task completed successfully: %@; pinning failure report sent", response); + } + else + { + TSKLog(@"Background upload - task completed with error: %@ (code %ld)", [error localizedDescription], (long)error.code); + } + }]; + [uploadTask resume]; } } - -- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error -{ - if (error == nil) - { - TSKLog(@"Background upload - task %@ completed successfully; pinning failure report sent", task); - } - else - { - TSKLog(@"Background upload - task %@ completed with error: %@ (code %ld)", task, [error localizedDescription], (long)error.code); - } -} - @end From e7d7859e50768f39f127fb8edf00ae629e4a2e07 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 16:05:02 -0700 Subject: [PATCH 112/118] Significantly improve test coverage of the background reporter --- TrustKit/Reporting/TSKBackgroundReporter.m | 52 +++++++++++++++------- TrustKit/TrustKit+Private.h | 8 +++- TrustKit/TrustKit.m | 6 +++ TrustKitTests/TSKReporterTests.m | 48 +++++++++++++++++--- 4 files changed, 91 insertions(+), 23 deletions(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index 2acf6b57..74c0869e 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -38,6 +38,7 @@ @interface TSKBackgroundReporter() @implementation TSKBackgroundReporter +#pragma mark Public methods - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports { @@ -130,11 +131,6 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports } -/* - Pin validation failed for a connection to a pinned domain - In this implementation for a simple background reporter, we're just going to send out the report upon each failure - in a background task - */ - (void) pinValidationFailedForHostname:(NSString *) serverHostname port:(NSNumber *) serverPort trust:(SecTrustRef) serverTrust @@ -143,6 +139,40 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname includeSubdomains:(BOOL) includeSubdomains knownPins:(NSArray *) knownPins validationResult:(TSKPinValidationResult) validationResult +{ + return [self pinValidationFailedForHostname:serverHostname + port:serverPort + trust:serverTrust + notedHostname:notedHostname + reportURIs:reportURIs + includeSubdomains:includeSubdomains + knownPins:knownPins + validationResult:validationResult + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) + { + if (error == nil) + { + TSKLog(@"Background upload - task completed successfully: %@; pinning failure report sent", response); + } + else + { + TSKLog(@"Background upload - task completed with error: %@ (code %ld)", [error localizedDescription], (long)error.code); + } + }]; +} + +#pragma mark Private method +- (void) pinValidationFailedForHostname:(NSString *) serverHostname + port:(NSNumber *) serverPort + trust:(SecTrustRef) serverTrust + notedHostname:(NSString *) notedHostname + reportURIs:(NSArray *) reportURIs + includeSubdomains:(BOOL) includeSubdomains + knownPins:(NSArray *) knownPins + validationResult:(TSKPinValidationResult) validationResult + completionHandler:(void (^ _Nonnull)(NSData * _Nullable data, + NSURLResponse * _Nullable response, + NSError * _Nullable error))completionHandler { // Default port to 0 if not specified if (serverPort == nil) @@ -203,17 +233,7 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname // Pass the URL and the temporary file to the background upload task and start uploading NSURLSessionUploadTask *uploadTask = [_backgroundSession uploadTaskWithRequest:request fromFile:tmpFileURL - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) - { - if (error == nil) - { - TSKLog(@"Background upload - task completed successfully: %@; pinning failure report sent", response); - } - else - { - TSKLog(@"Background upload - task completed with error: %@ (code %ld)", [error localizedDescription], (long)error.code); - } - }]; + completionHandler:completionHandler]; [uploadTask resume]; } diff --git a/TrustKit/TrustKit+Private.h b/TrustKit/TrustKit+Private.h index 6d7eb353..64edc0f5 100644 --- a/TrustKit/TrustKit+Private.h +++ b/TrustKit/TrustKit+Private.h @@ -15,18 +15,24 @@ #import #import "ssl_pin_verifier.h" -NSDictionary *parseTrustKitArguments(NSDictionary *TrustKitArguments); + +#pragma mark Utility functions void TSKLog(NSString *format, ...); void sendPinFailureReport_async(TSKPinValidationResult validationResult, SecTrustRef serverTrust, NSString *serverHostname, NSString *notedHostname, NSDictionary *notedHostnameConfig, void (^onCompletion)(void)); +#pragma mark Methods for the unit tests + +NSDictionary *parseTrustKitArguments(NSDictionary *TrustKitArguments); + @interface TrustKit(Private) + (void) resetConfiguration; + (NSDictionary *) configuration; + (BOOL) wasTrustKitInitialized; ++ (NSString *) getDefaultReportUri; @end diff --git a/TrustKit/TrustKit.m b/TrustKit/TrustKit.m index faa1b8b2..44a57d4c 100644 --- a/TrustKit/TrustKit.m +++ b/TrustKit/TrustKit.m @@ -411,6 +411,12 @@ + (void) resetConfiguration dispatchOnceTrustKitInit = 0; } + ++ (NSString *) getDefaultReportUri +{ + return kTSKDefaultReportUri; +} + @end diff --git a/TrustKitTests/TSKReporterTests.m b/TrustKitTests/TSKReporterTests.m index 69a1f42a..bf27412b 100644 --- a/TrustKitTests/TSKReporterTests.m +++ b/TrustKitTests/TSKReporterTests.m @@ -15,6 +15,29 @@ #import "TSKCertificateUtils.h" #import "reporting_utils.h" #import "TSKReportsRateLimiter.h" +#import "TrustKit+Private.h" + + + +#pragma mark Private test methods +@interface TSKBackgroundReporter(Private) + +- (void) pinValidationFailedForHostname:(NSString *) serverHostname + port:(NSNumber *) serverPort + trust:(SecTrustRef) serverTrust + notedHostname:(NSString *) notedHostname + reportURIs:(NSArray *) reportURIs + includeSubdomains:(BOOL) includeSubdomains + knownPins:(NSArray *) knownPins + validationResult:(TSKPinValidationResult) validationResult + completionHandler:(void (^ _Nonnull)(NSData * _Nullable data, + NSURLResponse * _Nullable response, + NSError * _Nullable error))completionHandler; + +@end + + +#pragma mark Test suite @interface TSKReporterTests : XCTestCase @@ -57,24 +80,37 @@ - (void)tearDown - (void)testReporter { - // Just try a simple valid case to see if we can post this to the server + // Just try a simple valid case to see if we can post this to the default report URL TSKBackgroundReporter *reporter = [[TSKBackgroundReporter alloc] initAndRateLimitReports:NO]; + + XCTestExpectation *expectation = [self expectationWithDescription:@"TestReporter"]; + [reporter pinValidationFailedForHostname:@"mail.example.com" port:[NSNumber numberWithInt:443] trust:_testTrust notedHostname:@"example.com" - reportURIs:@[[NSURL URLWithString:@"http://127.0.0.1:8080/log_report"]] + reportURIs:@[[NSURL URLWithString:[TrustKit getDefaultReportUri]]] includeSubdomains:YES knownPins:@[ [[NSData alloc]initWithBase64EncodedString:@"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" options:(NSDataBase64DecodingOptions)0], [[NSData alloc]initWithBase64EncodedString:@"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" options:(NSDataBase64DecodingOptions)0], ] - validationResult:TSKPinValidationResultFailed]; - + validationResult:TSKPinValidationResultFailed + completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) + { + if (error == nil) + { + // Ensure the upload was succesful + [expectation fulfill]; + } + }]; - [NSThread sleepForTimeInterval:5.0]; - XCTAssert(YES, @"Pass"); + [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { + if (error) { + NSLog(@"Timeout Error: %@", error); + } + }]; } From e96cd85b402d67f60869ddbe677a308651740bcd Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 17:18:09 -0700 Subject: [PATCH 113/118] Actually we need a delegate for background sessions --- TrustKit/Reporting/TSKBackgroundReporter.h | 4 +- TrustKit/Reporting/TSKBackgroundReporter.m | 65 +++++++++------------- TrustKitTests/TSKReporterTests.m | 40 +------------ 3 files changed, 32 insertions(+), 77 deletions(-) diff --git a/TrustKit/Reporting/TSKBackgroundReporter.h b/TrustKit/Reporting/TSKBackgroundReporter.h index 5660ad87..84789931 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.h +++ b/TrustKit/Reporting/TSKBackgroundReporter.h @@ -17,7 +17,7 @@ `TSKSimpleBackgroundReporter` is a class for uploading pin failure reports using the background transfer service. */ -@interface TSKBackgroundReporter : NSObject +@interface TSKBackgroundReporter : NSObject ///--------------------- /// @name Initialization @@ -41,5 +41,7 @@ knownPins:(NSArray *) knownPins validationResult:(TSKPinValidationResult) validationResult; +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error; + @end diff --git a/TrustKit/Reporting/TSKBackgroundReporter.m b/TrustKit/Reporting/TSKBackgroundReporter.m index 74c0869e..5964d566 100644 --- a/TrustKit/Reporting/TSKBackgroundReporter.m +++ b/TrustKit/Reporting/TSKBackgroundReporter.m @@ -19,6 +19,8 @@ @import UIKit; // For accessing the IDFV #endif + + // Session identifier for background uploads: .TSKSimpleReporter static NSString* kTSKBackgroundSessionIdentifierFormat = @"%@.TSKSimpleReporter"; static NSURLSession *_backgroundSession = nil; @@ -32,12 +34,12 @@ @interface TSKBackgroundReporter() @property (nonatomic, strong) NSString * appVendorId; @property BOOL shouldRateLimitReports; + @end @implementation TSKBackgroundReporter - #pragma mark Public methods - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports @@ -75,7 +77,9 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports self.appVendorId = @"unit-tests"; dispatch_once(&dispatchOnceBackgroundSession, ^{ - _backgroundSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + _backgroundSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration] + delegate:self + delegateQueue:nil]; }); } else @@ -123,7 +127,10 @@ - (instancetype)initAndRateLimitReports:(BOOL)shouldRateLimitReports // On OS X discretionary is only available on 10.10 backgroundConfiguration.discretionary = YES; #endif - _backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration]; + // We have to use a delegate as background sessions can't use completion handlers + _backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration + delegate:self + delegateQueue:nil]; }); } } @@ -139,40 +146,6 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname includeSubdomains:(BOOL) includeSubdomains knownPins:(NSArray *) knownPins validationResult:(TSKPinValidationResult) validationResult -{ - return [self pinValidationFailedForHostname:serverHostname - port:serverPort - trust:serverTrust - notedHostname:notedHostname - reportURIs:reportURIs - includeSubdomains:includeSubdomains - knownPins:knownPins - validationResult:validationResult - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) - { - if (error == nil) - { - TSKLog(@"Background upload - task completed successfully: %@; pinning failure report sent", response); - } - else - { - TSKLog(@"Background upload - task completed with error: %@ (code %ld)", [error localizedDescription], (long)error.code); - } - }]; -} - -#pragma mark Private method -- (void) pinValidationFailedForHostname:(NSString *) serverHostname - port:(NSNumber *) serverPort - trust:(SecTrustRef) serverTrust - notedHostname:(NSString *) notedHostname - reportURIs:(NSArray *) reportURIs - includeSubdomains:(BOOL) includeSubdomains - knownPins:(NSArray *) knownPins - validationResult:(TSKPinValidationResult) validationResult - completionHandler:(void (^ _Nonnull)(NSData * _Nullable data, - NSURLResponse * _Nullable response, - NSError * _Nullable error))completionHandler { // Default port to 0 if not specified if (serverPort == nil) @@ -232,12 +205,26 @@ - (void) pinValidationFailedForHostname:(NSString *) serverHostname // Pass the URL and the temporary file to the background upload task and start uploading NSURLSessionUploadTask *uploadTask = [_backgroundSession uploadTaskWithRequest:request - fromFile:tmpFileURL - completionHandler:completionHandler]; + fromFile:tmpFileURL]; [uploadTask resume]; } } + + +- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error +{ + if (error == nil) + { + TSKLog(@"Background upload - task completed successfully: pinning failure report sent"); + } + else + { + TSKLog(@"Background upload - task completed with error: %@ (code %ld)", [error localizedDescription], (long)error.code); + } +} + + @end diff --git a/TrustKitTests/TSKReporterTests.m b/TrustKitTests/TSKReporterTests.m index bf27412b..0e67776a 100644 --- a/TrustKitTests/TSKReporterTests.m +++ b/TrustKitTests/TSKReporterTests.m @@ -18,25 +18,6 @@ #import "TrustKit+Private.h" - -#pragma mark Private test methods -@interface TSKBackgroundReporter(Private) - -- (void) pinValidationFailedForHostname:(NSString *) serverHostname - port:(NSNumber *) serverPort - trust:(SecTrustRef) serverTrust - notedHostname:(NSString *) notedHostname - reportURIs:(NSArray *) reportURIs - includeSubdomains:(BOOL) includeSubdomains - knownPins:(NSArray *) knownPins - validationResult:(TSKPinValidationResult) validationResult - completionHandler:(void (^ _Nonnull)(NSData * _Nullable data, - NSURLResponse * _Nullable response, - NSError * _Nullable error))completionHandler; - -@end - - #pragma mark Test suite @interface TSKReporterTests : XCTestCase @@ -78,14 +59,11 @@ - (void)tearDown [super tearDown]; } + - (void)testReporter { // Just try a simple valid case to see if we can post this to the default report URL TSKBackgroundReporter *reporter = [[TSKBackgroundReporter alloc] initAndRateLimitReports:NO]; - - - XCTestExpectation *expectation = [self expectationWithDescription:@"TestReporter"]; - [reporter pinValidationFailedForHostname:@"mail.example.com" port:[NSNumber numberWithInt:443] trust:_testTrust @@ -96,21 +74,9 @@ - (void)testReporter [[NSData alloc]initWithBase64EncodedString:@"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" options:(NSDataBase64DecodingOptions)0], [[NSData alloc]initWithBase64EncodedString:@"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" options:(NSDataBase64DecodingOptions)0], ] - validationResult:TSKPinValidationResultFailed - completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) - { - if (error == nil) - { - // Ensure the upload was succesful - [expectation fulfill]; - } - }]; + validationResult:TSKPinValidationResultFailed]; - [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) { - if (error) { - NSLog(@"Timeout Error: %@", error); - } - }]; + [NSThread sleepForTimeInterval:2.0]; } From d76c4ad9e382a5f87327da2dc7396d9c42a6ac80 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 17:29:58 -0700 Subject: [PATCH 114/118] Set deployment target to 8.0 when dynamically linking --- TrustKit.xcodeproj/project.pbxproj | 4 ++-- TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index cc970717..1d4d77be 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -904,7 +904,7 @@ ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", @@ -936,7 +936,7 @@ ENABLE_BITCODE = "$(inherited)"; INFOPLIST_FILE = TrustKit/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", diff --git a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj index bc3644ed..437e3f5f 100644 --- a/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj +++ b/TrustKitDemo/TrustKitDemo.xcodeproj/project.pbxproj @@ -499,7 +499,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = TrustKitDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -514,7 +514,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; INFOPLIST_FILE = TrustKitDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 7.1; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.datatheorem.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; From 9ab8634d3ce681ea1bfdd54f731daaffaedf47c3 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 17:37:19 -0700 Subject: [PATCH 115/118] Remove remaining fishhook files --- TrustKit/Dependencies/fishhook/LICENSE | 22 ------- TrustKit/Dependencies/fishhook/README.md | 81 ------------------------ 2 files changed, 103 deletions(-) delete mode 100755 TrustKit/Dependencies/fishhook/LICENSE delete mode 100755 TrustKit/Dependencies/fishhook/README.md diff --git a/TrustKit/Dependencies/fishhook/LICENSE b/TrustKit/Dependencies/fishhook/LICENSE deleted file mode 100755 index c45bb7c0..00000000 --- a/TrustKit/Dependencies/fishhook/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2013, Facebook, Inc. -// All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name Facebook nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific -// prior written permission. -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/TrustKit/Dependencies/fishhook/README.md b/TrustKit/Dependencies/fishhook/README.md deleted file mode 100755 index 6f0a7a22..00000000 --- a/TrustKit/Dependencies/fishhook/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# fishhook - -__fishhook__ is a very simple library that enables dynamically rebinding symbols in Mach-O binaries running on iOS in the simulator and on device. This provides functionality that is similar to using [`DYLD_INTERPOSE`][interpose] on OS X. At Facebook, we've found it useful as a way to hook calls in libSystem for debugging/tracing purposes (for example, auditing for double-close issues with file descriptors). - -[interpose]: http://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h "" - -## Usage - -Once you add `fishhook.h`/`fishhook.c` to your project, you can rebind symbols as follows: -```Objective-C -#import - -#import - -#import "AppDelegate.h" -#import "fishhook.h" - -static int (*orig_close)(int); -static int (*orig_open)(const char *, int, ...); - -void save_original_symbols() { - orig_close = dlsym(RTLD_DEFAULT, "close"); - orig_open = dlsym(RTLD_DEFAULT, "open"); -} - -int my_close(int fd) { - printf("Calling real close(%d)\n", fd); - return orig_close(fd); -} - -int my_open(const char *path, int oflag, ...) { - va_list ap = {0}; - mode_t mode = 0; - - if ((oflag & O_CREAT) != 0) { - // mode only applies to O_CREAT - va_start(ap, oflag); - mode = va_arg(ap, int); - va_end(ap); - printf("Calling real open('%s', %d, %d)\n", path, oflag, mode); - return orig_open(path, oflag, mode); - } else { - printf("Calling real open('%s', %d)\n", path, oflag); - return orig_open(path, oflag, mode); - } -} - -int main(int argc, char * argv[]) -{ - @autoreleasepool { - save_original_symbols(); - rebind_symbols((struct rebinding[2]){{"close", my_close}, {"open", my_open}}, 2); - - // Open our own binary and print out first 4 bytes (which is the same - // for all Mach-O binaries on a given architecture) - int fd = open(argv[0], O_RDONLY); - uint32_t magic_number = 0; - read(fd, &magic_number, 4); - printf("Mach-O Magic Number: %x \n", magic_number); - close(fd); - - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} -``` -### Sample output -``` -Calling real open('/var/mobile/Applications/161DA598-5B83-41F5-8A44-675491AF6A2C/Test.app/Test', 0) -Mach-O Magic Number: feedface -Calling real close(3) -... -``` - -## How it works - -`dyld` binds lazy and non-lazy symbols by updating pointers in particular sections of the `__DATA` segment of a Mach-O binary. __fishhook__ re-binds these symbols by determining the locations to update for each of the symbol names passed to `rebind_symbols` and then writing out the corresponding replacements. - -For a given image, the `__DATA` segment may contain two sections that are relevant for dynamic symbol bindings: `__nl_symbol_ptr` and `__la_symbol_ptr`. `__nl_symbol_ptr` is an array of pointers to non-lazily bound data (these are bound at the time a library is loaded) and `__la_symbol_ptr` is an array of pointers to imported functions that is generally filled by a routine called `dyld_stub_binder` during the first call to that symbol (it's also possible to tell `dyld` to bind these at launch). In order to find the name of the symbol that corresponds to a particular location in one of these sections, we have to jump through several layers of indirection. For the two relevant sections, the section headers (`struct section`s from ``) provide an offset (in the `reserved1` field) into what is known as the indirect symbol table. The indirect symbol table, which is located in the `__LINKEDIT` segment of the binary, is just an array of indexes into the symbol table (also in `__LINKEDIT`) whose order is identical to that of the pointers in the non-lazy and lazy symbol sections. So, given `struct section nl_symbol_ptr`, the corresponding index in the symbol table of the first address in that section is `indirect_symbol_table[nl_symbol_ptr->reserved1]`. The symbol table itself is an array of `struct nlist`s (see ``), and each `nlist` contains an index into the string table in `__LINKEDIT` which where the actual symbol names are stored. So, for each pointer `__nl_symbol_ptr` and `__la_symbol_ptr`, we are able to find the corresponding symbol and then the corresponding string to compare against the requested symbol names, and if there is a match, we replace the pointer in the section with the replacement. - -The process of looking up the name of a given entry in the lazy or non-lazy pointer tables looks like this: -![Visual explanation](http://i.imgur.com/HVXqHCz.png) \ No newline at end of file From e4f5737fc6c4061a92c46a2aa5dbb7f62145c595 Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 17:38:03 -0700 Subject: [PATCH 116/118] Fix TrustKit_Static scheme --- TrustKit.xcodeproj/project.pbxproj | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 1d4d77be..0b10e3cb 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -80,6 +80,9 @@ 8CC78B291B1B697000523A25 /* COMODOECCDomainValidationSecureServerCA2.der in Resources */ = {isa = PBXBuildFile; fileRef = 8CC78B1C1B1B55EC00523A25 /* COMODOECCDomainValidationSecureServerCA2.der */; }; 8CCBD15B1B186D1100CB88AF /* reporting_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CCBD15A1B186D1100CB88AF /* reporting_utils.m */; }; 8CD0D4171BD42A7D004478C0 /* RSSwizzle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7411BCB06F4005801D8 /* RSSwizzle.m */; settings = {ASSET_TAGS = (); COMPILER_FLAGS = "-Wno-sign-conversion -Wno-sign-compare"; }; }; + 8CD0D4271BD7159E004478C0 /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC321BAE2C1100BDA419 /* libassert_lib.a */; }; + 8CD0D4281BD7159E004478C0 /* libdomain_registry_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC331BAE2C1100BDA419 /* libdomain_registry_lib.a */; }; + 8CD0D4291BD7159E004478C0 /* libinit_registry_tables_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC341BAE2C1100BDA419 /* libinit_registry_tables_lib.a */; }; 8CD5F7311BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7321BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CD5F72F1BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h */; settings = {ASSET_TAGS = (); }; }; 8CD5F7331BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CD5F7301BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.m */; settings = {ASSET_TAGS = (); }; }; @@ -221,6 +224,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 8CD0D4271BD7159E004478C0 /* libassert_lib.a in Frameworks */, + 8CD0D4281BD7159E004478C0 /* libdomain_registry_lib.a in Frameworks */, + 8CD0D4291BD7159E004478C0 /* libinit_registry_tables_lib.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1018,7 +1024,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", + "$(PROJECT_DIR)/TrustKit", + "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/ios", ); ONLY_ACTIVE_ARCH = NO; OTHER_LDFLAGS = "-ObjC"; @@ -1042,7 +1049,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 7.0; LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry", + "$(PROJECT_DIR)/TrustKit", + "$(PROJECT_DIR)/TrustKit/Dependencies/domain_registry/ios", ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; From 90870c9096d4a3212c57f5824c69393aa6d193ee Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 17:56:58 -0700 Subject: [PATCH 117/118] Fix OS X scheme by making headers public --- TrustKit.xcodeproj/project.pbxproj | 8 ++++---- TrustKitDemo/TrustKitDemo/AppDelegate.m | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/TrustKit.xcodeproj/project.pbxproj b/TrustKit.xcodeproj/project.pbxproj index 0b10e3cb..ee1eed87 100644 --- a/TrustKit.xcodeproj/project.pbxproj +++ b/TrustKit.xcodeproj/project.pbxproj @@ -48,9 +48,9 @@ 8CA6CC201BAE2B6A00BDA419 /* public_key_utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE9191D1AEA073C002B29AE /* public_key_utils.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC211BAE2B6A00BDA419 /* ssl_pin_verifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919241AEA07C5002B29AE /* ssl_pin_verifier.h */; settings = {ASSET_TAGS = (); }; }; 8CA6CC221BAE2B6A00BDA419 /* ssl_pin_verifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CE919211AEA077F002B29AE /* ssl_pin_verifier.m */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC231BAE2B6A00BDA419 /* TSKPinningValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F9911B132F9200F06C0E /* TSKPinningValidator.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC231BAE2B6A00BDA419 /* TSKPinningValidator.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C15F9911B132F9200F06C0E /* TSKPinningValidator.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8CA6CC241BAE2B6A00BDA419 /* TSKPinningValidator.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C15F9921B132F9200F06C0E /* TSKPinningValidator.m */; settings = {ASSET_TAGS = (); }; }; - 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C84804C1A896EE30017C155 /* TrustKit.h */; settings = {ASSET_TAGS = (); }; }; + 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 8C84804C1A896EE30017C155 /* TrustKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8CA6CC261BAE2B6A00BDA419 /* TrustKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8C84806C1A896F660017C155 /* TrustKit.m */; settings = {ASSET_TAGS = (); }; }; 8CA6CC271BAE2B7000BDA419 /* domain_registry.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CE919291AEA0F7E002B29AE /* domain_registry.h */; settings = {ASSET_TAGS = (); }; }; 8CA6CC2F1BAE2C0700BDA419 /* libassert_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8CA6CC2C1BAE2C0700BDA419 /* libassert_lib.a */; settings = {ASSET_TAGS = (); }; }; @@ -476,17 +476,17 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */, + 8CA6CC231BAE2B6A00BDA419 /* TSKPinningValidator.h in Headers */, 8CD5F74A1BCB535E005801D8 /* TSKNSURLSessionDelegateProxy.h in Headers */, 8CA6CC1B1BAE2B6600BDA419 /* TSKPinFailureReport.h in Headers */, 8CA6CC141BAE2B6600BDA419 /* TSKReportsRateLimiter.h in Headers */, 8CD5F7321BC5ED4A005801D8 /* TSKNSURLConnectionDelegateProxy.h in Headers */, 8CA6CC211BAE2B6A00BDA419 /* ssl_pin_verifier.h in Headers */, - 8CA6CC251BAE2B6A00BDA419 /* TrustKit.h in Headers */, 8CD5F7431BCB06F4005801D8 /* RSSwizzle.h in Headers */, 8CA6CC191BAE2B6600BDA419 /* TSKBackgroundReporter.h in Headers */, 8CA6CC271BAE2B7000BDA419 /* domain_registry.h in Headers */, 8CA6CC161BAE2B6600BDA419 /* TSKReporterDelegate.h in Headers */, - 8CA6CC231BAE2B6A00BDA419 /* TSKPinningValidator.h in Headers */, 8CA6CC1D1BAE2B6600BDA419 /* reporting_utils.h in Headers */, 8CA6CC1F1BAE2B6A00BDA419 /* public_key_utils.h in Headers */, ); diff --git a/TrustKitDemo/TrustKitDemo/AppDelegate.m b/TrustKitDemo/TrustKitDemo/AppDelegate.m index bca54d1a..533abaa1 100644 --- a/TrustKitDemo/TrustKitDemo/AppDelegate.m +++ b/TrustKitDemo/TrustKitDemo/AppDelegate.m @@ -21,7 +21,6 @@ @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. - // Initialize TrustKit NSDictionary *trustKitConfig = @{ @@ -60,6 +59,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( }}}; [TrustKit initializeWithConfiguration:trustKitConfig]; + + [TSKPinningValidator evaluateTrust:NULL forHostname:NULL]; return YES; } From d57dfb971acf890387dc25d105b82d2cfa6be5ad Mon Sep 17 00:00:00 2001 From: Alban Diquet Date: Tue, 20 Oct 2015 18:12:29 -0700 Subject: [PATCH 118/118] Ignore internal header in appledoc --- docs/AppledocSettings.plist | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/AppledocSettings.plist b/docs/AppledocSettings.plist index d50390ed..3fc56d33 100755 --- a/docs/AppledocSettings.plist +++ b/docs/AppledocSettings.plist @@ -17,6 +17,7 @@ Reporting public_key_utils.h docs + ssl_pin_verifier.h --index-desc docs/api-doc-index.md