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

Side by Side Diff: components/cronet/android/test/javatests/src/org/chromium/net/HpkpTest.java

Issue 1407263010: [Cronet] Public key pinning for Java API (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Refactored X509UtilTest to avoid code duplication Created 5 years, 1 month 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 2015 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 package org.chromium.net;
6
7 import android.test.suitebuilder.annotation.SmallTest;
8
9 import org.chromium.base.test.util.Feature;
10 import org.chromium.net.test.util.CertTestUtil;
11
12 import java.io.ByteArrayInputStream;
13 import java.security.cert.CertificateFactory;
14 import java.security.cert.X509Certificate;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collection;
18
19 /**
20 * Public-Key-Pinning tests of Cronet Java API.
xunjieli 2015/11/06 15:47:54 Should we say **dynamic** public key pinning here?
kapishnikov 2015/11/06 16:18:13 I would like to clarify the terminology here. I wa
xunjieli 2015/11/06 16:43:50 I got the impression that we do not want to do sta
davidben 2015/11/06 16:53:13 "static" vs "dynamic" is whatever we want to call
21 */
22 public class HpkpTest extends CronetTestBase {
23 private static final String CERT_USED = "quic_test.example.com.crt";
24 private static final String[] CERTS_USED = {CERT_USED};
25
26 private CronetTestFramework mTestFramework;
27 private CronetEngine.Builder mBuilder;
28 private TestUrlRequestCallback mListener;
29 private String mServerUrl; // https://test.example.com:6121
30 private String mServerHost; // test.example.com
31 private String mDomain; // example.com
32
33 @Override
34 protected void setUp() throws Exception {
35 super.setUp();
36 // Start QUIC Test Server
37 System.loadLibrary("cronet_tests");
38 QuicTestServer.startQuicTestServer(getContext());
39 mServerUrl = QuicTestServer.getServerURL();
40 mServerHost = QuicTestServer.getServerHost();
41 mDomain = mServerHost.substring(mServerHost.indexOf('.') + 1, mServerHos t.length());
42
43 // Set common CronetEngine parameters
44 mBuilder = new CronetEngine.Builder(getContext());
45 mBuilder.enableQUIC(true);
46 mBuilder.addQuicHint(QuicTestServer.getServerHost(), QuicTestServer.getS erverPort(),
47 QuicTestServer.getServerPort());
48 mBuilder.setStoragePath(CronetTestFramework.getTestStorage(getContext()) );
49 mBuilder.enableHttpCache(CronetEngine.Builder.HTTP_CACHE_DISK_NO_HTTP, 1 000 * 1024);
50 mBuilder.setMockCertVerifierForTesting(MockCertVerifier.createMockCertVe rifier(CERTS_USED));
51 }
52
53 @Override
54 protected void tearDown() throws Exception {
55 QuicTestServer.shutdownQuicTestServer();
56 super.tearDown();
57 }
58
59 /**
60 * Tests the case when the pin hash does not match. The client is expected t o
61 * receive the error response.
62 *
63 * @throws Exception
64 */
65 @SmallTest
66 @Feature({"Cronet"})
67 public void testErrorCodeIfPinDoesNotMatch() throws Exception {
68 byte[] nonMatchingHash = generateSomeSha256();
69 addPkpSha256(mServerHost, nonMatchingHash, false);
70 startCronetFramework();
71 registerHostResolver();
72 sendRequestAndWaitForResult();
73
74 assertErrorResponse();
75 }
76
77 /**
78 * Tests the case when the pin hash matches. The client is expected to
79 * receive the successful response with the response code 200.
80 *
81 * @throws Exception
82 */
83 @SmallTest
84 @Feature({"Cronet"})
85 public void testSuccessIfPinMatches() throws Exception {
86 // Get PKP hash of the real certificate
87 X509Certificate cert = readCertFromFileInPemFormat(CERT_USED);
88 byte[] matchingHash = CertTestUtil.getPublicKeySha256(cert);
89
90 addPkpSha256(mServerHost, matchingHash, false);
91 startCronetFramework();
92 registerHostResolver();
93 sendRequestAndWaitForResult();
94
95 assertSuccessfulResponse();
96 }
97
98 /**
99 * Tests the case when the pin hash does not match and the client accesses t he subdomain of
100 * the configured HPKP host with includeSubdomains flag set to true. The cli ent is
101 * expected to receive the error response.
102 *
103 * @throws Exception
104 */
105 @SmallTest
106 @Feature({"Cronet"})
107 public void testIncludeSubdomainsFlagEqualTrue() throws Exception {
108 addPkpSha256(mDomain, generateSomeSha256(), true);
109 startCronetFramework();
110 registerHostResolver();
111 sendRequestAndWaitForResult();
112
113 assertErrorResponse();
114 }
115
116 /**
117 * Tests the case when the pin hash does not match and the client accesses t he subdomain of
118 * the configured HPKP host with includeSubdomains flag set to false. The cl ient is expected to
119 * receive the successful response with the response code 200.
120 *
121 * @throws Exception
122 */
123 @SmallTest
124 @Feature({"Cronet"})
125 public void testIncludeSubdomainsFlagEqualFalse() throws Exception {
126 addPkpSha256(mDomain, generateSomeSha256(), false);
127 startCronetFramework();
128 registerHostResolver();
129 sendRequestAndWaitForResult();
130
131 assertSuccessfulResponse();
132 }
133
134 /**
135 * Tests the case when the mismatching pin is set for some host that is diff erent from the one
136 * the client wants to access. In that case the other host pinning policy sh ould not be applied
137 * and the client is expected to receive the successful response with the re sponse code 200.
138 *
139 * @throws Exception
140 */
141 @SmallTest
142 @Feature({"Cronet"})
143 public void testSuccessIfNoPinSpecified() throws Exception {
144 addPkpSha256("somerandomhost.com", generateSomeSha256(), true);
145 startCronetFramework();
146 registerHostResolver();
147 sendRequestAndWaitForResult();
148
149 assertSuccessfulResponse();
150 }
151
152 /**
153 * Asserts that the response from the server contains an HPKP error.
154 * TODO(kapishnikov) currently QUIC returns ERR_QUIC_PROTOCOL_ERROR instead of expected
xunjieli 2015/11/06 15:47:54 nit: Probably only one TODO is needed. There shoul
kapishnikov 2015/11/06 16:18:13 Done.
155 * TODO(kapishnikov) ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN error code when th e pin doesn't match.
156 * TODO(kapishnikov) This method should be changed when the bug is resolved.
157 * TODO(kapishnikov) See http://crbug.com/548378
158 */
159 private void assertErrorResponse() {
160 assertNotNull("Expected an error", mListener.mError);
161 int errorCode = mListener.mError.netError();
162 boolean correctErrorCode = errorCode == NetError.ERR_SSL_PINNED_KEY_NOT_ IN_CERT_CHAIN
163 || errorCode == NetError.ERR_QUIC_PROTOCOL_ERROR;
164 assertTrue(String.format("Incorrect error code. Expected %s or %s but re ceived %s",
165 NetError.ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN,
166 NetError.ERR_QUIC_PROTOCOL_ERROR, errorCode),
167 correctErrorCode);
168 }
169
170 /**
171 * Asserts a successful response with response code 200.
172 */
173 private void assertSuccessfulResponse() {
174 if (mListener.mError != null) {
175 fail("Did not expect an error but got error code " + mListener.mErro r.mNetError);
176 }
177 assertNotNull("Expected non-null response from the server", mListener.mR esponseInfo);
178 assertEquals(200, mListener.mResponseInfo.getHttpStatusCode());
179 }
180
181 private void startCronetFramework() {
182 mTestFramework = startCronetTestFrameworkWithUrlAndCronetEngineBuilder(n ull, mBuilder);
183 }
184
185 private void registerHostResolver() {
186 long urlRequestContextAdapter = ((CronetUrlRequestContext) mTestFramewor k.mCronetEngine)
187 .getUrlRequestContextAdapter();
188 NativeTestServer.registerHostResolverProc(urlRequestContextAdapter, fals e);
189 }
190
191 private byte[] generateSomeSha256() {
192 byte[] sha256 = new byte[32];
193 Arrays.fill(sha256, (byte) 58);
194 return sha256;
195 }
196
197 private void addPkpSha256(String host, byte[] pinHashValue, boolean includeS ubdomain) {
198 Collection<byte[]> hashes = new ArrayList<>();
199 hashes.add(pinHashValue);
200 mBuilder.addPublicKeyPins(host, hashes, includeSubdomain);
201 }
202
203 private void sendRequestAndWaitForResult() {
204 mListener = new TestUrlRequestCallback();
205
206 String quicURL = mServerUrl + "/simple.txt";
207 UrlRequest.Builder requestBuilder = new UrlRequest.Builder(
208 quicURL, mListener, mListener.getExecutor(), mTestFramework.mCro netEngine);
209 requestBuilder.build().start();
210 mListener.blockForDone();
211 }
212
213 private X509Certificate readCertFromFileInPemFormat(String certFileName) thr ows Exception {
214 byte[] certDer = CertTestUtil.pemToDer(CertTestUtil.CERTS_DIRECTORY + ce rtFileName);
215 CertificateFactory certFactory = CertificateFactory.getInstance("X.509") ;
216 return (X509Certificate) certFactory.generateCertificate(new ByteArrayIn putStream(certDer));
217 }
218 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698