Stashing merge

This commit is contained in:
Mattt Thompson 2013-02-06 14:03:22 +01:00
commit 8cd63afe76
4 changed files with 94 additions and 5 deletions

View file

@ -23,6 +23,7 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#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
///---------------------------------------------

View file

@ -535,6 +535,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];
}

View file

@ -75,6 +75,16 @@
- A copy of an operation will not include the `outputStream` of the original.
- 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_
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 <NSURLConnectionDelegate,
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_5_0) || \
(defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_8)
@ -131,7 +141,6 @@ NSCoding, NSCopying>
*/
@property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding;
///-------------------------------
/// @name Managing URL Credentials
///-------------------------------
@ -150,6 +159,13 @@ NSCoding, NSCopying>
*/
@property (nonatomic, strong) NSURLCredential *credential;
/**
The pinning mode which will be used for SSL connections.
*/
#ifdef _SECURITY_SECBASE_H_
@property (nonatomic, assign) AFURLConnectionOperationSSLPinningMode SSLPinningMode;
#endif
///------------------------
/// @name Accessing Streams
///------------------------

View file

@ -145,6 +145,9 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat
@dynamic inputStream;
@synthesize outputStream = _outputStream;
@synthesize credential = _credential;
#ifdef _SECURITY_SECBASE_H_
@synthesize SSLPinningMode = _SSLPinningMode;
#endif
@synthesize shouldUseCredentialStorage = _shouldUseCredentialStorage;
@synthesize userInfo = _userInfo;
@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier;
@ -167,7 +170,6 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
@ -176,13 +178,14 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat
return _networkRequestThread;
}
#ifdef _SECURITY_SECBASE_H_
+ (NSArray *)pinnedCertificates {
static NSArray *_pinnedCertificates = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
NSMutableArray *certificates = [NSMutableArray array];
for (NSString *path in paths) {
NSData *certificateData = [NSData dataWithContentsOfFile:path];
@ -194,6 +197,37 @@ 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);
CFRelease(policy);
}
_pinnedPublicKeys = [[NSArray alloc] initWithArray:publicKeys];
});
return _pinnedPublicKeys;
}
#endif
- (id)initWithRequest:(NSURLRequest *)urlRequest {
self = [super init];
if (!self) {
@ -501,7 +535,7 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat
#pragma mark - NSURLConnectionDelegate
#ifdef _AFNETWORKING_PIN_SSL_CERTIFICATES_
#ifdef _SECURITY_SECBASE_H_
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
@ -514,12 +548,39 @@ willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challe
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
switch (self.SSLPinningMode) {
case AFSSLPinningModePublicKey: {
id publicKey = (__bridge_transfer id)SecTrustCopyPublicKey(serverTrust);
if ([[self.class pinnedPublicKeys] containsObject:publicKey]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
break;
}
case AFSSLPinningModeCertificate: {
SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0);
NSData *serverCertificateData = (__bridge_transfer NSData *)SecCertificateCopyData(serverCertificate);
if ([[[self class] pinnedCertificates] containsObject:serverCertificateData]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
break;
}
}
}
}
}
#endif
- (BOOL)connection:(NSURLConnection *)connection
canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
{