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

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

Issue 2928653002: [Cronet-iOS] Public-Key-Pinning Tests (Closed)
Patch Set: Build fix on bot 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 cronet {
18
19 static const bool kINCLUDE_SUBDOMAINS = true;
20 static const bool kEXCLUDE_SUBDOMAINS = false;
21 static const std::string kSERVER_CERT = "quic_test.example.com.crt";
22 static NSDate* distant_future = [NSDate distantFuture];
23
24 // Tests public-key-pinning functionality.
25 class PkpTest : public CronetTestBase {
26 protected:
27 void SetUp() override {
28 CronetTestBase::SetUp();
29
30 NSString* full_url_str = [NSString
31 stringWithFormat:@"%@:%i",
32 [NSString
33 stringWithCString:grpc_support::kTestServerUrl
34 encoding:NSUTF8StringEncoding],
35 grpc_support::GetQuicTestServerPort()];
36 request_url_ = [NSURL URLWithString:full_url_str];
37 server_host_ = request_url_.host;
38 NSArray<NSString*>* components = [server_host_
39 componentsSeparatedByCharactersInSet:
40 [NSCharacterSet characterSetWithCharactersInString:@"."]];
41 domain_ =
42 [NSString stringWithFormat:@"%@.%@", components[components.count - 2],
43 components[components.count - 1]];
44
45 // Create a Cronet enabled NSURLSession
46 NSURLSessionConfiguration* sessionConfig =
47 [NSURLSessionConfiguration defaultSessionConfiguration];
48 [Cronet installIntoSessionConfiguration:sessionConfig];
49 url_session_ = [NSURLSession sessionWithConfiguration:sessionConfig
50 delegate:delegate_
51 delegateQueue:nil];
52
53 // Set mock cert verifier
54 [Cronet setMockCertVerifier:CreateMockCertVerifier({kSERVER_CERT}, YES)];
55 }
56
57 void TearDown() override {
58 [Cronet shutdownForTesting];
59 CronetTestBase::TearDown();
60 }
61
62 // Sends a request to a given URL, waits for the response and asserts that
63 // the response doesn't contain an error.
64 void sendRequestAndAssertSuccess(NSURL* url) {
65 sendRequestAndAssertResult(url, true);
66 }
67
68 // Sends a request to a given URL, waits for the response and asserts that
69 // the response contains an error.
70 void sendRequestAndAssertError(NSURL* url) {
71 sendRequestAndAssertResult(url, false);
72 }
73
74 // Sends a request to a given URL, waits for the response and asserts that
75 // the response is either successful or containing an error depending on
76 // the value of the passed |expected_success| parameter.
77 void sendRequestAndAssertResult(NSURL* url, bool expected_success) {
78 NSURLSessionDataTask* dataTask =
79 [url_session_ dataTaskWithURL:request_url_];
80 StartDataTaskAndWaitForCompletion(dataTask);
81 if (expected_success) {
82 ASSERT_TRUE(IsResponseSuccessful());
83 } else {
84 ASSERT_FALSE(IsResponseSuccessful());
85 }
86 }
87
88 // Adds a give public-key-pin and starts a Cronet engine for testing.
89 static void AddPkpAndStartCronet(NSString* host,
90 NSData* hash,
91 BOOL include_subdomains,
92 const NSDate* expiration_date) {
93 NSSet* hashes = [NSSet setWithObject:hash];
94 [Cronet addPublicKeyPinsForHost:host
95 pinHashes:hashes
96 includeSubdomains:include_subdomains
97 expirationDate:(NSDate*)expiration_date];
98 StartCronet(grpc_support::GetQuicTestServerPort());
99 }
100
101 // Returns an arbitrary public key hash that doesn't match with any test
102 // certificate.
103 static NSData* NonMatchingHash() {
104 const int length = 32;
105 u_char hash[length];
106 memset(hash, 77, length);
107 return [NSData dataWithBytes:hash length:length];
108 }
109
110 NSURLSession* url_session_;
111 NSURL* request_url_; // "https://test.example.com/hello.txt:62922"
112 NSString* server_host_; // test.example.com
113 NSString* domain_; // example.com
114
115 }; // class PkpTest
116
117 // Tests the case when a mismatching pin is set for some host that is
118 // different from the one the client wants to access. In that case the other
119 // host pinning policy should not be applied and the client is expected to
120 // receive the successful response with the response code 200.
121 TEST_F(PkpTest, TestSuccessIfPinSetForDifferentHost) {
122 AddPkpAndStartCronet(@"some-other-host.com", NonMatchingHash(),
123 kEXCLUDE_SUBDOMAINS, distant_future);
124 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
125 }
126
127 // Tests the case when the pin hash does not match. The client is expected to
128 // receive the error response.
129 TEST_F(PkpTest, TestErrorIfPinDoesNotMatch) {
130 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
131 distant_future);
132 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
133 }
134
135 // Tests the case when the pin hash matches. The client is expected to
136 // receive the successful response with the response code 200.
137 TEST_F(PkpTest, TestSuccessIfPinMatches) {
138 // Calculate hash of the server certificate
139 scoped_refptr<net::X509Certificate> cert =
140 net::ImportCertFromFile(net::GetTestCertsDirectory(), kSERVER_CERT);
141 net::HashValue hash_value;
142 CalculatePublicKeySha256(*cert, &hash_value);
143 ASSERT_EQ(32ul, hash_value.size());
144 NSData* matching_hash =
145 [NSData dataWithBytes:hash_value.data() length:hash_value.size()];
146
147 AddPkpAndStartCronet(server_host_, matching_hash, kEXCLUDE_SUBDOMAINS,
148 distant_future);
149 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
150 }
151
152 // Tests the case when the pin hash does not match and the client accesses the
153 // subdomain of the configured PKP host with includeSubdomains flag set to true.
154 // The client is expected to receive the error response.
155 TEST_F(PkpTest, TestIncludeSubdomainsFlagEqualTrue) {
156 AddPkpAndStartCronet(domain_, NonMatchingHash(), kINCLUDE_SUBDOMAINS,
157 distant_future);
158 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
159 }
160
161 // Tests the case when the pin hash does not match and the client accesses the
162 // subdomain of the configured PKP host with includeSubdomains flag set to
163 // false. The client is expected to receive the successful response with the
164 // response code 200.
165 TEST_F(PkpTest, TestIncludeSubdomainsFlagEqualFalse) {
166 AddPkpAndStartCronet(domain_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
167 distant_future);
168 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
169 }
170
171 // Tests a mismatching pin that will expire in 10 seconds. The pins should be
172 // still valid and enforced during the request; thus returning the pin match
173 // error.
174 TEST_F(PkpTest, TestSoonExpiringPin) {
175 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
176 [NSDate dateWithTimeIntervalSinceNow:10]);
177 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
178 }
179
180 // Tests mismatching pin that expired 1 second ago. Since the pin has
181 // expired, it should not be enforced during the request; thus a successful
182 // response is expected.
183 TEST_F(PkpTest, TestRecentlyExpiredPin) {
184 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
185 [NSDate dateWithTimeIntervalSinceNow:-1]);
186 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
187 }
188
189 // Tests that host pinning is not persisted between multiple CronetEngine
190 // instances.
191 TEST_F(PkpTest, TestPinsAreNotPersisted) {
192 //
193 AddPkpAndStartCronet(server_host_, NonMatchingHash(), kEXCLUDE_SUBDOMAINS,
194 distant_future);
195 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertError(request_url_));
196 [Cronet shutdownForTesting];
197
198 // Restart Cronet engine and try the same request again. Since the pins are
199 // not persisted, a successful response is expected.
200 StartCronet(grpc_support::GetQuicTestServerPort());
201 ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertSuccess(request_url_));
202 }
203
204 } // namespace cronet
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698