Merge pull request #1047 from OliverLetterer/ssl-pinning-tests
SSL pinning tests
This commit is contained in:
commit
230afbbbf7
8 changed files with 323 additions and 12 deletions
|
|
@ -107,6 +107,26 @@ static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperat
|
|||
}
|
||||
}
|
||||
|
||||
#if !defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
static NSData *AFSecKeyGetData(SecKeyRef key) {
|
||||
CFDataRef data = NULL;
|
||||
|
||||
OSStatus status = SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data);
|
||||
NSCAssert(status == errSecSuccess, @"SecItemExport error: %ld", (long int)status);
|
||||
NSCParameterAssert(data);
|
||||
|
||||
return (__bridge_transfer NSData *)data;
|
||||
}
|
||||
#endif
|
||||
|
||||
static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
|
||||
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
return [(__bridge id)key1 isEqual:(__bridge id)key2];
|
||||
#else
|
||||
return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)];
|
||||
#endif
|
||||
}
|
||||
|
||||
@interface AFURLConnectionOperation ()
|
||||
@property (readwrite, nonatomic, assign) AFOperationState state;
|
||||
@property (readwrite, nonatomic, assign, getter = isCancelled) BOOL cancelled;
|
||||
|
|
@ -616,11 +636,15 @@ willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challe
|
|||
|
||||
switch (self.SSLPinningMode) {
|
||||
case AFSSLPinningModePublicKey: {
|
||||
NSArray *pinnedPublicKeys = [self.class pinnedPublicKeys];
|
||||
|
||||
for (id publicKey in trustChain) {
|
||||
if ([[self.class pinnedPublicKeys] containsObject:publicKey]) {
|
||||
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
|
||||
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
|
||||
return;
|
||||
for (id pinnedPublicKey in pinnedPublicKeys) {
|
||||
if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)publicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
|
||||
NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
|
||||
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@
|
|||
25C4EC42173D86B60083E116 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25C4EC30173D7DCA0083E116 /* MobileCoreServices.framework */; };
|
||||
29A9CE2117456336002360C8 /* AFJSONRequestOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A9CE2017456336002360C8 /* AFJSONRequestOperationTests.m */; };
|
||||
29A9CE2217456336002360C8 /* AFJSONRequestOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 29A9CE2017456336002360C8 /* AFJSONRequestOperationTests.m */; };
|
||||
A70F4A96175A529400386DF5 /* root_certificate.cer in Resources */ = {isa = PBXBuildFile; fileRef = A70F4A95175A529400386DF5 /* root_certificate.cer */; };
|
||||
A70F4A97175A529400386DF5 /* root_certificate.cer in Resources */ = {isa = PBXBuildFile; fileRef = A70F4A95175A529400386DF5 /* root_certificate.cer */; };
|
||||
A70F4A9E175A726B00386DF5 /* ca.cer in Resources */ = {isa = PBXBuildFile; fileRef = A70F4A9C175A726B00386DF5 /* ca.cer */; };
|
||||
A70F4A9F175A726B00386DF5 /* ca.cer in Resources */ = {isa = PBXBuildFile; fileRef = A70F4A9C175A726B00386DF5 /* ca.cer */; };
|
||||
A70F4AA0175A726B00386DF5 /* derived.cert in Resources */ = {isa = PBXBuildFile; fileRef = A70F4A9D175A726B00386DF5 /* derived.cert */; };
|
||||
A70F4AA1175A726B00386DF5 /* derived.cert in Resources */ = {isa = PBXBuildFile; fileRef = A70F4A9D175A726B00386DF5 /* derived.cert */; };
|
||||
A7DC62A617592E4200EBEC2F /* AFTestURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = A7DC62A517592E4200EBEC2F /* AFTestURLProtocol.m */; };
|
||||
A7DC62A717592E4200EBEC2F /* AFTestURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = A7DC62A517592E4200EBEC2F /* AFTestURLProtocol.m */; };
|
||||
A7DC62A917592E4800EBEC2F /* AFURLConnectionOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A7DC62A817592E4800EBEC2F /* AFURLConnectionOperationTests.m */; };
|
||||
|
|
@ -78,6 +84,9 @@
|
|||
2B6D24F8E1B74E10A269E8B3 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
55E73C267F33406A9F92476C /* libPods-ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ios.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
96A923755B00464187DEDBAF /* libPods-osx.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-osx.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
A70F4A95175A529400386DF5 /* root_certificate.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = root_certificate.cer; path = Resources/root_certificate.cer; sourceTree = "<group>"; };
|
||||
A70F4A9C175A726B00386DF5 /* ca.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = ca.cer; path = Resources/ca.cer; sourceTree = "<group>"; };
|
||||
A70F4A9D175A726B00386DF5 /* derived.cert */ = {isa = PBXFileReference; lastKnownFileType = file; name = derived.cert; path = Resources/derived.cert; sourceTree = "<group>"; };
|
||||
A7DC62A417592E4200EBEC2F /* AFTestURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFTestURLProtocol.h; sourceTree = "<group>"; };
|
||||
A7DC62A517592E4200EBEC2F /* AFTestURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFTestURLProtocol.m; sourceTree = "<group>"; };
|
||||
A7DC62A817592E4800EBEC2F /* AFURLConnectionOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLConnectionOperationTests.m; sourceTree = "<group>"; };
|
||||
|
|
@ -119,6 +128,7 @@
|
|||
25801549173EB4B40026AA6E /* Pods-ios.xcconfig */,
|
||||
2580154A173EB4B40026AA6E /* Pods-osx.xcconfig */,
|
||||
25801548173EB3B00026AA6E /* Tests */,
|
||||
A70F4A91175A4E0000386DF5 /* Certificates */,
|
||||
2544EC37173BE382004117E8 /* AFNetworking */,
|
||||
25A753091747FC7E00F04F2F /* Resources */,
|
||||
2544EC34173BE382004117E8 /* Frameworks */,
|
||||
|
|
@ -215,6 +225,16 @@
|
|||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
A70F4A91175A4E0000386DF5 /* Certificates */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A70F4A9C175A726B00386DF5 /* ca.cer */,
|
||||
A70F4A9D175A726B00386DF5 /* derived.cert */,
|
||||
A70F4A95175A529400386DF5 /* root_certificate.cer */,
|
||||
);
|
||||
name = Certificates;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
|
@ -287,6 +307,9 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F8C6F282174D2C6200B154D5 /* Icon.png in Resources */,
|
||||
A70F4A96175A529400386DF5 /* root_certificate.cer in Resources */,
|
||||
A70F4A9E175A726B00386DF5 /* ca.cer in Resources */,
|
||||
A70F4AA0175A726B00386DF5 /* derived.cert in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -295,6 +318,9 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F8C6F283174D2C6200B154D5 /* Icon.png in Resources */,
|
||||
A70F4A97175A529400386DF5 /* root_certificate.cer in Resources */,
|
||||
A70F4A9F175A726B00386DF5 /* ca.cer in Resources */,
|
||||
A70F4AA1175A726B00386DF5 /* derived.cert in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,14 +58,12 @@ static AFTestURLProtocolInitializationCallback _initializationCallback = nil;
|
|||
cachedResponse:(NSCachedURLResponse *)cachedResponse
|
||||
client:(id <NSURLProtocolClient>)client
|
||||
{
|
||||
NSParameterAssert(_initializationCallback);
|
||||
|
||||
self = [super initWithRequest:request cachedResponse:cachedResponse client:client];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self = _initializationCallback(self);
|
||||
self = _initializationCallback ? _initializationCallback(self) : self;
|
||||
|
||||
_matchingURL = nil;
|
||||
_initializationCallback = nil;
|
||||
|
|
@ -79,15 +77,25 @@ static AFTestURLProtocolInitializationCallback _initializationCallback = nil;
|
|||
|
||||
#pragma mark - NSURLAuthenticationChallengeSender
|
||||
|
||||
- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {}
|
||||
- (void)cancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {}
|
||||
- (void)continueWithoutCredentialForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)useCredential:(NSURLCredential *)credential
|
||||
forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {}
|
||||
forAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)performDefaultHandlingForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {}
|
||||
- (void)performDefaultHandlingForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
- (void)rejectProtectionSpaceAndContinueWithChallenge:(NSURLAuthenticationChallenge *)challenge {}
|
||||
- (void)rejectProtectionSpaceAndContinueWithChallenge:(NSURLAuthenticationChallenge *)challenge {
|
||||
[self doesNotRecognizeSelector:_cmd];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -68,4 +68,242 @@
|
|||
[operation cancel];
|
||||
}
|
||||
|
||||
- (void)testThatAFURLConnectionOperationTrustsPinnedCertificates {
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/path" relativeToURL:self.baseURL]];
|
||||
AFURLConnectionOperation *operation = [[AFURLConnectionOperation alloc] initWithRequest:request];
|
||||
operation.SSLPinningMode = AFSSLPinningModeCertificate;
|
||||
|
||||
__block BOOL useCredentialInvoked = NO;
|
||||
|
||||
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:request.URL.host port:request.URL.port.integerValue protocol:request.URL.scheme realm:nil authenticationMethod:NSURLAuthenticationMethodServerTrust];
|
||||
|
||||
NSData *certificateData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"root_certificate" ofType:@"cer"]];
|
||||
NSParameterAssert(certificateData);
|
||||
|
||||
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData);
|
||||
NSParameterAssert(certificate);
|
||||
|
||||
SecCertificateRef allowedCertificates[] = {certificate};
|
||||
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
|
||||
|
||||
SecPolicyRef policy = SecPolicyCreateBasicX509();
|
||||
SecTrustRef trust = NULL;
|
||||
OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &trust);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status);
|
||||
|
||||
SecTrustResultType result;
|
||||
status = SecTrustEvaluate(trust, &result);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
|
||||
|
||||
id mockedProtectionSpace = [OCMockObject partialMockForObject:protectionSpace];
|
||||
|
||||
[[[mockedProtectionSpace stub] andDo:^(NSInvocation *invocation) {
|
||||
[invocation setReturnValue:(void *)&trust];
|
||||
}] serverTrust];
|
||||
|
||||
AFTestURLProtocol *protocol = [[AFTestURLProtocol alloc] initWithRequest:request cachedResponse:nil client:nil];
|
||||
id mockedProtocol = [OCMockObject partialMockForObject:protocol];
|
||||
|
||||
void(^useCredential)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
|
||||
useCredentialInvoked = YES;
|
||||
};
|
||||
|
||||
[[[mockedProtocol stub] andDo:useCredential] useCredential:OCMOCK_ANY forAuthenticationChallenge:OCMOCK_ANY];
|
||||
|
||||
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:trust];
|
||||
NSURLAuthenticationChallenge *authenticationChallenge = [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:protectionSpace proposedCredential:credential previousFailureCount:0 failureResponse:nil error:nil sender:mockedProtocol];
|
||||
[protocol.client URLProtocol:mockedProtocol didReceiveAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
[operation connection:nil willSendRequestForAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
CFRelease(trust);
|
||||
CFRelease(policy);
|
||||
CFRelease(certificates);
|
||||
CFRelease(certificate);
|
||||
|
||||
expect(useCredentialInvoked).will.beTruthy();
|
||||
}
|
||||
|
||||
- (void)testThatAFURLConnectionOperationTrustsPinnedPublicKeys {
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/path" relativeToURL:self.baseURL]];
|
||||
AFURLConnectionOperation *operation = [[AFURLConnectionOperation alloc] initWithRequest:request];
|
||||
operation.SSLPinningMode = AFSSLPinningModePublicKey;
|
||||
|
||||
__block BOOL useCredentialInvoked = NO;
|
||||
|
||||
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:request.URL.host port:request.URL.port.integerValue protocol:request.URL.scheme realm:nil authenticationMethod:NSURLAuthenticationMethodServerTrust];
|
||||
|
||||
NSData *certificateData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"root_certificate" ofType:@"cer"]];
|
||||
NSParameterAssert(certificateData);
|
||||
|
||||
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData);
|
||||
NSParameterAssert(certificate);
|
||||
|
||||
SecCertificateRef allowedCertificates[] = {certificate};
|
||||
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
|
||||
|
||||
SecPolicyRef policy = SecPolicyCreateBasicX509();
|
||||
SecTrustRef trust = NULL;
|
||||
OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &trust);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status);
|
||||
|
||||
SecTrustResultType result;
|
||||
status = SecTrustEvaluate(trust, &result);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
|
||||
|
||||
id mockedProtectionSpace = [OCMockObject partialMockForObject:protectionSpace];
|
||||
|
||||
[[[mockedProtectionSpace stub] andDo:^(NSInvocation *invocation) {
|
||||
[invocation setReturnValue:(void *)&trust];
|
||||
}] serverTrust];
|
||||
|
||||
AFTestURLProtocol *protocol = [[AFTestURLProtocol alloc] initWithRequest:request cachedResponse:nil client:nil];
|
||||
id mockedProtocol = [OCMockObject partialMockForObject:protocol];
|
||||
|
||||
void(^useCredential)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
|
||||
useCredentialInvoked = YES;
|
||||
};
|
||||
|
||||
[[[mockedProtocol stub] andDo:useCredential] useCredential:OCMOCK_ANY forAuthenticationChallenge:OCMOCK_ANY];
|
||||
|
||||
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:trust];
|
||||
NSURLAuthenticationChallenge *authenticationChallenge = [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:protectionSpace proposedCredential:credential previousFailureCount:0 failureResponse:nil error:nil sender:mockedProtocol];
|
||||
[protocol.client URLProtocol:mockedProtocol didReceiveAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
[operation connection:nil willSendRequestForAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
CFRelease(trust);
|
||||
CFRelease(policy);
|
||||
CFRelease(certificates);
|
||||
CFRelease(certificate);
|
||||
|
||||
expect(useCredentialInvoked).will.beTruthy();
|
||||
}
|
||||
|
||||
- (void)testThatAFURLConnectionOperationTrustsPublicKeysOfDerivedCertificates {
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/path" relativeToURL:self.baseURL]];
|
||||
AFURLConnectionOperation *operation = [[AFURLConnectionOperation alloc] initWithRequest:request];
|
||||
operation.SSLPinningMode = AFSSLPinningModePublicKey;
|
||||
|
||||
__block BOOL useCredentialInvoked = NO;
|
||||
|
||||
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:request.URL.host port:request.URL.port.integerValue protocol:request.URL.scheme realm:nil authenticationMethod:NSURLAuthenticationMethodServerTrust];
|
||||
|
||||
NSData *caCertificateData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"ca" ofType:@"cer"]];
|
||||
NSParameterAssert(caCertificateData);
|
||||
|
||||
SecCertificateRef caCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCertificateData);
|
||||
NSParameterAssert(caCertificate);
|
||||
|
||||
NSData *hostCertificateData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"derived" ofType:@"cert"]];
|
||||
NSParameterAssert(hostCertificateData);
|
||||
|
||||
SecCertificateRef hostCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCertificateData);
|
||||
NSParameterAssert(hostCertificate);
|
||||
|
||||
SecCertificateRef allowedCertificates[] = {caCertificate, hostCertificate};
|
||||
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 2, NULL);
|
||||
|
||||
SecPolicyRef policy = SecPolicyCreateBasicX509();
|
||||
SecTrustRef trust = NULL;
|
||||
OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &trust);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status);
|
||||
|
||||
SecTrustResultType result;
|
||||
status = SecTrustEvaluate(trust, &result);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
|
||||
|
||||
id mockedProtectionSpace = [OCMockObject partialMockForObject:protectionSpace];
|
||||
|
||||
[[[mockedProtectionSpace stub] andDo:^(NSInvocation *invocation) {
|
||||
[invocation setReturnValue:(void *)&trust];
|
||||
}] serverTrust];
|
||||
|
||||
AFTestURLProtocol *protocol = [[AFTestURLProtocol alloc] initWithRequest:request cachedResponse:nil client:nil];
|
||||
id mockedProtocol = [OCMockObject partialMockForObject:protocol];
|
||||
|
||||
void(^useCredential)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
|
||||
useCredentialInvoked = YES;
|
||||
};
|
||||
|
||||
[[[mockedProtocol stub] andDo:useCredential] useCredential:OCMOCK_ANY forAuthenticationChallenge:OCMOCK_ANY];
|
||||
|
||||
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:trust];
|
||||
NSURLAuthenticationChallenge *authenticationChallenge = [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:protectionSpace proposedCredential:credential previousFailureCount:0 failureResponse:nil error:nil sender:mockedProtocol];
|
||||
[protocol.client URLProtocol:mockedProtocol didReceiveAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
[operation connection:nil willSendRequestForAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
CFRelease(trust);
|
||||
CFRelease(policy);
|
||||
CFRelease(certificates);
|
||||
CFRelease(caCertificate);
|
||||
CFRelease(hostCertificate);
|
||||
|
||||
expect(useCredentialInvoked).will.beTruthy();
|
||||
}
|
||||
|
||||
- (void)testThatAFURLConnectionOperationTrustsDerivedCertificates {
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"/path" relativeToURL:self.baseURL]];
|
||||
AFURLConnectionOperation *operation = [[AFURLConnectionOperation alloc] initWithRequest:request];
|
||||
operation.SSLPinningMode = AFSSLPinningModeCertificate;
|
||||
|
||||
__block BOOL useCredentialInvoked = NO;
|
||||
|
||||
NSURLProtectionSpace *protectionSpace = [[NSURLProtectionSpace alloc] initWithHost:request.URL.host port:request.URL.port.integerValue protocol:request.URL.scheme realm:nil authenticationMethod:NSURLAuthenticationMethodServerTrust];
|
||||
|
||||
NSData *caCertificateData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"ca" ofType:@"cer"]];
|
||||
NSParameterAssert(caCertificateData);
|
||||
|
||||
SecCertificateRef caCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCertificateData);
|
||||
NSParameterAssert(caCertificate);
|
||||
|
||||
NSData *hostCertificateData = [NSData dataWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForResource:@"derived" ofType:@"cert"]];
|
||||
NSParameterAssert(hostCertificateData);
|
||||
|
||||
SecCertificateRef hostCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCertificateData);
|
||||
NSParameterAssert(hostCertificate);
|
||||
|
||||
SecCertificateRef allowedCertificates[] = {caCertificate, hostCertificate};
|
||||
CFArrayRef certificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 2, NULL);
|
||||
|
||||
SecPolicyRef policy = SecPolicyCreateBasicX509();
|
||||
SecTrustRef trust = NULL;
|
||||
OSStatus status = SecTrustCreateWithCertificates(certificates, policy, &trust);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustCreateWithCertificates error: %ld", (long int)status);
|
||||
|
||||
SecTrustResultType result;
|
||||
status = SecTrustEvaluate(trust, &result);
|
||||
NSAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);
|
||||
|
||||
id mockedProtectionSpace = [OCMockObject partialMockForObject:protectionSpace];
|
||||
|
||||
[[[mockedProtectionSpace stub] andDo:^(NSInvocation *invocation) {
|
||||
[invocation setReturnValue:(void *)&trust];
|
||||
}] serverTrust];
|
||||
|
||||
AFTestURLProtocol *protocol = [[AFTestURLProtocol alloc] initWithRequest:request cachedResponse:nil client:nil];
|
||||
id mockedProtocol = [OCMockObject partialMockForObject:protocol];
|
||||
|
||||
void(^useCredential)(NSInvocation *invocation) = ^(NSInvocation *invocation) {
|
||||
useCredentialInvoked = YES;
|
||||
};
|
||||
|
||||
[[[mockedProtocol stub] andDo:useCredential] useCredential:OCMOCK_ANY forAuthenticationChallenge:OCMOCK_ANY];
|
||||
|
||||
NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:trust];
|
||||
NSURLAuthenticationChallenge *authenticationChallenge = [[NSURLAuthenticationChallenge alloc] initWithProtectionSpace:protectionSpace proposedCredential:credential previousFailureCount:0 failureResponse:nil error:nil sender:mockedProtocol];
|
||||
[protocol.client URLProtocol:mockedProtocol didReceiveAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
[operation connection:nil willSendRequestForAuthenticationChallenge:authenticationChallenge];
|
||||
|
||||
CFRelease(trust);
|
||||
CFRelease(policy);
|
||||
CFRelease(certificates);
|
||||
CFRelease(caCertificate);
|
||||
CFRelease(hostCertificate);
|
||||
|
||||
expect(useCredentialInvoked).will.beTruthy();
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
BIN
Tests/Resources/ca.cer
Normal file
BIN
Tests/Resources/ca.cer
Normal file
Binary file not shown.
BIN
Tests/Resources/derived.cert
Normal file
BIN
Tests/Resources/derived.cert
Normal file
Binary file not shown.
BIN
Tests/Resources/root_certificate.cer
Normal file
BIN
Tests/Resources/root_certificate.cer
Normal file
Binary file not shown.
15
Tests/Resources/root_certificate.key
Normal file
15
Tests/Resources/root_certificate.key
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCc9QJKFLopeILA83YzRmFenXIcgfIIaIbfCbFbvm/ntwCtZ7eK
|
||||
cqGBA2SI/kSEJGpIkpzq0lyb1ZJB8ayGD8p8lKfxnmOsc1RSzXz3cieomqF3ftIF
|
||||
21yp79qnwo8roWV2AAolWnmcpCwbrWmgbWueupl7ieu4gcSOXU4EikwGKwIDAQAB
|
||||
AoGASq0zmqWD8Sk6JK1xJnIs74Q/f5q/2gpJaSLGdJ0FxxxFwTsgk0l419YSZi97
|
||||
z9c3jjHbYMoXb7lMbf2bFOm8b4zQvmdVpLbiHC9Lned30VHgZJ55WSPd0GQJl9EJ
|
||||
uw4C9J2Uk7uUjQbbgGPHwO5w/75F++Cp5jN91M/7fqgxO9kCQQDMC15vSVrHR0hU
|
||||
GO235KeaDIUlIWBQYcPXZTn2kBfpSE2T3aYuIqfM5fx0z5A4nSM9Ylo/FOrm+y/p
|
||||
ogT+APTFAkEAxOxAn09r9vx46drP8ap8ca2+0x46+1xVoaAdUv/OlXV4Ftgo5l7h
|
||||
5ZRvs+JILmtvErtzkaUiCudh96F3tLAeLwJAOXO2ClW4NsYuamd+f7nlKy39S2Aj
|
||||
c16juwFombEm2mueVFUjlnfxkXLsa6OJ8zbjlkQcLwjfv1vYuMsC5tY0FQJBAJcd
|
||||
hWm7lOpwTImI9NJLNjw2TJ3OMQz7imsBZ/9tdqaTApjlQF2oqkl3Y1DzcNjOcOo7
|
||||
FzDJPBqJ/U/+hNIP5NkCQCUhCnfTXxx48sL7XKjlTr66rEbk3e1rZL7vx+24jcax
|
||||
xUooGhnRWaQsbEynVteYbPg7I8e8N6YEHtW5jwxhFaE=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
Loading…
Add table
Reference in a new issue