1 /* |
|
2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. |
|
8 * |
|
9 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
12 * version 2 for more details (a copy is included in the LICENSE file that |
|
13 * accompanied this code). |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License version |
|
16 * 2 along with this work; if not, write to the Free Software Foundation, |
|
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
18 * |
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
20 * or visit www.oracle.com if you need additional information or have any |
|
21 * questions. |
|
22 */ |
|
23 |
|
24 package sun.security.ssl; |
|
25 |
|
26 import java.io.IOException; |
|
27 import java.util.*; |
|
28 import java.nio.ByteBuffer; |
|
29 import javax.net.ssl.*; |
|
30 |
|
31 /* |
|
32 * Checks that the hash value for a certificate's issuer name is generated |
|
33 * correctly. Requires any certificate that is not self-signed. |
|
34 * |
|
35 * NOTE: this test uses Sun private classes which are subject to change. |
|
36 */ |
|
37 public class CertStatusReqListV2ExtensionTests { |
|
38 |
|
39 private static final boolean debug = false; |
|
40 |
|
41 // Default status_request_v2 extension with two items |
|
42 // 1. Type = ocsp_multi, OCSPStatusRequest is default |
|
43 // 2. Type = ocsp, OCSPStatusRequest is default |
|
44 private static final byte[] CSRLV2_DEF = { |
|
45 0, 14, 2, 0, 4, 0, 0, 0, |
|
46 0, 1, 0, 4, 0, 0, 0, 0 |
|
47 }; |
|
48 |
|
49 // A status_request_v2 where the item list length is |
|
50 // longer than the provided data |
|
51 private static final byte[] CSRLV2_LEN_TOO_LONG = { |
|
52 0, 18, 2, 0, 4, 0, 0, 0, |
|
53 0, 1, 0, 4, 0, 0, 0, 0 |
|
54 }; |
|
55 |
|
56 // A status_request_v2 where the item list length is |
|
57 // shorter than the provided data |
|
58 private static final byte[] CSRLV2_LEN_TOO_SHORT = { |
|
59 0, 11, 2, 0, 4, 0, 0, 0, |
|
60 0, 1, 0, 4, 0, 0, 0, 0 |
|
61 }; |
|
62 |
|
63 // A status_request_v2 extension with a zero-length |
|
64 // certificate_status_req_list (not allowed by the spec) |
|
65 private static final byte[] CSRLV2_INVALID_ZEROLEN = {0, 0}; |
|
66 |
|
67 // A status_request_v2 extension with two items (ocsp_multi and ocsp) |
|
68 // using OCSPStatusRequests with 5 ResponderIds and 1 Extension each. |
|
69 private static final byte[] CSRLV2_TWO_NON_DEF_ITEMS = { |
|
70 2, 90, 2, 1, 42, 0, -13, 0, |
|
71 59, -95, 57, 48, 55, 49, 16, 48, |
|
72 14, 6, 3, 85, 4, 10, 19, 7, |
|
73 83, 111, 109, 101, 73, 110, 99, 49, |
|
74 16, 48, 14, 6, 3, 85, 4, 11, |
|
75 19, 7, 83, 111, 109, 101, 80, 75, |
|
76 73, 49, 17, 48, 15, 6, 3, 85, |
|
77 4, 3, 19, 8, 83, 111, 109, 101, |
|
78 79, 67, 83, 80, 0, 68, -95, 66, |
|
79 48, 64, 49, 13, 48, 11, 6, 3, |
|
80 85, 4, 10, 19, 4, 79, 104, 77, |
|
81 121, 49, 14, 48, 12, 6, 3, 85, |
|
82 4, 11, 19, 5, 66, 101, 97, 114, |
|
83 115, 49, 15, 48, 13, 6, 3, 85, |
|
84 4, 11, 19, 6, 84, 105, 103, 101, |
|
85 114, 115, 49, 14, 48, 12, 6, 3, |
|
86 85, 4, 3, 19, 5, 76, 105, 111, |
|
87 110, 115, 0, 58, -95, 56, 48, 54, |
|
88 49, 16, 48, 14, 6, 3, 85, 4, |
|
89 10, 19, 7, 67, 111, 109, 112, 97, |
|
90 110, 121, 49, 13, 48, 11, 6, 3, |
|
91 85, 4, 11, 19, 4, 87, 101, 115, |
|
92 116, 49, 19, 48, 17, 6, 3, 85, |
|
93 4, 3, 19, 10, 82, 101, 115, 112, |
|
94 111, 110, 100, 101, 114, 49, 0, 24, |
|
95 -94, 22, 4, 20, -67, -36, 114, 121, |
|
96 92, -79, 116, -1, 102, -107, 7, -21, |
|
97 18, -113, 64, 76, 96, -7, -66, -63, |
|
98 0, 24, -94, 22, 4, 20, -51, -69, |
|
99 107, -82, -39, -87, 45, 25, 41, 28, |
|
100 -76, -68, -11, -110, -94, -97, 62, 47, |
|
101 58, -125, 0, 51, 48, 49, 48, 47, |
|
102 6, 9, 43, 6, 1, 5, 5, 7, |
|
103 48, 1, 2, 4, 34, 4, 32, -26, |
|
104 -81, -120, -61, -127, -79, 0, -39, -54, |
|
105 49, 3, -51, -57, -85, 19, -126, 94, |
|
106 -2, 21, 26, 98, 6, 105, -35, -37, |
|
107 -29, -73, 101, 53, 44, 15, -19, 1, |
|
108 1, 42, 0, -13, 0, 59, -95, 57, |
|
109 48, 55, 49, 16, 48, 14, 6, 3, |
|
110 85, 4, 10, 19, 7, 83, 111, 109, |
|
111 101, 73, 110, 99, 49, 16, 48, 14, |
|
112 6, 3, 85, 4, 11, 19, 7, 83, |
|
113 111, 109, 101, 80, 75, 73, 49, 17, |
|
114 48, 15, 6, 3, 85, 4, 3, 19, |
|
115 8, 83, 111, 109, 101, 79, 67, 83, |
|
116 80, 0, 68, -95, 66, 48, 64, 49, |
|
117 13, 48, 11, 6, 3, 85, 4, 10, |
|
118 19, 4, 79, 104, 77, 121, 49, 14, |
|
119 48, 12, 6, 3, 85, 4, 11, 19, |
|
120 5, 66, 101, 97, 114, 115, 49, 15, |
|
121 48, 13, 6, 3, 85, 4, 11, 19, |
|
122 6, 84, 105, 103, 101, 114, 115, 49, |
|
123 14, 48, 12, 6, 3, 85, 4, 3, |
|
124 19, 5, 76, 105, 111, 110, 115, 0, |
|
125 58, -95, 56, 48, 54, 49, 16, 48, |
|
126 14, 6, 3, 85, 4, 10, 19, 7, |
|
127 67, 111, 109, 112, 97, 110, 121, 49, |
|
128 13, 48, 11, 6, 3, 85, 4, 11, |
|
129 19, 4, 87, 101, 115, 116, 49, 19, |
|
130 48, 17, 6, 3, 85, 4, 3, 19, |
|
131 10, 82, 101, 115, 112, 111, 110, 100, |
|
132 101, 114, 49, 0, 24, -94, 22, 4, |
|
133 20, -67, -36, 114, 121, 92, -79, 116, |
|
134 -1, 102, -107, 7, -21, 18, -113, 64, |
|
135 76, 96, -7, -66, -63, 0, 24, -94, |
|
136 22, 4, 20, -51, -69, 107, -82, -39, |
|
137 -87, 45, 25, 41, 28, -76, -68, -11, |
|
138 -110, -94, -97, 62, 47, 58, -125, 0, |
|
139 51, 48, 49, 48, 47, 6, 9, 43, |
|
140 6, 1, 5, 5, 7, 48, 1, 2, |
|
141 4, 34, 4, 32, -26, -81, -120, -61, |
|
142 -127, -79, 0, -39, -54, 49, 3, -51, |
|
143 -57, -85, 19, -126, 94, -2, 21, 26, |
|
144 98, 6, 105, -35, -37, -29, -73, 101, |
|
145 53, 44, 15, -19 |
|
146 }; |
|
147 |
|
148 public static void main(String[] args) throws Exception { |
|
149 Map<String, TestCase> testList = |
|
150 new LinkedHashMap<String, TestCase>() {{ |
|
151 put("CTOR (default)", testCtorDefault); |
|
152 put("CTOR (List<CertStatusReqItemV2)", testCtorItemList); |
|
153 put("CTOR (HandshakeInStream, getRequestList", |
|
154 testCtorInStream); |
|
155 }}; |
|
156 |
|
157 TestUtils.runTests(testList); |
|
158 } |
|
159 |
|
160 public static final TestCase testCtorDefault = new TestCase() { |
|
161 @Override |
|
162 public Map.Entry<Boolean, String> runTest() { |
|
163 Boolean pass = Boolean.FALSE; |
|
164 String message = null; |
|
165 try { |
|
166 CertStatusReqListV2Extension csrlV2 = |
|
167 new CertStatusReqListV2Extension(); |
|
168 HandshakeOutStream hsout = new HandshakeOutStream(null); |
|
169 csrlV2.send(hsout); |
|
170 TestUtils.valueCheck(wrapExtData(new byte[0]), |
|
171 hsout.toByteArray()); |
|
172 |
|
173 // The length should be 4 (2 bytes for the type, 2 for the |
|
174 // encoding of zero-length |
|
175 if (csrlV2.length() != 4) { |
|
176 throw new RuntimeException("Incorrect length from " + |
|
177 "default object. Expected 4, got " + |
|
178 csrlV2.length()); |
|
179 } |
|
180 |
|
181 // Since there's no data, there are no status_type or request |
|
182 // data fields defined. An empty, unmodifiable list should be |
|
183 // returned when obtained from the extension. |
|
184 List<CertStatusReqItemV2> itemList = csrlV2.getRequestItems(); |
|
185 if (!itemList.isEmpty()) { |
|
186 throw new RuntimeException("Default CSRLV2 returned " + |
|
187 "non-empty request list"); |
|
188 } else { |
|
189 try { |
|
190 itemList.add(new CertStatusReqItemV2( |
|
191 StatusRequestType.OCSP_MULTI, |
|
192 new OCSPStatusRequest())); |
|
193 throw new RuntimeException("Returned itemList is " + |
|
194 "modifiable!"); |
|
195 } catch (UnsupportedOperationException uoe) { } |
|
196 } |
|
197 |
|
198 pass = Boolean.TRUE; |
|
199 } catch (Exception e) { |
|
200 e.printStackTrace(System.out); |
|
201 message = e.getClass().getName(); |
|
202 } |
|
203 |
|
204 return new AbstractMap.SimpleEntry<>(pass, message); |
|
205 } |
|
206 }; |
|
207 |
|
208 public static final TestCase testCtorItemList = new TestCase() { |
|
209 @Override |
|
210 public Map.Entry<Boolean, String> runTest() { |
|
211 Boolean pass = Boolean.FALSE; |
|
212 String message = null; |
|
213 OCSPStatusRequest osr = new OCSPStatusRequest(); |
|
214 List<CertStatusReqItemV2> noItems = Collections.emptyList(); |
|
215 List<CertStatusReqItemV2> defList = |
|
216 new ArrayList<CertStatusReqItemV2>() {{ |
|
217 add(new CertStatusReqItemV2(StatusRequestType.OCSP_MULTI, osr)); |
|
218 add(new CertStatusReqItemV2(StatusRequestType.OCSP, osr)); |
|
219 }}; |
|
220 List<CertStatusReqItemV2> unknownTypesList = |
|
221 new ArrayList<CertStatusReqItemV2>() {{ |
|
222 add(new CertStatusReqItemV2(StatusRequestType.get(8), |
|
223 new UnknownStatusRequest(new byte[0]))); |
|
224 add(new CertStatusReqItemV2(StatusRequestType.get(12), |
|
225 new UnknownStatusRequest(new byte[5]))); |
|
226 }}; |
|
227 |
|
228 try { |
|
229 HandshakeOutStream hsout = new HandshakeOutStream(null); |
|
230 StatusRequest basicStatReq = new OCSPStatusRequest(); |
|
231 |
|
232 // Create an extension using a default-style OCSPStatusRequest |
|
233 // (no responder IDs, no extensions). |
|
234 CertStatusReqListV2Extension csrlv2 = |
|
235 new CertStatusReqListV2Extension(defList); |
|
236 csrlv2.send(hsout); |
|
237 TestUtils.valueCheck(wrapExtData(CSRLV2_DEF), |
|
238 hsout.toByteArray()); |
|
239 hsout.reset(); |
|
240 |
|
241 // Create the extension using a StatusRequestType not already |
|
242 // instantiated as a static StatusRequestType |
|
243 // (e.g. OCSP/OCSP_MULTI) |
|
244 csrlv2 = new CertStatusReqListV2Extension(unknownTypesList); |
|
245 List<CertStatusReqItemV2> itemList = csrlv2.getRequestItems(); |
|
246 if (itemList.size() != unknownTypesList.size()) { |
|
247 throw new RuntimeException("Custom CSRLV2 returned " + |
|
248 "an incorrect number of items: expected " + |
|
249 unknownTypesList.size() + ", got " + |
|
250 itemList.size()); |
|
251 } else { |
|
252 // Verify that the list is unmodifiable |
|
253 try { |
|
254 itemList.add(new CertStatusReqItemV2( |
|
255 StatusRequestType.OCSP_MULTI, |
|
256 new OCSPStatusRequest())); |
|
257 throw new RuntimeException("Returned itemList is " + |
|
258 "modifiable!"); |
|
259 } catch (UnsupportedOperationException uoe) { } |
|
260 } |
|
261 |
|
262 // Pass a null value for the item list. This should throw |
|
263 // an exception |
|
264 try { |
|
265 CertStatusReqListV2Extension csrlv2Null = |
|
266 new CertStatusReqListV2Extension(null); |
|
267 throw new RuntimeException("Constructor accepted a " + |
|
268 "null request list"); |
|
269 } catch (NullPointerException npe) { } |
|
270 |
|
271 pass = Boolean.TRUE; |
|
272 } catch (Exception e) { |
|
273 e.printStackTrace(System.out); |
|
274 message = e.getClass().getName(); |
|
275 } |
|
276 |
|
277 return new AbstractMap.SimpleEntry<>(pass, message); |
|
278 } |
|
279 }; |
|
280 |
|
281 // Test the constructor that builds the ob ject using data from |
|
282 // a HandshakeInStream |
|
283 // This also tests the length, getReqType and getRequest methods |
|
284 public static final TestCase testCtorInStream = new TestCase() { |
|
285 @Override |
|
286 public Map.Entry<Boolean, String> runTest() { |
|
287 Boolean pass = Boolean.FALSE; |
|
288 String message = null; |
|
289 OCSPStatusRequest osr; |
|
290 CertStatusReqListV2Extension csrlv2; |
|
291 |
|
292 try { |
|
293 // To simulate the extension coming in a ServerHello, the |
|
294 // type and length would already be read by HelloExtensions |
|
295 // and there is no extension data |
|
296 HandshakeInStream hsis = new HandshakeInStream(); |
|
297 hsis.incomingRecord(ByteBuffer.wrap(new byte[0])); |
|
298 csrlv2 = new CertStatusReqListV2Extension(hsis, |
|
299 hsis.available()); |
|
300 |
|
301 // Verify length/request list |
|
302 if (csrlv2.length() != 4) { |
|
303 throw new RuntimeException("Invalid length: received " + |
|
304 csrlv2.length() + ", expected 4"); |
|
305 } else { |
|
306 List<CertStatusReqItemV2> itemList = |
|
307 csrlv2.getRequestItems(); |
|
308 if (!itemList.isEmpty()) { |
|
309 throw new RuntimeException("Default CSRLV2 returned " + |
|
310 "non-empty request list"); |
|
311 } else { |
|
312 try { |
|
313 itemList.add(new CertStatusReqItemV2( |
|
314 StatusRequestType.OCSP_MULTI, |
|
315 new OCSPStatusRequest())); |
|
316 throw new RuntimeException("Returned itemList is " + |
|
317 "modifiable!"); |
|
318 } catch (UnsupportedOperationException uoe) { } |
|
319 } |
|
320 } |
|
321 |
|
322 // Try the an extension with our basic client-generated |
|
323 // status_request_v2 (2 items, ocsp_multi and ocsp, each with |
|
324 // a default OCSPStatusRequest |
|
325 hsis = new HandshakeInStream(); |
|
326 hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_DEF)); |
|
327 csrlv2 = new CertStatusReqListV2Extension(hsis, |
|
328 hsis.available()); |
|
329 if (csrlv2.length() != (CSRLV2_DEF.length + 4)) { |
|
330 throw new RuntimeException("Invalid length: received " + |
|
331 csrlv2.length() + ", expected " + |
|
332 CSRLV2_DEF.length + 4); |
|
333 } else { |
|
334 List<CertStatusReqItemV2> itemList = |
|
335 csrlv2.getRequestItems(); |
|
336 if (itemList.size() != 2) { |
|
337 throw new RuntimeException("Unexpected number of " + |
|
338 "items request list, expected 2, got " + |
|
339 itemList.size()); |
|
340 } else { |
|
341 try { |
|
342 itemList.add(new CertStatusReqItemV2( |
|
343 StatusRequestType.OCSP_MULTI, |
|
344 new OCSPStatusRequest())); |
|
345 throw new RuntimeException("Returned itemList is " + |
|
346 "modifiable!"); |
|
347 } catch (UnsupportedOperationException uoe) { } |
|
348 } |
|
349 } |
|
350 |
|
351 // Try incoming data with an illegal zero-length |
|
352 // certificate_status_req_list |
|
353 try { |
|
354 hsis = new HandshakeInStream(); |
|
355 hsis.incomingRecord( |
|
356 ByteBuffer.wrap(CSRLV2_INVALID_ZEROLEN)); |
|
357 csrlv2 = new CertStatusReqListV2Extension(hsis, |
|
358 hsis.available()); |
|
359 throw new RuntimeException("Unxpected successful " + |
|
360 "object construction"); |
|
361 } catch (SSLException ssle) { } |
|
362 |
|
363 // Try extensions where the certificate_status_req_list length |
|
364 // is either too long or too short |
|
365 try { |
|
366 hsis = new HandshakeInStream(); |
|
367 hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_LEN_TOO_LONG)); |
|
368 csrlv2 = new CertStatusReqListV2Extension(hsis, |
|
369 hsis.available()); |
|
370 throw new RuntimeException("Unxpected successful " + |
|
371 "object construction"); |
|
372 } catch (SSLException ssle) { } |
|
373 |
|
374 try { |
|
375 hsis = new HandshakeInStream(); |
|
376 hsis.incomingRecord(ByteBuffer.wrap(CSRLV2_LEN_TOO_SHORT)); |
|
377 csrlv2 = new CertStatusReqListV2Extension(hsis, |
|
378 hsis.available()); |
|
379 throw new RuntimeException("Unxpected successful " + |
|
380 "object construction"); |
|
381 } catch (SSLException ssle) { } |
|
382 |
|
383 pass = Boolean.TRUE; |
|
384 } catch (Exception e) { |
|
385 e.printStackTrace(System.out); |
|
386 message = e.getClass().getName(); |
|
387 } |
|
388 |
|
389 return new AbstractMap.SimpleEntry<>(pass, message); |
|
390 } |
|
391 }; |
|
392 |
|
393 // Take CSRE extension data and add extension type and length decorations |
|
394 private static byte[] wrapExtData(byte[] extData) { |
|
395 int bufferLen = extData.length + 4; |
|
396 ByteBuffer bb = ByteBuffer.allocate(bufferLen); |
|
397 |
|
398 bb.putShort((short)ExtensionType.EXT_STATUS_REQUEST_V2.id); |
|
399 bb.putShort((short)extData.length); |
|
400 if (extData.length != 0) { |
|
401 bb.put(extData); |
|
402 } |
|
403 return bb.array(); |
|
404 } |
|
405 } |
|