Skip to content

Commit

Permalink
Make it impossible to set a security policy with pinning on insecure …
Browse files Browse the repository at this point in the history
…URLs

### Before this commit
Setting a security policy configured with `AFSSLPinningModeCertificate` or `AFSSLPinningModePublicKey` on a AFHTTPSessionManager instance configured with an insecure `http` base URL was valid. Requests made with this manager would always succeed since the `-[AFURLSessionManager URLSession:didReceiveChallenge:completionHandler:]` would never be called and thus the security policy would never be evaluated.

### After this commit
Setting a security policy configured with `AFSSLPinningModeCertificate` or `AFSSLPinningModePublicKey` on a AFHTTPSessionManager instance configured with an insecure `http` base URL will throw an exception. This will force the manager to be configured with a secure `https` URL.

Note that properly configuring App Transport Security (ATS) would also solve this issue since insecure connections would fail anyway, but this is a *belt and suspenders* solution.
  • Loading branch information
0xced authored and kcharwood committed Oct 6, 2016
1 parent e337471 commit a26a500
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
9 changes: 9 additions & 0 deletions AFNetworking/AFHTTPSessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;

///-------------------------------
/// @name Managing Security Policy
///-------------------------------

/**
The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified. A security policy configured with `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate` can only be applied on a session manager initialized with a secure base URL (i.e. https). Applying a security policy with pinning enabled on an insecure session manager throws an `Invalid Security Policy` exception.
*/
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;

///---------------------
/// @name Initialization
///---------------------
Expand Down
17 changes: 17 additions & 0 deletions AFNetworking/AFHTTPSessionManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ - (void)setResponseSerializer:(AFHTTPResponseSerializer <AFURLResponseSerializat
[super setResponseSerializer:responseSerializer];
}

@dynamic securityPolicy;

- (void)setSecurityPolicy:(AFSecurityPolicy *)securityPolicy {
if (securityPolicy.SSLPinningMode != AFSSLPinningModeNone && ![self.baseURL.scheme isEqualToString:@"https"]) {
NSString *pinningMode = @"Unknown Pinning Mode";
switch (securityPolicy.SSLPinningMode) {
case AFSSLPinningModeNone: pinningMode = @"AFSSLPinningModeNone"; break;
case AFSSLPinningModeCertificate: pinningMode = @"AFSSLPinningModeCertificate"; break;
case AFSSLPinningModePublicKey: pinningMode = @"AFSSLPinningModePublicKey"; break;
}
NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode];
@throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil];
}

[super setSecurityPolicy:securityPolicy];
}

#pragma mark -

- (NSURLSessionDataTask *)GET:(NSString *)URLString
Expand Down
50 changes: 50 additions & 0 deletions Tests/Tests/AFHTTPSessionManagerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,56 @@ - (void)testHiddenBasicAuthentication {
[self waitForExpectationsWithCommonTimeoutUsingHandler:nil];
}

# pragma mark - Security Policy

- (void)testValidSecureNoPinningSecurityPolicy {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://example.com"]];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
XCTAssertNoThrow(manager.securityPolicy = securityPolicy);
}

- (void)testValidInsecureNoPinningSecurityPolicy {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://example.com"]];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
XCTAssertNoThrow(manager.securityPolicy = securityPolicy);
}

- (void)testValidCertificatePinningSecurityPolicy {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://example.com"]];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
XCTAssertNoThrow(manager.securityPolicy = securityPolicy);
}

- (void)testInvalidCertificatePinningSecurityPolicy {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://example.com"]];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy");
}

- (void)testValidPublicKeyPinningSecurityPolicy {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://example.com"]];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
XCTAssertNoThrow(manager.securityPolicy = securityPolicy);
}

- (void)testInvalidPublicKeyPinningSecurityPolicy {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://example.com"]];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy");
}

- (void)testInvalidCertificatePinningSecurityPolicyWithoutBaseURL {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy");
}

- (void)testInvalidPublicKeyPinningSecurityPolicyWithoutBaseURL {
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy");
}

# pragma mark - Server Trust

- (void)testInvalidServerTrustProducesCorrectErrorForCertificatePinning {
Expand Down

0 comments on commit a26a500

Please sign in to comment.