Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/javax/net/ssl/TLSv13/HRRKeyShares.java
41152 views
1
/*
2
* Copyright (c) 2020, 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
// SunJSSE does not support dynamic system properties, no way to re-use
25
// system properties in samevm/agentvm mode. For further debugging output
26
// set the -Djavax.net.debug=ssl:handshake property on the @run lines.
27
28
/*
29
* @test
30
* @bug 8247630
31
* @summary Use two key share entries
32
* @library /test/lib
33
* @run main/othervm -Djdk.tls.namedGroups=x25519,secp256r1,secp384r1 HRRKeyShares
34
*/
35
36
import java.io.ByteArrayOutputStream;
37
import java.io.DataOutputStream;
38
import java.io.IOException;
39
import javax.net.ssl.*;
40
import javax.net.ssl.SSLEngineResult.*;
41
import java.nio.ByteBuffer;
42
import java.util.ArrayList;
43
import java.util.LinkedHashMap;
44
import java.util.List;
45
import java.util.Map;
46
import java.util.Objects;
47
import jdk.test.lib.Utils;
48
49
50
public class HRRKeyShares {
51
52
// Some TLS constants we'll use for testing
53
private static final int TLS_REC_HANDSHAKE = 22;
54
private static final int TLS_REC_ALERT = 21;
55
private static final int HS_MSG_CLIHELLO = 1;
56
private static final int HS_MSG_SERVHELLO = 2; // Also for HRR
57
private static final int HELLO_EXT_SUPP_GROUPS = 10;
58
private static final int HELLO_EXT_SUPP_VERS = 43;
59
private static final int HELLO_EXT_KEY_SHARE = 51;
60
private static final int TLS_LEGACY_VER = 0x0303; // TLSv1.2
61
private static final int TLS_PROT_VER_13 = 0x0304; // TLSv1.3
62
private static final int NG_SECP256R1 = 0x0017;
63
private static final int NG_SECP384R1 = 0x0018;
64
private static final int NG_X25519 = 0x001D;
65
private static final int NG_X448 = 0x001E;
66
private static final int NG_GC512A = 0x0026;
67
private static final int COMP_NONE = 0;
68
private static final int ALERT_TYPE_FATAL = 2;
69
private static final int ALERT_DESC_ILLEGAL_PARAM = 47;
70
private static final byte[] HRR_RANDOM = Utils.toByteArray(
71
"CF21AD74E59A6111BE1D8C021E65B891" +
72
"C2A211167ABB8C5E079E09E2C8A8339C");
73
74
static class ClientHello {
75
// TLS Record header fields
76
final int recType;
77
final int recVers;
78
final int recLength;
79
80
// Handshake header fields
81
final int hsMsgType;
82
final int hsMsgLength;
83
84
// ClientHello fields
85
final int version;
86
final byte[] random;
87
final byte[] sessId;
88
final List<Integer> cipherSuites = new ArrayList<>();
89
final List<Integer> compressionList = new ArrayList<>();
90
final Map<Integer,byte[]> extensionMap = new LinkedHashMap<>();
91
92
// These are fields built from specific extension data fields we
93
// are interested in for our tests
94
final List<Integer> suppGroups = new ArrayList<>();
95
final Map<Integer,byte[]> keyShares = new LinkedHashMap<>();
96
final List<Integer> suppVersions = new ArrayList<>();
97
98
ClientHello(ByteBuffer data) {
99
Objects.requireNonNull(data);
100
data.mark();
101
102
// Process the TLS record header
103
recType = Byte.toUnsignedInt(data.get());
104
recVers = Short.toUnsignedInt(data.getShort());
105
recLength = Short.toUnsignedInt(data.getShort());
106
if (recType != TLS_REC_HANDSHAKE) {
107
throw new RuntimeException("Not a Handshake TLS record. " +
108
"Type = " + recType);
109
}
110
111
// Process the Handshake message header
112
int recHdr = data.getInt();
113
hsMsgType = recHdr >>> 24;
114
hsMsgLength = recHdr & 0x00FFFFFF;
115
if (hsMsgType != HS_MSG_CLIHELLO) {
116
throw new RuntimeException("Not a ClientHello message. " +
117
"Type = " + hsMsgType);
118
} else if (hsMsgLength > data.remaining()) {
119
throw new RuntimeException("Incomplete record in buffer: " +
120
"Record length = " + hsMsgLength + ", Remaining = " +
121
data.remaining());
122
}
123
124
version = Short.toUnsignedInt(data.getShort());
125
random = new byte[32];
126
data.get(random);
127
sessId = new byte[Byte.toUnsignedInt(data.get())];
128
data.get(sessId);
129
130
int suiteLen = Short.toUnsignedInt(data.getShort());
131
while (suiteLen > 0) {
132
cipherSuites.add(Short.toUnsignedInt(data.getShort()));
133
suiteLen -= 2;
134
}
135
136
int compLen = Byte.toUnsignedInt(data.get());
137
while (compLen > 0) {
138
compressionList.add(Byte.toUnsignedInt(data.get()));
139
compLen--;
140
}
141
142
// Extension processing time!
143
int extListLen = Short.toUnsignedInt(data.getShort());
144
while (extListLen > 0) {
145
int extType = Short.toUnsignedInt(data.getShort());
146
int extLen = Short.toUnsignedInt(data.getShort());
147
byte[] extData = new byte[extLen];
148
data.get(extData);
149
extensionMap.put(extType, extData);
150
switch (extType) {
151
case HELLO_EXT_SUPP_GROUPS:
152
ByteBuffer sgBuf = ByteBuffer.wrap(extData);
153
int supGrpLen = Short.toUnsignedInt(sgBuf.getShort());
154
for (int remain = supGrpLen; remain > 0; remain -= 2) {
155
suppGroups.add(Short.toUnsignedInt(
156
sgBuf.getShort()));
157
}
158
break;
159
case HELLO_EXT_SUPP_VERS:
160
ByteBuffer svBuf = ByteBuffer.wrap(extData);
161
int supVerLen = Byte.toUnsignedInt(svBuf.get());
162
for (int remain = supVerLen; remain > 0; remain -= 2) {
163
suppVersions.add(Short.toUnsignedInt(
164
svBuf.getShort()));
165
}
166
break;
167
case HELLO_EXT_KEY_SHARE:
168
ByteBuffer ksBuf = ByteBuffer.wrap(extData);
169
int ksListLen = Short.toUnsignedInt(ksBuf.getShort());
170
while (ksListLen > 0) {
171
int namedGroup = Short.toUnsignedInt(
172
ksBuf.getShort());
173
int ksLen = Short.toUnsignedInt(ksBuf.getShort());
174
byte[] ksData = new byte[ksLen];
175
ksBuf.get(ksData);
176
keyShares.put(namedGroup, ksData);
177
ksListLen -= (4 + ksLen);
178
}
179
break;
180
}
181
extListLen -= (4 + extLen);
182
}
183
}
184
}
185
186
static class Alert {
187
final int recType;
188
final int recVers;
189
final int recLength;
190
final int alertType;
191
final int alertDesc;
192
193
Alert(ByteBuffer data) {
194
Objects.requireNonNull(data);
195
data.mark();
196
197
// Process the TLS record header
198
recType = Byte.toUnsignedInt(data.get());
199
recVers = Short.toUnsignedInt(data.getShort());
200
recLength = Short.toUnsignedInt(data.getShort());
201
if (recType != TLS_REC_ALERT) {
202
throw new RuntimeException("Not a Handshake TLS record. " +
203
"Type = " + recType);
204
}
205
206
alertType = Byte.toUnsignedInt(data.get());
207
alertDesc = Byte.toUnsignedInt(data.get());
208
}
209
}
210
211
public static void main(String args[]) throws Exception {
212
System.out.println("Test 1: Good HRR exchange using secp384r1");
213
hrrKeyShareTest(NG_SECP384R1, true);
214
System.out.println();
215
216
System.out.println("Test 2: Bad HRR exchange using secp256r1");
217
hrrKeyShareTest(NG_SECP256R1, false);
218
System.out.println();
219
220
System.out.println("Test 3: Bad HRR using unknown GC512A");
221
hrrKeyShareTest(NG_GC512A, false);
222
System.out.println();
223
224
System.out.println("Test 4: Bad HRR using known / unasserted x448");
225
hrrKeyShareTest(NG_X448, false);
226
System.out.println();
227
}
228
229
private static void logResult(String str, SSLEngineResult result) {
230
HandshakeStatus hsStatus = result.getHandshakeStatus();
231
System.out.println(str +
232
result.getStatus() + "/" + hsStatus + ", " +
233
result.bytesConsumed() + "/" + result.bytesProduced() +
234
" bytes");
235
if (hsStatus == HandshakeStatus.FINISHED) {
236
System.out.println("\t...ready for application data");
237
}
238
}
239
240
/*
241
* If the result indicates that we have outstanding tasks to do,
242
* go ahead and run them in this thread.
243
*/
244
private static void runDelegatedTasks(SSLEngine engine) throws Exception {
245
if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
246
Runnable runnable;
247
while ((runnable = engine.getDelegatedTask()) != null) {
248
System.out.println(" running delegated task...");
249
runnable.run();
250
}
251
HandshakeStatus hsStatus = engine.getHandshakeStatus();
252
if (hsStatus == HandshakeStatus.NEED_TASK) {
253
throw new Exception(
254
"handshake shouldn't need additional tasks");
255
}
256
}
257
}
258
259
/**
260
* Dump a ByteBuffer as a hexdump to stdout. The dumping routine will
261
* start at the current position of the buffer and run to its limit.
262
* After completing the dump, the position will be returned to its
263
* starting point.
264
*
265
* @param data the ByteBuffer to dump to stdout.
266
*
267
* @return the hexdump of the byte array.
268
*/
269
private static String dumpHexBytes(ByteBuffer data) {
270
StringBuilder sb = new StringBuilder();
271
if (data != null) {
272
int i = 0;
273
data.mark();
274
while (data.hasRemaining()) {
275
if (i % 16 == 0 && i != 0) {
276
sb.append("\n");
277
}
278
sb.append(String.format("%02X ", data.get()));
279
i++;
280
}
281
data.reset();
282
}
283
284
return sb.toString();
285
}
286
287
private static void hrrKeyShareTest(int hrrNamedGroup, boolean expectedPass)
288
throws Exception {
289
SSLContext sslCtx = SSLContext.getDefault();
290
SSLEngine engine = sslCtx.createSSLEngine();
291
engine.setUseClientMode(true);
292
SSLSession session = engine.getSession();
293
ByteBuffer clientOut =
294
ByteBuffer.wrap("I'm a Client".getBytes());
295
ByteBuffer cTOs = ByteBuffer.allocateDirect(
296
session.getPacketBufferSize());
297
298
// Create and check the ClientHello message
299
SSLEngineResult clientResult = engine.wrap(clientOut, cTOs);
300
logResult("client wrap: ", clientResult);
301
if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
302
throw new RuntimeException("Client wrap got status: " +
303
clientResult.getStatus());
304
}
305
306
cTOs.flip();
307
System.out.println("----- ORIGINAL CLIENT HELLO -----\n" +
308
dumpHexBytes(cTOs));
309
ClientHello initialCh = new ClientHello(cTOs);
310
311
if (!initialCh.suppVersions.contains(TLS_PROT_VER_13)) {
312
throw new RuntimeException(
313
"Missing TLSv1.3 protocol in supported_versions");
314
} else if (!initialCh.keyShares.containsKey(NG_X25519) ||
315
!initialCh.keyShares.containsKey(NG_SECP256R1)) {
316
throw new RuntimeException(
317
"Missing one or more expected KeyShares");
318
}
319
320
// Craft the HRR message with the passed-in named group as the
321
// key share named group to request.
322
ByteBuffer sTOc = buildHRRMessage(initialCh, hrrNamedGroup);
323
System.out.println("----- SERVER HELLO RETRY REQUEST -----\n" +
324
dumpHexBytes(sTOc));
325
326
// Unwrap the HRR and process it
327
clientResult = engine.unwrap(sTOc, clientOut);
328
logResult("client unwrap: ", clientResult);
329
if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
330
throw new RuntimeException("Client wrap got status: " +
331
clientResult.getStatus());
332
}
333
runDelegatedTasks(engine);
334
335
try {
336
// Now we're expecting to reissue the ClientHello, this time
337
// with a secp384r1 share.
338
cTOs.compact();
339
clientResult = engine.wrap(clientOut, cTOs);
340
logResult("client wrap: ", clientResult);
341
if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
342
throw new RuntimeException("Client wrap got status: " +
343
clientResult.getStatus());
344
}
345
} catch (RuntimeException | SSLException ssle) {
346
if (expectedPass) {
347
System.out.println("Caught unexpected exception");
348
throw ssle;
349
} else {
350
System.out.println("Caught expected exception: " + ssle);
351
352
// Try issuing another wrap call and see if we can get
353
// the Alert out.
354
clientResult = engine.wrap(clientOut, cTOs);
355
logResult("client wrap: ", clientResult);
356
if (clientResult.getStatus() != SSLEngineResult.Status.CLOSED) {
357
throw new RuntimeException("Client wrap got status: " +
358
clientResult.getStatus());
359
}
360
361
cTOs.flip();
362
System.out.println("----- ALERT -----\n" + dumpHexBytes(cTOs));
363
Alert alert = new Alert(cTOs);
364
if (alert.alertType != ALERT_TYPE_FATAL ||
365
alert.alertDesc != ALERT_DESC_ILLEGAL_PARAM) {
366
throw new RuntimeException("Unexpected alert. " +
367
"received " + alert.alertType + " / " +
368
alert.alertDesc);
369
}
370
return;
371
}
372
}
373
374
cTOs.flip();
375
System.out.println("----- REISSUED CLIENT HELLO -----\n" +
376
dumpHexBytes(cTOs));
377
ClientHello reissuedCh = new ClientHello(cTOs);
378
379
if (!reissuedCh.keyShares.containsKey(hrrNamedGroup)) {
380
throw new RuntimeException("Missing secp384r1 key share");
381
}
382
}
383
384
private static ByteBuffer buildHRRMessage(ClientHello cliHello,
385
int namedGroup) throws IOException {
386
// Create a ByteBuffer that will be large enough to handle
387
// the HelloRetryRequest
388
ByteBuffer hrrBuf = ByteBuffer.allocate(2048); // More than enough!
389
390
// Advance past the TLS record and handshake message headers. We will
391
// go back later and scribble in the proper lengths. The record header
392
// is 5 bytes long, the handshake header is 4.
393
hrrBuf.position(9);
394
hrrBuf.putShort((short)TLS_LEGACY_VER);
395
hrrBuf.put(HRR_RANDOM);
396
hrrBuf.put((byte)cliHello.sessId.length);
397
hrrBuf.put(cliHello.sessId);
398
hrrBuf.putShort(cliHello.cipherSuites.get(0).shortValue());
399
hrrBuf.put((byte)COMP_NONE);
400
401
// Use a separate stream for creating the extension section
402
ByteArrayOutputStream extBaos = new ByteArrayOutputStream();
403
DataOutputStream extStream = new DataOutputStream(extBaos);
404
405
// Supported version
406
extStream.writeShort(HELLO_EXT_SUPP_VERS);
407
extStream.writeShort(2);
408
extStream.writeShort(TLS_PROT_VER_13);
409
410
// Key share
411
extStream.writeShort(HELLO_EXT_KEY_SHARE);
412
extStream.writeShort(2);
413
extStream.writeShort(namedGroup);
414
415
// Now add in the extensions into the main message
416
hrrBuf.putShort((short)extStream.size());
417
hrrBuf.put(extBaos.toByteArray());
418
419
// At this point we can go back and write in the TLS record and
420
// handshake message headers.
421
hrrBuf.flip();
422
423
// Write in the TLS record header
424
hrrBuf.put((byte)TLS_REC_HANDSHAKE);
425
hrrBuf.putShort((short)TLS_LEGACY_VER);
426
hrrBuf.putShort((short)(hrrBuf.limit() - 5));
427
428
// Write the Handshake message header
429
hrrBuf.putInt((HS_MSG_SERVHELLO << 24) |
430
((hrrBuf.limit() - 9) & 0x00FFFFFF));
431
432
hrrBuf.rewind();
433
return hrrBuf;
434
}
435
}
436
437