Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/javax/net/ssl/TLSv13/ClientHelloKeyShares.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
* @run main/othervm ClientHelloKeyShares 29 23
33
* @run main/othervm -Djdk.tls.namedGroups=secp384r1,secp521r1,x448,ffdhe2048 ClientHelloKeyShares 24 30
34
* @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,x25519 ClientHelloKeyShares 29
35
* @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,secp256r1 ClientHelloKeyShares 23
36
* @run main/othervm -Djdk.tls.namedGroups=sect163k1,sect163r1,ffdhe2048,ffdhe3072,ffdhe4096 ClientHelloKeyShares 256
37
* @run main/othervm -Djdk.tls.namedGroups=sect163k1,ffdhe2048,x25519,secp256r1 ClientHelloKeyShares 256 29
38
* @run main/othervm -Djdk.tls.namedGroups=secp256r1,secp384r1,ffdhe2048,x25519 ClientHelloKeyShares 23 256
39
*/
40
41
import javax.net.ssl.*;
42
import javax.net.ssl.SSLEngineResult.*;
43
import java.nio.ByteBuffer;
44
import java.util.*;
45
46
47
public class ClientHelloKeyShares {
48
49
// Some TLS constants we'll use for testing
50
private static final int TLS_REC_HANDSHAKE = 22;
51
private static final int HELLO_EXT_SUPP_GROUPS = 10;
52
private static final int HELLO_EXT_SUPP_VERS = 43;
53
private static final int HELLO_EXT_KEY_SHARE = 51;
54
private static final int TLS_PROT_VER_13 = 0x0304;
55
private static final int NG_SECP256R1 = 0x0017;
56
private static final int NG_SECP384R1 = 0x0018;
57
private static final int NG_X25519 = 0x001D;
58
private static final int NG_X448 = 0x001E;
59
60
public static void main(String args[]) throws Exception {
61
// Arguments to this test are an abitrary number of integer
62
// values which will be the expected NamedGroup IDs in the key_share
63
// extension. Expected named group assertions may also be affected
64
// by setting the jdk.tls.namedGroups System property.
65
List<Integer> expectedKeyShares = new ArrayList<>();
66
Arrays.stream(args).forEach(arg ->
67
expectedKeyShares.add(Integer.valueOf(arg)));
68
69
SSLContext sslCtx = SSLContext.getDefault();
70
SSLEngine engine = sslCtx.createSSLEngine();
71
engine.setUseClientMode(true);
72
SSLSession session = engine.getSession();
73
ByteBuffer clientOut = ByteBuffer.wrap("I'm a Client".getBytes());
74
ByteBuffer cTOs =
75
ByteBuffer.allocateDirect(session.getPacketBufferSize());
76
77
// Create and check the ClientHello message
78
SSLEngineResult clientResult = engine.wrap(clientOut, cTOs);
79
logResult("client wrap: ", clientResult);
80
if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
81
throw new RuntimeException("Client wrap got status: " +
82
clientResult.getStatus());
83
}
84
85
cTOs.flip();
86
System.out.println(dumpHexBytes(cTOs));
87
checkClientHello(cTOs, expectedKeyShares);
88
}
89
90
private static void logResult(String str, SSLEngineResult result) {
91
HandshakeStatus hsStatus = result.getHandshakeStatus();
92
System.out.println(str +
93
result.getStatus() + "/" + hsStatus + ", " +
94
result.bytesConsumed() + "/" + result.bytesProduced() +
95
" bytes");
96
if (hsStatus == HandshakeStatus.FINISHED) {
97
System.out.println("\t...ready for application data");
98
}
99
}
100
101
/**
102
* Dump a ByteBuffer as a hexdump to stdout. The dumping routine will
103
* start at the current position of the buffer and run to its limit.
104
* After completing the dump, the position will be returned to its
105
* starting point.
106
*
107
* @param data the ByteBuffer to dump to stdout.
108
*
109
* @return the hexdump of the byte array.
110
*/
111
private static String dumpHexBytes(ByteBuffer data) {
112
StringBuilder sb = new StringBuilder();
113
if (data != null) {
114
int i = 0;
115
data.mark();
116
while (data.hasRemaining()) {
117
if (i % 16 == 0 && i != 0) {
118
sb.append("\n");
119
}
120
sb.append(String.format("%02X ", data.get()));
121
i++;
122
}
123
data.reset();
124
}
125
126
return sb.toString();
127
}
128
129
/**
130
* Tests the ClientHello for the presence of the key shares in the supplied
131
* List of key share identifiers.
132
*
133
* @param data the ByteBuffer containing the ClientHello bytes
134
* @param keyShareTypes a List containing the expected key shares
135
*
136
* @throws RuntimeException if there is a deviation between what is expected
137
* and what is supplied. It will also throw this exception if other
138
* basic structural elements of the ClientHello are not found (e.g. TLS 1.3
139
* is not in the list of supported groups, etc.)
140
*/
141
private static void checkClientHello(ByteBuffer data,
142
List<Integer> expectedKeyShares) {
143
Objects.requireNonNull(data);
144
data.mark();
145
146
// Process the TLS record header
147
int type = Byte.toUnsignedInt(data.get());
148
int ver_major = Byte.toUnsignedInt(data.get());
149
int ver_minor = Byte.toUnsignedInt(data.get());
150
int recLen = Short.toUnsignedInt(data.getShort());
151
152
// Simple sanity checks
153
if (type != 22) {
154
throw new RuntimeException("Not a handshake: Type = " + type);
155
} else if (recLen > data.remaining()) {
156
throw new RuntimeException("Incomplete record in buffer: " +
157
"Record length = " + recLen + ", Remaining = " +
158
data.remaining());
159
}
160
161
// Grab the handshake message header.
162
int msgHdr = data.getInt();
163
int msgType = (msgHdr >> 24) & 0x000000FF;
164
int msgLen = msgHdr & 0x00FFFFFF;
165
166
// More simple sanity checks
167
if (msgType != 1) {
168
throw new RuntimeException("Not a ClientHello: Type = " + msgType);
169
}
170
171
// Skip over the protocol version and client random
172
data.position(data.position() + 34);
173
174
// Jump past the session ID (if there is one)
175
int sessLen = Byte.toUnsignedInt(data.get());
176
if (sessLen != 0) {
177
data.position(data.position() + sessLen);
178
}
179
180
// Jump past the cipher suites
181
int csLen = Short.toUnsignedInt(data.getShort());
182
if (csLen != 0) {
183
data.position(data.position() + csLen);
184
}
185
186
// ...and the compression
187
int compLen = Byte.toUnsignedInt(data.get());
188
if (compLen != 0) {
189
data.position(data.position() + compLen);
190
}
191
192
// Now for the fun part. Go through the extensions and look
193
// for supported_versions (to make sure TLS 1.3 is asserted) and
194
// the expected key shares are present.
195
boolean foundSupVer = false;
196
boolean foundKeyShare = false;
197
int extsLen = Short.toUnsignedInt(data.getShort());
198
List<Integer> supGrpList = new ArrayList<>();
199
List<Integer> chKeyShares = new ArrayList<>();
200
while (data.hasRemaining()) {
201
int extType = Short.toUnsignedInt(data.getShort());
202
int extLen = Short.toUnsignedInt(data.getShort());
203
boolean foundTLS13 = false;
204
switch (extType) {
205
case HELLO_EXT_SUPP_GROUPS:
206
int supGrpLen = Short.toUnsignedInt(data.getShort());
207
for (int remain = supGrpLen; remain > 0; remain -= 2) {
208
supGrpList.add(Short.toUnsignedInt(data.getShort()));
209
}
210
break;
211
case HELLO_EXT_SUPP_VERS:
212
foundSupVer = true;
213
int supVerLen = Byte.toUnsignedInt(data.get());
214
for (int remain = supVerLen; remain > 0; remain -= 2) {
215
foundTLS13 |= (Short.toUnsignedInt(data.getShort()) ==
216
TLS_PROT_VER_13);
217
}
218
219
if (!foundTLS13) {
220
throw new RuntimeException("Missing TLS 1.3 Protocol " +
221
"Version in supported_groups");
222
}
223
break;
224
case HELLO_EXT_KEY_SHARE:
225
foundKeyShare = true;
226
int ksListLen = Short.toUnsignedInt(data.getShort());
227
while (ksListLen > 0) {
228
chKeyShares.add(Short.toUnsignedInt(data.getShort()));
229
int ksLen = Short.toUnsignedInt(data.getShort());
230
data.position(data.position() + ksLen);
231
ksListLen -= (4 + ksLen);
232
}
233
break;
234
default:
235
data.position(data.position() + extLen);
236
break;
237
}
238
}
239
240
// We must have parsed supported_versions, key_share and
241
// supported_groups extensions.
242
if ((foundSupVer && foundKeyShare && !supGrpList.isEmpty()) == false) {
243
throw new RuntimeException("Missing one or more of key_share, " +
244
"supported_versions and/or supported_groups extensions");
245
}
246
247
// The key share types we expected in the test should match exactly what
248
// was asserted in the client hello
249
if (!expectedKeyShares.equals(chKeyShares)) {
250
StringBuilder sb = new StringBuilder(
251
"Expected and Actual key_share lists differ: ");
252
sb.append("Expected: ");
253
expectedKeyShares.forEach(ng -> sb.append(ng).append(" "));
254
sb.append(", Actual: ");
255
chKeyShares.forEach(ng -> sb.append(ng).append(" "));
256
throw new RuntimeException(sb.toString());
257
}
258
259
// The order of the key shares should match the order of precedence
260
// of the same named groups asserted in the supported_groups extension.
261
// (RFC 8446, 4.2.8)
262
int prevChNg = -1;
263
for (int ng : chKeyShares) {
264
int chNgPos = supGrpList.indexOf(ng);
265
if (chNgPos <= prevChNg) {
266
throw new RuntimeException("Order of precedence violation " +
267
"for NamedGroup " + ng + " between key_share and " +
268
"supported_groups extensions");
269
}
270
prevChNg = chNgPos;
271
}
272
273
// We should be at the end of the ClientHello
274
data.reset();
275
}
276
}
277
278