Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(344)

Side by Side Diff: components/cronet/ios/test/cronet_pkp_test.mm

Issue 2928653002: [Cronet-iOS] Public-Key-Pinning Tests (Closed)
Patch Set: Replace static with anonymous namespace Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <Cronet/Cronet.h>
6
7 #include "components/cronet/ios/test/start_cronet.h"
8 #include "components/grpc_support/test/quic_test_server.h"
9 #include "cronet_test_base.h"
10 #include "net/base/mac/url_conversions.h"
11 #include "net/cert/mock_cert_verifier.h"
12 #include "net/test/cert_test_util.h"
13 #include "net/test/test_data_directory.h"
14
15 #include "testing/gtest_mac.h"
16
17 namespace {
18 const bool kINCLUDE_SUBDOMAINS = true;
19 const bool kEXCLUDE_SUBDOMAINS = false;
20 const std::string kSERVER_CERT = "quic_test.example.com.crt";
21 NSDate* distant_future = [NSDate distantFuture];
22 } // namespace
23
24 namespace cronet {
25 // Tests public-key-pinning functionality.
26 class PkpTest : public CronetTestBase {
27 protected:
28 void SetUp() override {
29 CronetTestBase::SetUp();
30
31 NSString* full_url_str = [NSString
32 stringWithFormat:@"%@:%i",
33 [NSString
34 stringWithCString:grpc_support::kTestServerUrl
35 encoding:NSUTF8StringEncoding],
36 grpc_support::GetQuicTestServerPort()];
37 request_url_ = [NSURL URLWithString:full_url_str];
38 server_host_ = request_url_.host;
39 NSArray<NSString*>* components = [server_host_
40 componentsSeparatedByCharactersInSet:
41 [NSCharacterSet characterSetWithCharactersInString:@"."]];
42 domain_ =
43 [NSString stringWithFormat:@"%@.%@", components[components.count - 2],
44 components[components.count - 1]];
45
46 // Create a Cronet enabled NSURLSession
47 NSURLSessionConfiguration* sessionConfig =
48 [NSURLSessionConfiguration defaultSessionConfiguration];
49 [Cronet installIntoSessionConfiguration:sessionConfig];
50 url_session_ = [NSURLSession sessionWithConfiguration:sessionConfig
51 delegate:delegate_
52 delegateQueue:nil];
53
54 // Set mock cert verifier
55 [Cronet setMockCertVerifier:CreateMockCertVerifier({kSERVER_CERT}, YES)];
56 }
57
58 void TearDown() override {
59 [Cronet shutdownForTesting];
60 CronetTestBase::TearDown();
61 }
62
63 // Sends a request to a given URL, waits for the response and asserts that
64 // the response doesn't contain an error.
65 void sendRequestAndAssertSuccess(NSURL* url) {
lilyhoughton 2017/06/09 17:07:52 nit: I don't think these are much clearer than usi
kapishnikov 2017/06/09 21:27:02 Done.
66 sendRequestAndAssertResult(url, true);
67 }
68
69 // Sends a request to a given URL, waits for the response and asserts that
70 // the response contains an error.
71 void sendRequestAndAssertError(NSURL* url) {
72 sendRequestAndAssertResult(url, false);
73 }
74
75 // Sends a request to a given URL, waits for the response and asserts that
76 // the response is either successful or containing an error depending on
77 // the value of the passed |expected_success| parameter.
78 void sendRequestAndAssertResult(NSURL* url, bool expected_success) {
79 NSURLSessionDataTask* dataTask =
80 [url_session_ dataTaskWithURL:request_url_];
81 StartDataTaskAndWaitForCompletion(dataTask);
82 if (expected_success) {
lilyhoughton 2017/06/09 17:07:51 nit: why not just something like |ASSERT_EQ(IsResp
kapishnikov 2017/06/09 21:27:02 It doesn't show an error message if I change it to
83 ASSERT_TRUE(IsResponseSuccessful());
84 } else {
85 ASSERT_FALSE(IsResponseSuccessful());
86 }
87 }
88
89 // Adds a give public-key-pin and starts a Cronet engine for testing.
90 static void AddPkpAndStartCronet(NSString* host,
91 NSData* hash,
92 BOOL include_subdomains,
93 const NSDate* expiration_date) {
94 NSSet* hashes = [NSSet setWithObject:hash];
95 [Cronet addPublicKeyPinsForHost:host
96 pinHashes:hashes
97 includeSubdomains:include_subdomains
98 expirationDate:(NSDate*)expiration_date];
99 StartCronet(grpc_support::GetQuicTestServerPort());
100 }
101
102 // Returns an arbitrary public key hash that doesn't match with any test
103 // certificate.
104 static NSData* NonMatchingHash() {
105 const int length = 32;
106 u_char hash[length];
107 memset(hash, 77, length);
108 return [NSData dataWithBytes:hash length:length];
109 }
110
111 NSURLSession* url_session_;
112 NSURL* request_url_; // "https://test.example.com/hello.txt:62922"
113 NSString* server_host_; // test.example.com
114 NSString* domain_; // example.com
115
116 }; // class PkpTest
117
118 // Tests the case when a mismatching pin is set for some host that is
119 // different from the one the client wants to access. In that case the other
120 // host pinning policy should not be applied and the client is expected to
121 // receive the successful response with the response code 200.
122 TEST_F(PkpTest, TestSuccessIfPinSetForDifferentHost) {
123 AddPkpAndStartCronet(@"some-other-host.com", NonMatchingHash(),
124 kEXCLUDE_SUBDOMAINS, distant_future);
125 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
126 }
127
128 // Tests the case when the pin hash does not match. The client is expected to
129 // receive the error response.
130 TEST_F(PkpTest, TestErrorIfPinDoesNotMatch) {
131 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
132 distant_future);
133 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
lilyhoughton 2017/06/09 17:07:51 Is it possible to make the test more robust with r
kapishnikov 2017/06/09 21:27:02 Unfortunately because of http://crbug.com/548378 w
134 }
135
136 // Tests the case when the pin hash matches. The client is expected to
137 // receive the successful response with the response code 200.
138 TEST_F(PkpTest, TestSuccessIfPinMatches) {
139 // Calculate hash of the server certificate
140 scoped_refptr<net::X509Certificate> cert =
141 net::ImportCertFromFile(net::GetTestCertsDirectory(), kSERVER_CERT);
142 net::HashValue hash_value;
143 CalculatePublicKeySha256(*cert, &hash_value);
144 ASSERT_EQ(32ul, hash_value.size());
145 NSData* matching_hash =
146 [NSData dataWithBytes:hash_value.data() length:hash_value.size()];
147
148 AddPkpAndStartCronet(server_host_, matching_hash, kEXCLUDE_SUBDOMAINS,
149 distant_future);
150 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
151 }
152
153 // Tests the case when the pin hash does not match and the client accesses the
154 // subdomain of the configured PKP host with includeSubdomains flag set to true.
155 // The client is expected to receive the error response.
156 TEST_F(PkpTest, TestIncludeSubdomainsFlagEqualTrue) {
157 AddPkpAndStartCronet(domain_, NonMatchingHash(), kINCLUDE_SUBDOMAINS,
158 distant_future);
159 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
160 }
161
162 // Tests the case when the pin hash does not match and the client accesses the
163 // subdomain of the configured PKP host with includeSubdomains flag set to
164 // false. The client is expected to receive the successful response with the
165 // response code 200.
166 TEST_F(PkpTest, TestIncludeSubdomainsFlagEqualFalse) {
167 AddPkpAndStartCronet(domain_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
168 distant_future);
169 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
170 }
171
172 // Tests a mismatching pin that will expire in 10 seconds. The pins should be
173 // still valid and enforced during the request; thus returning the pin match
174 // error.
175 TEST_F(PkpTest, TestSoonExpiringPin) {
176 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
177 [NSDate dateWithTimeIntervalSinceNow:10]);
178 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
179 }
180
181 // Tests mismatching pin that expired 1 second ago. Since the pin has
182 // expired, it should not be enforced during the request; thus a successful
183 // response is expected.
184 TEST_F(PkpTest, TestRecentlyExpiredPin) {
185 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
186 [NSDate dateWithTimeIntervalSinceNow:-1]);
187 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
188 }
189
190 // Tests that host pinning is not persisted between multiple CronetEngine
191 // instances.
192 TEST_F(PkpTest, TestPinsAreNotPersisted) {
193 //
194 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
195 distant_future);
196 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
197 [Cronet shutdownForTesting];
198
199 // Restart Cronet engine and try the same request again. Since the pins are
200 // not persisted, a successful response is expected.
201 StartCronet(grpc_support::GetQuicTestServerPort());
202 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
203 }
204
205 } // namespace cronet
OLDNEW
« no previous file with comments | « components/cronet/ios/test/cronet_http_test.mm ('k') | components/cronet/ios/test/cronet_test_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698