Adds SSLPinningMode to AFURLConnectionOperation and defaultSSLPinMode to AFHTTPClient.

This commit is contained in:
Oliver Letterer 2012-12-28 11:48:42 +01:00
parent 121ef7afa8
commit b1f9598ed2
4 changed files with 83 additions and 7 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

@ -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];
}

View file

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

View file

@ -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;
}
}
}
}