From 5dcfe99c93fe76b76bcad87eafe78a3fd027c5d8 Mon Sep 17 00:00:00 2001 From: Oliver Letterer Date: Sat, 1 Jun 2013 20:38:08 +0200 Subject: [PATCH] Adding tests for trusting derived certificates. --- .../project.pbxproj | 12 ++ Tests/AFURLConnectionOperationTests.m | 126 ++++++++++++++++++ Tests/Resources/ca.cer | Bin 0 -> 879 bytes Tests/Resources/derived.cert | Bin 0 -> 916 bytes 4 files changed, 138 insertions(+) create mode 100644 Tests/Resources/ca.cer create mode 100644 Tests/Resources/derived.cert diff --git a/Tests/AFNetworking Tests.xcodeproj/project.pbxproj b/Tests/AFNetworking Tests.xcodeproj/project.pbxproj index 4e64c3d..f4c273d 100644 --- a/Tests/AFNetworking Tests.xcodeproj/project.pbxproj +++ b/Tests/AFNetworking Tests.xcodeproj/project.pbxproj @@ -27,6 +27,10 @@ 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 */; }; @@ -81,6 +85,8 @@ 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 = ""; }; + A70F4A9C175A726B00386DF5 /* ca.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = ca.cer; path = Resources/ca.cer; sourceTree = ""; }; + A70F4A9D175A726B00386DF5 /* derived.cert */ = {isa = PBXFileReference; lastKnownFileType = file; name = derived.cert; path = Resources/derived.cert; sourceTree = ""; }; A7DC62A417592E4200EBEC2F /* AFTestURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFTestURLProtocol.h; sourceTree = ""; }; A7DC62A517592E4200EBEC2F /* AFTestURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFTestURLProtocol.m; sourceTree = ""; }; A7DC62A817592E4800EBEC2F /* AFURLConnectionOperationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLConnectionOperationTests.m; sourceTree = ""; }; @@ -222,6 +228,8 @@ A70F4A91175A4E0000386DF5 /* Certificates */ = { isa = PBXGroup; children = ( + A70F4A9C175A726B00386DF5 /* ca.cer */, + A70F4A9D175A726B00386DF5 /* derived.cert */, A70F4A95175A529400386DF5 /* root_certificate.cer */, ); name = Certificates; @@ -300,6 +308,8 @@ files = ( F8C6F282174D2C6200B154D5 /* Icon.png in Resources */, A70F4A96175A529400386DF5 /* root_certificate.cer in Resources */, + A70F4A9E175A726B00386DF5 /* ca.cer in Resources */, + A70F4AA0175A726B00386DF5 /* derived.cert in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -309,6 +319,8 @@ files = ( F8C6F283174D2C6200B154D5 /* Icon.png in Resources */, A70F4A97175A529400386DF5 /* root_certificate.cer in Resources */, + A70F4A9F175A726B00386DF5 /* ca.cer in Resources */, + A70F4AA1175A726B00386DF5 /* derived.cert in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Tests/AFURLConnectionOperationTests.m b/Tests/AFURLConnectionOperationTests.m index d575339..44cc410 100644 --- a/Tests/AFURLConnectionOperationTests.m +++ b/Tests/AFURLConnectionOperationTests.m @@ -180,4 +180,130 @@ 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 diff --git a/Tests/Resources/ca.cer b/Tests/Resources/ca.cer new file mode 100644 index 0000000000000000000000000000000000000000..b04dc96b72b33a01235ed4925df78ca5e2274d60 GIT binary patch literal 879 zcmXqLV$L>bV!E<`nTe5!iIZV=uR^>?-h@pCylk9WZ60mkc^Mg5Ss4r(8w|M(IN6v( zS=fY`TwD!B41_=&4qD9G zq?lQl-#;g_EVW3%C$*#`wJ5d7KtY_>(AdDtz|hdb(A2;(N`l|W5GY`3U;z~v432D^ zj~sH0tPISJy};1xWNK_=xR_KN8okU+=0^O+mz-DYW^U13%2An>vi4Qf#&_ax^1nnl znytuw5EPly&3qz#!P}X#byqf=t*mR_|72^zhG|X>GeS*uIsFa$@(;aynP6I(uf_hR zLUVrIdvTXu#Yy|r#2Cabt8`b}T;d6RCwKG9`E~De=1+asyM{@7pX_TbnN9sn%!~|- ziyL1UG(I(u1qQM#ABz}^Nd8ZyuII9==3lr_Q@(GrmQ46AO&f#8tsr@2md3RPjjI~4 zs#)0BwxqFn5QKRXQmW+vIa`>8)qt6i@jr4*0MjrtFbbq^u}yN^f6uC0==w_w$*bz- z^8=rj9IbX}-LSJfyPKhsu|7ESpx4?-H~7D-o7X<;>Jo*Wn?zHUHcVZ4GOWDbkS#e% z`)BC}BbMgW+I7|OENhDoMd#bBUHaGd@n7|$jf+GlU0A;>{`W444O2dPulU-`EV1HZ S|MZ7X?fPy;=Rezf`!N7=#u;1y literal 0 HcmV?d00001 diff --git a/Tests/Resources/derived.cert b/Tests/Resources/derived.cert new file mode 100644 index 0000000000000000000000000000000000000000..46bf343f3dbed87bfad0e30badd1219c0a86a03e GIT binary patch literal 916 zcmXqLVxC~o#Po9kGZP~d6CgCq%%usJU^u2ObdvCZw<5rNoGE3uHgT_@2BKbd+x}M9f znt$O!P5HjfS~B6gG;J0(wk>IF9t6?V#K|zbS0P>`Z^9Qub=mQdhXBa bnB5ak{CFi3Upv=k?qrFO^zVw-d28|kU#A<6 literal 0 HcmV?d00001