Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java
41159 views
1
/*
2
* Copyright (c) 2018, 2019, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.ssl;
27
28
import java.io.IOException;
29
import java.security.MessageDigest;
30
import java.security.NoSuchAlgorithmException;
31
import java.security.SecureRandom;
32
import java.util.Arrays;
33
import java.util.concurrent.locks.ReentrantLock;
34
import static sun.security.ssl.ClientHello.ClientHelloMessage;
35
36
/**
37
* (D)TLS handshake cookie manager
38
*/
39
abstract class HelloCookieManager {
40
41
static class Builder {
42
43
final SecureRandom secureRandom;
44
45
private volatile D10HelloCookieManager d10HelloCookieManager;
46
private volatile D13HelloCookieManager d13HelloCookieManager;
47
private volatile T13HelloCookieManager t13HelloCookieManager;
48
49
private final ReentrantLock managerLock = new ReentrantLock();
50
51
Builder(SecureRandom secureRandom) {
52
this.secureRandom = secureRandom;
53
}
54
55
HelloCookieManager valueOf(ProtocolVersion protocolVersion) {
56
if (protocolVersion.isDTLS) {
57
if (protocolVersion.useTLS13PlusSpec()) {
58
if (d13HelloCookieManager != null) {
59
return d13HelloCookieManager;
60
}
61
62
managerLock.lock();
63
try {
64
if (d13HelloCookieManager == null) {
65
d13HelloCookieManager =
66
new D13HelloCookieManager(secureRandom);
67
}
68
} finally {
69
managerLock.unlock();
70
}
71
72
return d13HelloCookieManager;
73
} else {
74
if (d10HelloCookieManager != null) {
75
return d10HelloCookieManager;
76
}
77
78
managerLock.lock();
79
try {
80
if (d10HelloCookieManager == null) {
81
d10HelloCookieManager =
82
new D10HelloCookieManager(secureRandom);
83
}
84
} finally {
85
managerLock.unlock();
86
}
87
88
return d10HelloCookieManager;
89
}
90
} else {
91
if (protocolVersion.useTLS13PlusSpec()) {
92
if (t13HelloCookieManager != null) {
93
return t13HelloCookieManager;
94
}
95
96
managerLock.lock();
97
try {
98
if (t13HelloCookieManager == null) {
99
t13HelloCookieManager =
100
new T13HelloCookieManager(secureRandom);
101
}
102
} finally {
103
managerLock.unlock();
104
}
105
106
return t13HelloCookieManager;
107
}
108
}
109
110
return null;
111
}
112
}
113
114
abstract byte[] createCookie(ServerHandshakeContext context,
115
ClientHelloMessage clientHello) throws IOException;
116
117
abstract boolean isCookieValid(ServerHandshakeContext context,
118
ClientHelloMessage clientHello, byte[] cookie) throws IOException;
119
120
// DTLS 1.0/1.2
121
private static final
122
class D10HelloCookieManager extends HelloCookieManager {
123
124
final SecureRandom secureRandom;
125
private int cookieVersion; // allow to wrap, version + sequence
126
private final byte[] cookieSecret;
127
private final byte[] legacySecret;
128
129
private final ReentrantLock d10ManagerLock = new ReentrantLock();
130
131
D10HelloCookieManager(SecureRandom secureRandom) {
132
this.secureRandom = secureRandom;
133
134
this.cookieVersion = secureRandom.nextInt();
135
this.cookieSecret = new byte[32];
136
this.legacySecret = new byte[32];
137
138
secureRandom.nextBytes(cookieSecret);
139
System.arraycopy(cookieSecret, 0, legacySecret, 0, 32);
140
}
141
142
@Override
143
byte[] createCookie(ServerHandshakeContext context,
144
ClientHelloMessage clientHello) throws IOException {
145
int version;
146
byte[] secret;
147
148
d10ManagerLock.lock();
149
try {
150
version = cookieVersion;
151
secret = cookieSecret;
152
153
// the cookie secret usage limit is 2^24
154
if ((cookieVersion & 0xFFFFFF) == 0) { // reset the secret
155
System.arraycopy(cookieSecret, 0, legacySecret, 0, 32);
156
secureRandom.nextBytes(cookieSecret);
157
}
158
159
cookieVersion++;
160
} finally {
161
d10ManagerLock.unlock();
162
}
163
164
MessageDigest md;
165
try {
166
md = MessageDigest.getInstance("SHA-256");
167
} catch (NoSuchAlgorithmException nsae) {
168
throw new RuntimeException(
169
"MessageDigest algorithm SHA-256 is not available", nsae);
170
}
171
byte[] helloBytes = clientHello.getHelloCookieBytes();
172
md.update(helloBytes);
173
byte[] cookie = md.digest(secret); // 32 bytes
174
cookie[0] = (byte)((version >> 24) & 0xFF);
175
176
return cookie;
177
}
178
179
@Override
180
boolean isCookieValid(ServerHandshakeContext context,
181
ClientHelloMessage clientHello, byte[] cookie) throws IOException {
182
// no cookie exchange or not a valid cookie length
183
if ((cookie == null) || (cookie.length != 32)) {
184
return false;
185
}
186
187
byte[] secret;
188
d10ManagerLock.lock();
189
try {
190
if (((cookieVersion >> 24) & 0xFF) == cookie[0]) {
191
secret = cookieSecret;
192
} else {
193
secret = legacySecret; // including out of window cookies
194
}
195
} finally {
196
d10ManagerLock.unlock();
197
}
198
199
MessageDigest md;
200
try {
201
md = MessageDigest.getInstance("SHA-256");
202
} catch (NoSuchAlgorithmException nsae) {
203
throw new RuntimeException(
204
"MessageDigest algorithm SHA-256 is not available", nsae);
205
}
206
byte[] helloBytes = clientHello.getHelloCookieBytes();
207
md.update(helloBytes);
208
byte[] target = md.digest(secret); // 32 bytes
209
target[0] = cookie[0];
210
211
return Arrays.equals(target, cookie);
212
}
213
}
214
215
private static final
216
class D13HelloCookieManager extends HelloCookieManager {
217
D13HelloCookieManager(SecureRandom secureRandom) {
218
}
219
220
@Override
221
byte[] createCookie(ServerHandshakeContext context,
222
ClientHelloMessage clientHello) throws IOException {
223
throw new UnsupportedOperationException("Not supported yet.");
224
}
225
226
@Override
227
boolean isCookieValid(ServerHandshakeContext context,
228
ClientHelloMessage clientHello, byte[] cookie) throws IOException {
229
throw new UnsupportedOperationException("Not supported yet.");
230
}
231
}
232
233
private static final
234
class T13HelloCookieManager extends HelloCookieManager {
235
236
final SecureRandom secureRandom;
237
private int cookieVersion; // version + sequence
238
private final byte[] cookieSecret;
239
private final byte[] legacySecret;
240
241
private final ReentrantLock t13ManagerLock = new ReentrantLock();
242
243
T13HelloCookieManager(SecureRandom secureRandom) {
244
this.secureRandom = secureRandom;
245
this.cookieVersion = secureRandom.nextInt();
246
this.cookieSecret = new byte[64];
247
this.legacySecret = new byte[64];
248
249
secureRandom.nextBytes(cookieSecret);
250
System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
251
}
252
253
@Override
254
byte[] createCookie(ServerHandshakeContext context,
255
ClientHelloMessage clientHello) throws IOException {
256
int version;
257
byte[] secret;
258
259
t13ManagerLock.lock();
260
try {
261
version = cookieVersion;
262
secret = cookieSecret;
263
264
// the cookie secret usage limit is 2^24
265
if ((cookieVersion & 0xFFFFFF) == 0) { // reset the secret
266
System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
267
secureRandom.nextBytes(cookieSecret);
268
}
269
270
cookieVersion++; // allow wrapped version number
271
} finally {
272
t13ManagerLock.unlock();
273
}
274
275
MessageDigest md;
276
try {
277
md = MessageDigest.getInstance(
278
context.negotiatedCipherSuite.hashAlg.name);
279
} catch (NoSuchAlgorithmException nsae) {
280
throw new RuntimeException(
281
"MessageDigest algorithm " +
282
context.negotiatedCipherSuite.hashAlg.name +
283
" is not available", nsae);
284
}
285
byte[] headerBytes = clientHello.getHeaderBytes();
286
md.update(headerBytes);
287
byte[] headerCookie = md.digest(secret);
288
289
// hash of ClientHello handshake message
290
context.handshakeHash.update();
291
byte[] clientHelloHash = context.handshakeHash.digest();
292
293
// version and cipher suite
294
//
295
// Store the negotiated cipher suite in the cookie as well.
296
// cookie[0]/[1]: cipher suite
297
// cookie[2]: cookie version
298
// + (hash length): Mac(ClientHello header)
299
// + (hash length): Hash(ClientHello)
300
byte[] prefix = new byte[] {
301
(byte)((context.negotiatedCipherSuite.id >> 8) & 0xFF),
302
(byte)(context.negotiatedCipherSuite.id & 0xFF),
303
(byte)((version >> 24) & 0xFF)
304
};
305
306
byte[] cookie = Arrays.copyOf(prefix,
307
prefix.length + headerCookie.length + clientHelloHash.length);
308
System.arraycopy(headerCookie, 0, cookie,
309
prefix.length, headerCookie.length);
310
System.arraycopy(clientHelloHash, 0, cookie,
311
prefix.length + headerCookie.length, clientHelloHash.length);
312
313
return cookie;
314
}
315
316
@Override
317
boolean isCookieValid(ServerHandshakeContext context,
318
ClientHelloMessage clientHello, byte[] cookie) throws IOException {
319
// no cookie exchange or not a valid cookie length
320
if ((cookie == null) || (cookie.length <= 32)) { // 32: roughly
321
return false;
322
}
323
324
int csId = ((cookie[0] & 0xFF) << 8) | (cookie[1] & 0xFF);
325
CipherSuite cs = CipherSuite.valueOf(csId);
326
if (cs == null || cs.hashAlg == null || cs.hashAlg.hashLength == 0) {
327
return false;
328
}
329
330
int hashLen = cs.hashAlg.hashLength;
331
if (cookie.length != (3 + hashLen * 2)) {
332
return false;
333
}
334
335
byte[] prevHeadCookie =
336
Arrays.copyOfRange(cookie, 3, 3 + hashLen);
337
byte[] prevClientHelloHash =
338
Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length);
339
340
byte[] secret;
341
t13ManagerLock.lock();
342
try {
343
if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) {
344
secret = cookieSecret;
345
} else {
346
secret = legacySecret; // including out of window cookies
347
}
348
} finally {
349
t13ManagerLock.unlock();
350
}
351
352
MessageDigest md;
353
try {
354
md = MessageDigest.getInstance(cs.hashAlg.name);
355
} catch (NoSuchAlgorithmException nsae) {
356
throw new RuntimeException(
357
"MessageDigest algorithm " +
358
cs.hashAlg.name + " is not available", nsae);
359
}
360
byte[] headerBytes = clientHello.getHeaderBytes();
361
md.update(headerBytes);
362
byte[] headerCookie = md.digest(secret);
363
364
if (!Arrays.equals(headerCookie, prevHeadCookie)) {
365
return false;
366
}
367
368
// Use the ClientHello hash in the cookie for transtript
369
// hash calculation for stateless HelloRetryRequest.
370
//
371
// Transcript-Hash(ClientHello1, HelloRetryRequest, ... Mn) =
372
// Hash(message_hash || /* Handshake type */
373
// 00 00 Hash.length || /* Handshake message length (bytes) */
374
// Hash(ClientHello1) || /* Hash of ClientHello1 */
375
// HelloRetryRequest || ... || Mn)
376
377
// Reproduce HelloRetryRequest handshake message
378
byte[] hrrMessage =
379
ServerHello.hrrReproducer.produce(context, clientHello);
380
context.handshakeHash.push(hrrMessage);
381
382
// Construct the 1st ClientHello message for transcript hash
383
byte[] hashedClientHello = new byte[4 + hashLen];
384
hashedClientHello[0] = SSLHandshake.MESSAGE_HASH.id;
385
hashedClientHello[1] = (byte)0x00;
386
hashedClientHello[2] = (byte)0x00;
387
hashedClientHello[3] = (byte)(hashLen & 0xFF);
388
System.arraycopy(prevClientHelloHash, 0,
389
hashedClientHello, 4, hashLen);
390
391
context.handshakeHash.push(hashedClientHello);
392
393
return true;
394
}
395
}
396
}
397
398