From b1f9598ed24b1ec1b6f24b004578e6736590998b Mon Sep 17 00:00:00 2001 From: Oliver Letterer Date: Fri, 28 Dec 2012 11:48:42 +0100 Subject: [PATCH 01/12] Adds SSLPinningMode to AFURLConnectionOperation and defaultSSLPinMode to AFHTTPClient. --- AFNetworking/AFHTTPClient.h | 8 ++++ AFNetworking/AFHTTPClient.m | 4 ++ AFNetworking/AFURLConnectionOperation.h | 14 ++++++ AFNetworking/AFURLConnectionOperation.m | 64 ++++++++++++++++++++++--- 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/AFNetworking/AFHTTPClient.h b/AFNetworking/AFHTTPClient.h index 68c6de8..79234b2 100644 --- a/AFNetworking/AFHTTPClient.h +++ b/AFNetworking/AFHTTPClient.h @@ -23,6 +23,7 @@ #import #import +#import "AFURLConnectionOperation.h" /** `AFHTTPClient` captures the common patterns of communicating with an web application over HTTP. It encapsulates information like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations. @@ -137,6 +138,13 @@ typedef enum { @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; #endif +/** + Default SSL pinning mode for each `AFHTTPRequestOperation` which will be enqueued with `enqueueHTTPRequestOperation:`. + */ +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ +@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode defaultSSLPinMode; +#endif + ///--------------------------------------------- /// @name Creating and Initializing HTTP Clients ///--------------------------------------------- diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m index 3fec759..ceda84d 100644 --- a/AFNetworking/AFHTTPClient.m +++ b/AFNetworking/AFHTTPClient.m @@ -524,6 +524,10 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) { #pragma mark - - (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation { +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ + operation.SSLPinningMode = self.defaultSSLPinMode; +#endif + [self.operationQueue addOperation:operation]; } diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h index 94c07e8..47139ac 100644 --- a/AFNetworking/AFURLConnectionOperation.h +++ b/AFNetworking/AFURLConnectionOperation.h @@ -24,6 +24,13 @@ #import +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ +typedef enum { + AFURLConnectionOperationSSLPinningModeCertificate = 0, + AFURLConnectionOperationSSLPinningModePublicKey +} AFURLConnectionOperationSSLPinningMode; +#endif + /** `AFURLConnectionOperation` is a subclass of `NSOperation` that implements `NSURLConnection` delegate methods. @@ -124,6 +131,13 @@ */ @property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding; +/** + The pinning mode which will be used for SSL connections. + */ +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ +@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode; +#endif + ///------------------------ /// @name Accessing Streams ///------------------------ diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index 0d27490..0a590a2 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -192,6 +192,36 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat return _pinnedCertificates; } ++ (NSArray *)pinnedPublicKeys { + static NSArray *_pinnedPublicKeys = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + NSArray *pinnedCertificates = [self pinnedCertificates]; + NSMutableArray *publicKeys = [NSMutableArray array]; + + for (NSData *data in pinnedCertificates) { + SecCertificateRef allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data); + NSParameterAssert(allowedCertificate); + + SecPolicyRef policy = SecPolicyCreateBasicX509(); + SecTrustRef allowedTrust = NULL; + OSStatus status = SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust); + NSAssert(status == noErr, @"SecTrustCreateWithCertificates error: %ld", status); + + SecKeyRef allowedPublicKey = SecTrustCopyPublicKey(allowedTrust); + [publicKeys addObject:(__bridge_transfer id)allowedPublicKey]; + + CFRelease(allowedTrust); + CFRelease(allowedCertificate); + } + + _pinnedPublicKeys = [[NSArray alloc] initWithArray:publicKeys]; + }); + + return _pinnedPublicKeys; +} + - (id)initWithRequest:(NSURLRequest *)urlRequest { self = [super init]; if (!self) { @@ -499,14 +529,34 @@ willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challe { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; - SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, 0); - NSData *certificateData = (__bridge_transfer NSData *)SecCertificateCopyData(certificate); - if ([[[self class] pinnedCertificates] containsObject:certificateData]) { - NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; - [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; - } else { - [[challenge sender] cancelAuthenticationChallenge:challenge]; + switch (self.SSLPinningMode) { + case AFURLConnectionOperationSSLPinningModeCertificate: { + SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0); + NSData *certificateData = (__bridge_transfer NSData *)SecCertificateCopyData(serverCertificate); + + if ([[[self class] pinnedCertificates] containsObject:certificateData]) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] cancelAuthenticationChallenge:challenge]; + } + break; + } case AFURLConnectionOperationSSLPinningModePublicKey: { + id publicKey = (__bridge_transfer id)SecTrustCopyPublicKey(serverTrust); + + for (id allowedPublicKey in [self.class pinnedPublicKeys]) { + if ([allowedPublicKey isEqual:publicKey]) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + + return; + } + } + + [[challenge sender] cancelAuthenticationChallenge:challenge]; + break; + } } } } From 3b1a09870165a04179e6e63b9c1f0fed1e145a27 Mon Sep 17 00:00:00 2001 From: Oliver Letterer Date: Sat, 29 Dec 2012 13:06:52 +0100 Subject: [PATCH 02/12] Fixes memory leak. --- AFNetworking/AFURLConnectionOperation.m | 1 + 1 file changed, 1 insertion(+) diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index 0a590a2..4633b8b 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -214,6 +214,7 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat CFRelease(allowedTrust); CFRelease(allowedCertificate); + CFRelease(policy); } _pinnedPublicKeys = [[NSArray alloc] initWithArray:publicKeys]; From 80bb2ea52730e16f70456919ff9f587740662647 Mon Sep 17 00:00:00 2001 From: Oliver Letterer Date: Sat, 29 Dec 2012 13:10:14 +0100 Subject: [PATCH 03/12] Gets rid of for loop to check if public key is present. --- AFNetworking/AFURLConnectionOperation.m | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index 4633b8b..c8d411c 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -546,16 +546,12 @@ willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challe } case AFURLConnectionOperationSSLPinningModePublicKey: { id publicKey = (__bridge_transfer id)SecTrustCopyPublicKey(serverTrust); - for (id allowedPublicKey in [self.class pinnedPublicKeys]) { - if ([allowedPublicKey isEqual:publicKey]) { - NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; - [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; - - return; - } + if ([[self.class pinnedPublicKeys] containsObject:publicKey]) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] cancelAuthenticationChallenge:challenge]; } - - [[challenge sender] cancelAuthenticationChallenge:challenge]; break; } } From 0e18f85bfb8ce731ff3d347e5b28a421f4cc6e5b Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Fri, 8 Feb 2013 14:21:52 +0100 Subject: [PATCH 04/12] Replacing #ifdef macro check for Security to _AFNETWORKING_PIN_SSL_CERTIFICATES_ --- AFNetworking/AFURLConnectionOperation.h | 4 ++-- AFNetworking/AFURLConnectionOperation.m | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h index ef2a87a..16f815f 100644 --- a/AFNetworking/AFURLConnectionOperation.h +++ b/AFNetworking/AFURLConnectionOperation.h @@ -76,7 +76,7 @@ - Operation copies do not include `completionBlock`. `completionBlock` often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ operation when copied. */ -#ifdef _SECURITY_SECBASE_H_ +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ typedef enum { AFSSLPinningModePublicKey, AFSSLPinningModeCertificate, @@ -162,7 +162,7 @@ NSCoding, NSCopying> /** The pinning mode which will be used for SSL connections. */ -#ifdef _SECURITY_SECBASE_H_ +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ @property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode; #endif diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index f4c7832..e273498 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -145,7 +145,7 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat @dynamic inputStream; @synthesize outputStream = _outputStream; @synthesize credential = _credential; -#ifdef _SECURITY_SECBASE_H_ +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ @synthesize SSLPinningMode = _SSLPinningMode; #endif @synthesize shouldUseCredentialStorage = _shouldUseCredentialStorage; @@ -178,7 +178,7 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat return _networkRequestThread; } -#ifdef _SECURITY_SECBASE_H_ +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ + (NSArray *)pinnedCertificates { static NSArray *_pinnedCertificates = nil; static dispatch_once_t onceToken; @@ -535,7 +535,7 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat #pragma mark - NSURLConnectionDelegate -#ifdef _SECURITY_SECBASE_H_ +#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { From 1053e00fff1fc8e03137f3d4a362330f7a989781 Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Fri, 8 Feb 2013 14:22:27 +0100 Subject: [PATCH 05/12] Removing #warning about Security framework --- AFNetworking/AFURLConnectionOperation.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h index 16f815f..c702f21 100644 --- a/AFNetworking/AFURLConnectionOperation.h +++ b/AFNetworking/AFURLConnectionOperation.h @@ -81,8 +81,6 @@ typedef enum { AFSSLPinningModePublicKey, AFSSLPinningModeCertificate, } AFURLConnectionOperationSSLPinningMode; -#else -#warning Security framework not found in project, or not included in precompiled header. SSL Certificate Pinning functionality will not be available. #endif @interface AFURLConnectionOperation : NSOperation Date: Fri, 8 Feb 2013 14:37:17 +0100 Subject: [PATCH 06/12] Fixing compiler warnings in SSL pinning initializers Minor refactoring --- AFNetworking/AFURLConnectionOperation.m | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index e273498..3d538e0 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -186,11 +186,12 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."]; - NSMutableArray *certificates = [NSMutableArray array]; + NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]]; for (NSString *path in paths) { NSData *certificateData = [NSData dataWithContentsOfFile:path]; [certificates addObject:certificateData]; } + _pinnedCertificates = [[NSArray alloc] initWithArray:certificates]; }); @@ -202,25 +203,29 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSArray *pinnedCertificates = [self pinnedCertificates]; - NSMutableArray *publicKeys = [NSMutableArray array]; + NSMutableArray *publicKeys = [NSMutableArray arrayWithCapacity:[pinnedCertificates count]]; for (NSData *data in pinnedCertificates) { SecCertificateRef allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data); - NSParameterAssert(allowedCertificate); + NSCParameterAssert(allowedCertificate); + + SecCertificateRef allowedCertificates[] = {allowedCertificate}; + CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL); SecPolicyRef policy = SecPolicyCreateBasicX509(); SecTrustRef allowedTrust = NULL; - OSStatus status = SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust); - NSAssert(status == noErr, @"SecTrustCreateWithCertificates error: %ld", status); + OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &allowedTrust); + NSAssert(status == noErr, @"SecTrustCreateWithCertificates error: %ld", (long int)status); SecKeyRef allowedPublicKey = SecTrustCopyPublicKey(allowedTrust); [publicKeys addObject:(__bridge_transfer id)allowedPublicKey]; - + CFRelease(allowedTrust); - CFRelease(allowedCertificate); CFRelease(policy); + CFRelease(certificates); + CFRelease(allowedCertificate); } - + _pinnedPublicKeys = [[NSArray alloc] initWithArray:publicKeys]; }); From 35c6f996c09f75e1534e09a923c8b03b3cc913f0 Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Fri, 8 Feb 2013 14:38:49 +0100 Subject: [PATCH 07/12] Adding Security framework to example projects and adding #define for _AFNETWORKING_PIN_SSL_CERTIFICATES_ --- Example/AFNetworking Mac Example.xcodeproj/project.pbxproj | 4 ++++ Example/AFNetworking iOS Example.xcodeproj/project.pbxproj | 2 ++ Example/Prefix.pch | 2 ++ 3 files changed, 8 insertions(+) diff --git a/Example/AFNetworking Mac Example.xcodeproj/project.pbxproj b/Example/AFNetworking Mac Example.xcodeproj/project.pbxproj index c679d72..55a77a5 100644 --- a/Example/AFNetworking Mac Example.xcodeproj/project.pbxproj +++ b/Example/AFNetworking Mac Example.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ F82EB080159A172000B10B56 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F82EB077159A172000B10B56 /* AFPropertyListRequestOperation.m */; }; F82EB081159A172000B10B56 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F82EB079159A172000B10B56 /* AFURLConnectionOperation.m */; }; F82EB082159A172000B10B56 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = F82EB07B159A172000B10B56 /* AFXMLRequestOperation.m */; }; + F88812F216C533E9003C8B8C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F88812F116C533E9003C8B8C /* Security.framework */; }; F8A847CF161F55A500940F39 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8A847CE161F55A500940F39 /* CoreServices.framework */; }; F8A847D2161F55AC00940F39 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8A847D1161F55AC00940F39 /* SystemConfiguration.framework */; }; /* End PBXBuildFile section */ @@ -57,6 +58,7 @@ F82EB07A159A172000B10B56 /* AFXMLRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AFXMLRequestOperation.h; path = ../AFNetworking/AFXMLRequestOperation.h; sourceTree = ""; }; F82EB07B159A172000B10B56 /* AFXMLRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AFXMLRequestOperation.m; path = ../AFNetworking/AFXMLRequestOperation.m; sourceTree = ""; }; F877018B159A1CE700B45C0D /* AFNetworking Example.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "AFNetworking Example.entitlements"; sourceTree = ""; }; + F88812F116C533E9003C8B8C /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; F8A847CE161F55A500940F39 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; F8A847D1161F55AC00940F39 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -66,6 +68,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F88812F216C533E9003C8B8C /* Security.framework in Frameworks */, F8A847D2161F55AC00940F39 /* SystemConfiguration.framework in Frameworks */, F8A847CF161F55A500940F39 /* CoreServices.framework in Frameworks */, F8129C001591061B009BFE23 /* Cocoa.framework in Frameworks */, @@ -78,6 +81,7 @@ F8129BF01591061B009BFE23 = { isa = PBXGroup; children = ( + F88812F116C533E9003C8B8C /* Security.framework */, F8A847D1161F55AC00940F39 /* SystemConfiguration.framework */, F8A847CE161F55A500940F39 /* CoreServices.framework */, F877018B159A1CE700B45C0D /* AFNetworking Example.entitlements */, diff --git a/Example/AFNetworking iOS Example.xcodeproj/project.pbxproj b/Example/AFNetworking iOS Example.xcodeproj/project.pbxproj index 16afe14..6467315 100644 --- a/Example/AFNetworking iOS Example.xcodeproj/project.pbxproj +++ b/Example/AFNetworking iOS Example.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ F8129C7415910C37009BFE23 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = F8129C7215910C37009BFE23 /* AppDelegate.m */; }; F818101615E6A0C600EF93C2 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50ABD6EC159FC2CE001BE42C /* MobileCoreServices.framework */; }; + F88812F016C533D6003C8B8C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8E469E013957DF100DB05C8 /* Security.framework */; }; F8A847C1161F51A300940F39 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F8A847C0161F51A300940F39 /* Default-568h@2x.png */; }; F8A847C3161F523E00940F39 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = F8A847C2161F523E00940F39 /* Default.png */; }; F8A847C5161F524200940F39 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F8A847C4161F524200940F39 /* Default@2x.png */; }; @@ -95,6 +96,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F88812F016C533D6003C8B8C /* Security.framework in Frameworks */, F8E469651395739D00DB05C8 /* UIKit.framework in Frameworks */, F8E469671395739D00DB05C8 /* Foundation.framework in Frameworks */, F8E469691395739D00DB05C8 /* CoreGraphics.framework in Frameworks */, diff --git a/Example/Prefix.pch b/Example/Prefix.pch index 18b984d..df78b3c 100644 --- a/Example/Prefix.pch +++ b/Example/Prefix.pch @@ -1,5 +1,7 @@ #import +#define _AFNETWORKING_PIN_SSL_CERTIFICATES_ + #if __IPHONE_OS_VERSION_MIN_REQUIRED #ifndef __IPHONE_3_0 #warning "This project uses features only available in iPhone SDK 3.0 and later." From d609df5321964ed99f7f0c1bf708810fc840a1b8 Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Fri, 8 Feb 2013 15:08:26 +0100 Subject: [PATCH 08/12] Adding documentation about SSL Pinning --- AFNetworking/AFURLConnectionOperation.h | 27 ++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h index c702f21..f8f9874 100644 --- a/AFNetworking/AFURLConnectionOperation.h +++ b/AFNetworking/AFURLConnectionOperation.h @@ -59,6 +59,14 @@ The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (i.e. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this. Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as ["The Deallocation Problem"](http://developer.apple.com/library/ios/#technotes/tn2109/). + + ## SSL Pinning + + Relying on the CA trust model to validate SSL certificates exposes your app to security vulnerabilities, such as man-in-the-middle attacks. For applications that connect to known servers, SSL certificate pinning provides an increased level of security, by checking server certificate validity against those specified in the app bundle. + + SSL with certificate pinning is strongly recommended for any application that transmits sensitive information to an external webservice. + + When `_AFNETWORKING_PIN_SSL_CERTIFICATES_` is defined and the Security framework is linked, connections will be validated on all matching certificates with a `.cer` extension in the bundle root. ## NSCoding & NSCopying Conformance @@ -158,7 +166,9 @@ NSCoding, NSCopying> @property (nonatomic, strong) NSURLCredential *credential; /** - The pinning mode which will be used for SSL connections. + The pinning mode which will be used for SSL connections. `AFSSLPinningModePublicKey` by default. + + @discussion To enable SSL Pinning, `#define _AFNETWORKING_PIN_SSL_CERTIFICATES_` in `Prefix.pch`. Also, make sure that the Security framework is linked with the binary. See the "SSL Pinning" section in the `AFURLConnectionOperation` header for more information. */ #ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ @property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode; @@ -304,6 +314,21 @@ NSCoding, NSCopying> ///---------------- /** + ## Network Reachability + + The following constants are provided by `AFURLConnectionOperation` as possible SSL Pinning options. + + enum { + AFSSLPinningModePublicKey, + AFSSLPinningModeCertificate, + } + + `AFSSLPinningModePublicKey` + Pin SSL connections to certificate public key (SPKI). + + `AFSSLPinningModeCertificate` + Pin SSL connections to exact certificate. This may cause problems when your certificate expires and needs re-issuance. + ## User info dictionary keys These keys may exist in the user info dictionary, in addition to those defined for NSError. From 8215c43680243097806250da2a88b396e3b3bf5f Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Fri, 8 Feb 2013 15:08:41 +0100 Subject: [PATCH 09/12] Minor reformatting of AFHTTPClient constants documentation --- AFNetworking/AFHTTPClient.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AFNetworking/AFHTTPClient.h b/AFNetworking/AFHTTPClient.h index bf8418f..1f58203 100644 --- a/AFNetworking/AFHTTPClient.h +++ b/AFNetworking/AFHTTPClient.h @@ -448,7 +448,7 @@ typedef enum { ///---------------- /** - ### Network Reachability + ## Network Reachability The following constants are provided by `AFHTTPClient` as possible network reachability statuses. @@ -479,7 +479,7 @@ typedef enum { A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification. The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status. - ### Parameter Encoding + ## Parameter Encoding The following constants are provided by `AFHTTPClient` as possible methods for serializing parameters into query string or message body values. From effd1136d2100d5acb555f2144568d54708434fe Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Fri, 8 Feb 2013 15:11:06 +0100 Subject: [PATCH 10/12] Adding Security frameworks to podspec, and defining _AFNETWORKING_PIN_SSL_CERTIFICATES_ --- AFNetworking.podspec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/AFNetworking.podspec b/AFNetworking.podspec index 8c6affc..b7e836b 100644 --- a/AFNetworking.podspec +++ b/AFNetworking.podspec @@ -10,13 +10,16 @@ Pod::Spec.new do |s| s.requires_arc = true s.ios.deployment_target = '5.0' - s.ios.frameworks = 'MobileCoreServices', 'SystemConfiguration' + s.ios.frameworks = 'MobileCoreServices', 'SystemConfiguration', 'Security' s.osx.deployment_target = '10.7' - s.osx.frameworks = 'CoreServices', 'SystemConfiguration' + s.osx.frameworks = 'CoreServices', 'SystemConfiguration', 'Security' s.prefix_header_contents = <<-EOS #import + +#define _AFNETWORKING_PIN_SSL_CERTIFICATES_ + #if __IPHONE_OS_VERSION_MIN_REQUIRED #import #import From 1bfed80989d984b35b6fac6439a7a7c8294d58fc Mon Sep 17 00:00:00 2001 From: Oliver Letterer Date: Fri, 8 Feb 2013 19:41:59 +0100 Subject: [PATCH 11/12] Adds `AFSSLPinningModeNone`. --- AFNetworking/AFURLConnectionOperation.h | 1 + AFNetworking/AFURLConnectionOperation.m | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h index f8f9874..f4c3b0e 100644 --- a/AFNetworking/AFURLConnectionOperation.h +++ b/AFNetworking/AFURLConnectionOperation.h @@ -86,6 +86,7 @@ #ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ typedef enum { + AFSSLPinningModeNone, AFSSLPinningModePublicKey, AFSSLPinningModeCertificate, } AFURLConnectionOperationSSLPinningMode; diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m index 3d538e0..24818de 100644 --- a/AFNetworking/AFURLConnectionOperation.m +++ b/AFNetworking/AFURLConnectionOperation.m @@ -579,6 +579,24 @@ willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challe break; } + case AFSSLPinningModeNone: { +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; +#else + SecTrustResultType result = 0; + OSStatus status = SecTrustEvaluate(serverTrust, &result); + NSAssert(status == noErr, @"SecTrustEvaluate error: %ld", (long int)status); + + if (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed) { + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] cancelAuthenticationChallenge:challenge]; + } +#endif + break; + } } } } From 8a642a26988486ef888a77c0459f52cea56584e4 Mon Sep 17 00:00:00 2001 From: Mattt Thompson Date: Sun, 24 Mar 2013 00:57:04 -0400 Subject: [PATCH 12/12] Minor formatting and documentation edits --- AFNetworking/AFHTTPClient.h | 2 +- AFNetworking/AFURLConnectionOperation.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/AFNetworking/AFHTTPClient.h b/AFNetworking/AFHTTPClient.h index 1f58203..cecaced 100644 --- a/AFNetworking/AFHTTPClient.h +++ b/AFNetworking/AFHTTPClient.h @@ -21,9 +21,9 @@ // THE SOFTWARE. #import +#import "AFURLConnectionOperation.h" #import -#import "AFURLConnectionOperation.h" /** `AFHTTPClient` captures the common patterns of communicating with an web application over HTTP. It encapsulates information like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations. diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h index f4c3b0e..1a54a5c 100644 --- a/AFNetworking/AFURLConnectionOperation.h +++ b/AFNetworking/AFURLConnectionOperation.h @@ -169,7 +169,7 @@ NSCoding, NSCopying> /** The pinning mode which will be used for SSL connections. `AFSSLPinningModePublicKey` by default. - @discussion To enable SSL Pinning, `#define _AFNETWORKING_PIN_SSL_CERTIFICATES_` in `Prefix.pch`. Also, make sure that the Security framework is linked with the binary. See the "SSL Pinning" section in the `AFURLConnectionOperation` header for more information. + @discussion To enable SSL Pinning, `#define _AFNETWORKING_PIN_SSL_CERTIFICATES_` in `Prefix.pch`. Also, make sure that the Security framework is linked with the binary. See the "SSL Pinning" section in the `AFURLConnectionOperation`" header for more information. */ #ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_ @property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode;