├── .gitignore ├── testapp ├── .gitignore ├── RootViewController.h ├── Resources │ ├── VeriSignClass3PublicPrimaryCertificationAuthority-G5.der │ └── Info.plist ├── main.m ├── control ├── Makefile ├── RootViewController.mm ├── SSLKillSwitchTestApplication.mm ├── TestSSLKillSwitch.h └── TestSSLKillSwitch.m ├── BH2012_MobileCertificatePinning.pdf ├── layout ├── Library │ └── PreferenceLoader │ │ └── Preferences │ │ ├── SSLKillSwitch.png │ │ └── SSLKillSwitch_prefs.plist └── DEBIAN │ └── control ├── .gitattributes ├── Makefile ├── README.md ├── LICENSE.txt └── Tweak.xm /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .theos 3 | theos 4 | *.deb 5 | obj 6 | _/* 7 | -------------------------------------------------------------------------------- /testapp/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .theos 3 | theos 4 | *.deb 5 | obj 6 | _/* 7 | -------------------------------------------------------------------------------- /testapp/RootViewController.h: -------------------------------------------------------------------------------- 1 | @interface RootViewController: UIViewController { 2 | } 3 | @end 4 | -------------------------------------------------------------------------------- /BH2012_MobileCertificatePinning.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nabla-c0d3/ios-ssl-kill-switch/HEAD/BH2012_MobileCertificatePinning.pdf -------------------------------------------------------------------------------- /layout/Library/PreferenceLoader/Preferences/SSLKillSwitch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nabla-c0d3/ios-ssl-kill-switch/HEAD/layout/Library/PreferenceLoader/Preferences/SSLKillSwitch.png -------------------------------------------------------------------------------- /testapp/Resources/VeriSignClass3PublicPrimaryCertificationAuthority-G5.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nabla-c0d3/ios-ssl-kill-switch/HEAD/testapp/Resources/VeriSignClass3PublicPrimaryCertificationAuthority-G5.der -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # These files are text and should be normalized (convert crlf => lf) 2 | *.h text 3 | *.m text 4 | *.xm text 5 | *.txt text 6 | *.md text 7 | Makefile text 8 | control text 9 | *.plist text 10 | -------------------------------------------------------------------------------- /testapp/main.m: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init]; 3 | int ret = UIApplicationMain(argc, argv, @"SSLKillSwitchTestApplication", @"SSLKillSwitchTestApplication"); 4 | [p drain]; 5 | return ret; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET := iphone:7.1 2 | ARCHS := armv7 arm64 3 | 4 | include theos/makefiles/common.mk 5 | 6 | TWEAK_NAME = SSLKillSwitch 7 | SSLKillSwitch_FILES = Tweak.xm 8 | 9 | SSLKillSwitch_FRAMEWORKS = UIKit Security 10 | include $(THEOS_MAKE_PATH)/tweak.mk 11 | include $(THEOS_MAKE_PATH)/aggregate.mk 12 | -------------------------------------------------------------------------------- /testapp/control: -------------------------------------------------------------------------------- 1 | Package: com.isecpartners.nabla.sslkillswitchtestapp 2 | Name: iOS SSL Kill Switch Test Application 3 | Depends: 4 | Version: 0.0.1 5 | Architecture: iphoneos-arm 6 | Description: iOS SSL Kill Switch Test Application 7 | Maintainer: Alban Diquet 8 | Author: Alban Diquet 9 | Section: Utilities 10 | -------------------------------------------------------------------------------- /testapp/Makefile: -------------------------------------------------------------------------------- 1 | include theos/makefiles/common.mk 2 | 3 | APPLICATION_NAME = SSLKillSwitchTestApplication 4 | SSLKillSwitchTestApplication_FILES = main.m SSLKillSwitchTestApplication.mm RootViewController.mm TestSSLKillSwitch.m 5 | SSLKillSwitchTestApplication_FRAMEWORKS = UIKit CoreGraphics Security CFNetwork 6 | 7 | include $(THEOS_MAKE_PATH)/application.mk 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | iOS SSL Kill Switch 2 | =================== 3 | 4 | Blackbox tool to disable SSL certificate validation - including certificate 5 | pinning - within iOS Apps. 6 | 7 | **The latest versions are now hosted on a different repository called 8 | [SSL Kill Switch 2](https://github.com/nabla-c0d3/ssl-kill-switch2).** 9 | 10 | 11 | Author 12 | ------ 13 | 14 | Alban Diquet - https://github.com/nabla-c0d3 15 | -------------------------------------------------------------------------------- /layout/DEBIAN/control: -------------------------------------------------------------------------------- 1 | Package: com.isecpartners.nabla.sslkillswitch 2 | Name: iOS SSL Kill Switch 3 | Depends: mobilesubstrate, preferenceloader 4 | Version: 0.6 5 | Architecture: iphoneos-arm 6 | Description: Blackbox tool to disable SSL certificate validation - including certificate pinning - within iOS Apps. 7 | Maintainer: Alban Diquet 8 | Author: Alban Diquet 9 | Section: Tweaks 10 | -------------------------------------------------------------------------------- /testapp/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | { 2 | CFBundleExecutable = "SSLKillSwitchTestApplication"; 3 | CFBundleIconFile = icon.png; 4 | CFBundleIdentifier = "com.isecpartners.nabla.sslkillswitchtestapp"; 5 | CFBundleInfoDictionaryVersion = 6.0; 6 | CFBundlePackageType = APPL; 7 | CFBundleSignature = "????"; 8 | CFBundleSupportedPlatforms = ( 9 | iPhoneOS 10 | ); 11 | CFBundleVersion = 1.0; 12 | DTPlatformName = iphoneos; 13 | DTSDKName = iphoneos3.0; 14 | LSRequiresIPhoneOS = 1; 15 | MinimumOSVersion = 3.0; 16 | } 17 | -------------------------------------------------------------------------------- /testapp/RootViewController.mm: -------------------------------------------------------------------------------- 1 | #import "RootViewController.h" 2 | #import "TestSSLKillSwitch.h" 3 | 4 | 5 | 6 | @implementation RootViewController 7 | - (void)loadView { 8 | self.view = [[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] autorelease]; 9 | self.view.backgroundColor = [UIColor redColor]; 10 | 11 | UIAlertView *alert = 12 | [[UIAlertView alloc] initWithTitle: @"iOS SSL Kill Switch" 13 | message: @"iOS SSL Kill Switch Test App Started" 14 | delegate: self 15 | cancelButtonTitle: @"OK" 16 | otherButtonTitles: nil]; 17 | [alert show]; 18 | [alert release]; 19 | 20 | [TestSSLKillSwitch runAllTests]; 21 | 22 | } 23 | @end 24 | 25 | -------------------------------------------------------------------------------- /testapp/SSLKillSwitchTestApplication.mm: -------------------------------------------------------------------------------- 1 | #import "RootViewController.h" 2 | 3 | @interface SSLKillSwitchTestApplication: UIApplication { 4 | UIWindow *_window; 5 | RootViewController *_viewController; 6 | } 7 | @property (nonatomic, retain) UIWindow *window; 8 | @end 9 | 10 | @implementation SSLKillSwitchTestApplication 11 | @synthesize window = _window; 12 | - (void)applicationDidFinishLaunching:(UIApplication *)application { 13 | _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 14 | _viewController = [[RootViewController alloc] init]; 15 | [_window addSubview:_viewController.view]; 16 | [_window makeKeyAndVisible]; 17 | } 18 | 19 | - (void)dealloc { 20 | [_viewController release]; 21 | [_window release]; 22 | [super dealloc]; 23 | } 24 | @end 25 | 26 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | This is the MIT license: http://www.opensource.org/licenses/mit-license.php 2 | 3 | Copyright 2012 Alban Diquet and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | software and associated documentation files (the "Software"), to deal in the Software 7 | without restriction, including without limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 9 | to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /layout/Library/PreferenceLoader/Preferences/SSLKillSwitch_prefs.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | cell 8 | PSLinkCell 9 | icon 10 | SSLKillSwitch.png 11 | label 12 | SSL Kill Switch 13 | 14 | items 15 | 16 | 17 | cell 18 | PSGroupCell 19 | label 20 | 21 | footerText 22 | SSL Kill Switch v0.6 - iSEC Partners 23 | 24 | 25 | cell 26 | PSSwitchCell 27 | default 28 | 29 | defaults 30 | com.isecpartners.nabla.SSLKillSwitchSettings 31 | key 32 | killSwitchSSLHandshake 33 | label 34 | Disable Certificate Validation 35 | 36 | 37 | title 38 | SSL Kill Switch 39 | 40 | 41 | -------------------------------------------------------------------------------- /testapp/TestSSLKillSwitch.h: -------------------------------------------------------------------------------- 1 | @interface TestSSLKillSwitch: NSObject { 2 | } 3 | 4 | + (void)runAllTests; 5 | + (void)testNSURLConnectionSSLPinning; 6 | + (void)testSecTrustEvaluateSSLPinning; 7 | 8 | @end 9 | 10 | 11 | 12 | @interface StreamDelegate: NSObject 13 | - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent; 14 | @end 15 | 16 | 17 | // NSURLConnectionDelegate - Generic class 18 | @interface SSLPinnedNSURLConnectionDelegate: NSObject { 19 | } 20 | 21 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection; 22 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; 23 | - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse; 24 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; 25 | - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse; 26 | - (void)handleAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; 27 | @end 28 | 29 | 30 | // NSURLConnectionDelegate - Custom cert validation - Strategy #1 31 | @interface SSLPinnedNSURLConnectionDelegate1: SSLPinnedNSURLConnectionDelegate { 32 | } 33 | - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; 34 | @end 35 | 36 | 37 | // NSURLConnectionDelegate - Custom cert validation - Strategy #2 38 | @interface SSLPinnedNSURLConnectionDelegate2: SSLPinnedNSURLConnectionDelegate { 39 | } 40 | - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace; 41 | - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; 42 | @end 43 | 44 | -------------------------------------------------------------------------------- /Tweak.xm: -------------------------------------------------------------------------------- 1 | #import 2 | #import "substrate.h" 3 | 4 | #define PREFERENCEFILE "/private/var/mobile/Library/Preferences/com.isecpartners.nabla.SSLKillSwitchSettings.plist" 5 | 6 | 7 | // Utility function to read the Tweak's preferences 8 | static BOOL shouldHookFromPreference(NSString *preferenceSetting) { 9 | NSString *preferenceFilePath = @PREFERENCEFILE; 10 | NSMutableDictionary* plist = [[NSMutableDictionary alloc] initWithContentsOfFile:preferenceFilePath]; 11 | 12 | if (!plist) { // Preference file not found, don't hook 13 | NSLog(@"SSL Kill Switch - Preference file not found."); 14 | return FALSE; 15 | } 16 | else { 17 | id shouldHook = [plist objectForKey:preferenceSetting]; 18 | if (shouldHook) { 19 | [plist release]; 20 | return [shouldHook boolValue]; 21 | } 22 | else { // Property was not set, don't hook 23 | NSLog(@"SSL Kill Switch - Preference not set."); 24 | [plist release]; 25 | return FALSE; 26 | } 27 | } 28 | } 29 | 30 | 31 | // Hook SSLSetSessionOption() 32 | static OSStatus (*original_SSLSetSessionOption)( 33 | SSLContextRef context, 34 | SSLSessionOption option, 35 | Boolean value); 36 | 37 | static OSStatus replaced_SSLSetSessionOption( 38 | SSLContextRef context, 39 | SSLSessionOption option, 40 | Boolean value) { 41 | 42 | // Remove the ability to modify the value of the kSSLSessionOptionBreakOnServerAuth option 43 | if (option == kSSLSessionOptionBreakOnServerAuth) 44 | return noErr; 45 | else 46 | return original_SSLSetSessionOption(context, option, value); 47 | } 48 | 49 | 50 | // Hook SSLCreateContext() 51 | static SSLContextRef (*original_SSLCreateContext) ( 52 | CFAllocatorRef alloc, 53 | SSLProtocolSide protocolSide, 54 | SSLConnectionType connectionType 55 | ); 56 | 57 | static SSLContextRef replaced_SSLCreateContext ( 58 | CFAllocatorRef alloc, 59 | SSLProtocolSide protocolSide, 60 | SSLConnectionType connectionType 61 | ) { 62 | SSLContextRef sslContext = original_SSLCreateContext(alloc, protocolSide, connectionType); 63 | 64 | // Immediately set the kSSLSessionOptionBreakOnServerAuth option in order to disable cert validation 65 | original_SSLSetSessionOption(sslContext, kSSLSessionOptionBreakOnServerAuth, true); 66 | return sslContext; 67 | } 68 | 69 | 70 | // Hook SSLHandshake() 71 | static OSStatus (*original_SSLHandshake)( 72 | SSLContextRef context 73 | ); 74 | 75 | static OSStatus replaced_SSLHandshake( 76 | SSLContextRef context 77 | ) { 78 | OSStatus result = original_SSLHandshake(context); 79 | 80 | // Hijack the flow when breaking on server authentication 81 | if (result == errSSLServerAuthCompleted) { 82 | // Do not check the cert and call SSLHandshake() again 83 | return original_SSLHandshake(context); 84 | } 85 | else 86 | return result; 87 | } 88 | 89 | 90 | %ctor { 91 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 92 | 93 | // Should we enable the hook ? 94 | if (shouldHookFromPreference(@"killSwitchSSLHandshake")) { 95 | NSLog(@"SSL Kill Switch - Hook Enabled."); 96 | MSHookFunction((void *) SSLHandshake,(void *) replaced_SSLHandshake, (void **) &original_SSLHandshake); 97 | MSHookFunction((void *) SSLSetSessionOption,(void *) replaced_SSLSetSessionOption, (void **) &original_SSLSetSessionOption); 98 | MSHookFunction((void *) SSLCreateContext,(void *) replaced_SSLCreateContext, (void **) &original_SSLCreateContext); 99 | } 100 | else { 101 | NSLog(@"SSL Kill Switch - Hook Disabled."); 102 | } 103 | 104 | [pool drain]; 105 | } 106 | -------------------------------------------------------------------------------- /testapp/TestSSLKillSwitch.m: -------------------------------------------------------------------------------- 1 | #import "TestSSLKillSwitch.h" 2 | 3 | @implementation TestSSLKillSwitch 4 | 5 | + (void)runAllTests { 6 | [self testNSURLConnectionSSLPinning]; 7 | [self testSecTrustEvaluateSSLPinning]; 8 | } 9 | 10 | 11 | + (void)testNSURLConnectionSSLPinning { 12 | // Test the Kill Switch on NSURLConnection 13 | // The connections will only work if SSL Kill Switch is enabled 14 | SSLPinnedNSURLConnectionDelegate* deleg1 = [[SSLPinnedNSURLConnectionDelegate1 alloc] init]; 15 | NSURLConnection *conn = [[NSURLConnection alloc] 16 | initWithRequest:[NSURLRequest requestWithURL: 17 | [NSURL URLWithString:@"https://www.isecpartners.com/"]] 18 | delegate:deleg1]; 19 | [conn start]; 20 | [deleg1 release]; // Give ownership to the connection 21 | 22 | 23 | SSLPinnedNSURLConnectionDelegate* deleg2 = [[SSLPinnedNSURLConnectionDelegate2 alloc] init]; 24 | NSURLConnection *conn2 = [[NSURLConnection alloc] 25 | initWithRequest:[NSURLRequest requestWithURL: 26 | [NSURL URLWithString:@"https://www.isecpartners.com/"]] 27 | delegate:deleg2 28 | startImmediately:NO]; 29 | [conn2 start]; 30 | [deleg2 release]; // Give ownership to the connection 31 | } 32 | 33 | 34 | + (void)testSecTrustEvaluateSSLPinning { 35 | // Test the Kill Switch on SecTrustEvaluate() 36 | // The connections will only work if SSL Kill Switch is enabled 37 | 38 | CFReadStreamRef readStream; 39 | CFWriteStreamRef writeStream; 40 | 41 | StreamDelegate *inStreamDelegate = [[StreamDelegate alloc] init]; 42 | StreamDelegate *outStreamDelegate = [[StreamDelegate alloc] init]; 43 | 44 | NSURL *website = [NSURL URLWithString:@"https://www.isecpartners.com"]; 45 | CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[website host], 443, &readStream, &writeStream); 46 | 47 | NSInputStream *inStream = (NSInputStream *)readStream; 48 | NSOutputStream *outStream = (NSOutputStream *) writeStream; 49 | 50 | [outStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey]; 51 | [inStream setProperty:NSStreamSocketSecurityLevelNegotiatedSSL forKey:NSStreamSocketSecurityLevelKey]; 52 | // Use an invalid hostname for cert validation to make the connection fail 53 | NSDictionary *sslSettings = [NSDictionary dictionaryWithObjectsAndKeys: @"www.bad.com", (id)kCFStreamSSLPeerName, nil]; 54 | [inStream setProperty: sslSettings forKey: (NSString *)kCFStreamPropertySSLSettings]; 55 | [outStream setProperty: sslSettings forKey: (NSString *)kCFStreamPropertySSLSettings]; 56 | 57 | CFReadStreamSetProperty(readStream, kCFStreamPropertySSLSettings, sslSettings); 58 | 59 | [inStream setDelegate:inStreamDelegate]; 60 | [outStream setDelegate:outStreamDelegate]; 61 | 62 | [inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 63 | [outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 64 | 65 | [inStream open]; 66 | [outStream open]; 67 | } 68 | 69 | 70 | @end 71 | 72 | 73 | 74 | @implementation StreamDelegate 75 | 76 | - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent { 77 | 78 | NSLog(@"%@ - Received: %x", NSStringFromClass([self class]), streamEvent); 79 | switch(streamEvent) { 80 | case NSStreamEventHasBytesAvailable: 81 | NSLog(@"%@ - Connection Succeeded"); 82 | break; 83 | case NSStreamEventErrorOccurred: 84 | NSLog(@"%@ - Error: %@", NSStringFromClass([self class]), [[theStream streamError] localizedDescription]); 85 | [theStream release]; 86 | break; 87 | default: 88 | break; 89 | } 90 | } 91 | 92 | @end 93 | 94 | 95 | 96 | @implementation SSLPinnedNSURLConnectionDelegate 97 | - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 98 | 99 | } 100 | 101 | - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 102 | NSLog(@"%@ - failed: %@", NSStringFromClass([self class]), error); 103 | } 104 | 105 | - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 106 | NSLog(@"%@ - received %d bytes", NSStringFromClass([self class]), [data length]); 107 | } 108 | 109 | - (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { 110 | return cachedResponse; 111 | } 112 | 113 | - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 114 | NSLog(@"%@ - success: %@", NSStringFromClass([self class]), [[response URL] host]); 115 | } 116 | 117 | - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse { 118 | NSLog(@"%@ - redirect: %@", NSStringFromClass([self class]), [[request URL] host]); 119 | return request; 120 | } 121 | 122 | - (void)handleAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { 123 | // Pin the wrong CA certificate => connection should only work if SSL Kill Switch is enabled 124 | 125 | if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 126 | SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; 127 | SecTrustResultType trustResult; 128 | 129 | // Load the anchor certificate 130 | NSString *certPath = [[NSString alloc] initWithFormat:@"%@/VeriSignClass3PublicPrimaryCertificationAuthority-G5.der", [[NSBundle mainBundle] bundlePath]]; 131 | NSData *anchorCertData = [[NSData alloc] initWithContentsOfFile:certPath]; 132 | if (anchorCertData == nil) { 133 | NSLog(@"Failed to load the certificates"); 134 | [[challenge sender] cancelAuthenticationChallenge: challenge]; 135 | return; 136 | } 137 | 138 | // Pin the anchor CA and validate the certificate chain 139 | SecCertificateRef anchorCertificate = SecCertificateCreateWithData(NULL, (CFDataRef)(anchorCertData)); 140 | NSArray *anchorArray = [NSArray arrayWithObject:(id)(anchorCertificate)]; 141 | SecTrustSetAnchorCertificates(serverTrust, (CFArrayRef)(anchorArray)); 142 | SecTrustEvaluate(serverTrust, &trustResult); 143 | CFRelease(anchorCertificate); 144 | 145 | if (trustResult == kSecTrustResultUnspecified) { 146 | // Continue connecting 147 | [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] 148 | forAuthenticationChallenge:challenge]; 149 | } 150 | else { 151 | // Certificate chain validation failed; cancel the connection 152 | [[challenge sender] cancelAuthenticationChallenge: challenge]; 153 | } 154 | } 155 | } 156 | @end 157 | 158 | 159 | 160 | @implementation SSLPinnedNSURLConnectionDelegate1 { 161 | } 162 | - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { 163 | [self handleAuthenticationChallenge:challenge]; 164 | } 165 | @end 166 | 167 | 168 | @implementation SSLPinnedNSURLConnectionDelegate2 { 169 | } 170 | - (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { 171 | return YES; 172 | } 173 | 174 | - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { 175 | [self handleAuthenticationChallenge:challenge]; 176 | } 177 | @end 178 | --------------------------------------------------------------------------------