Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/HelloCookieManager.java
38830 views
1
/*
2
* Copyright (c) 2018, 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.SecureRandom;
31
import java.util.Arrays;
32
import static sun.security.ssl.ClientHello.ClientHelloMessage;
33
34
/**
35
* TLS handshake cookie manager
36
*/
37
abstract class HelloCookieManager {
38
39
static class Builder {
40
41
final SecureRandom secureRandom;
42
43
private volatile T13HelloCookieManager t13HelloCookieManager;
44
45
Builder(SecureRandom secureRandom) {
46
this.secureRandom = secureRandom;
47
}
48
49
HelloCookieManager valueOf(ProtocolVersion protocolVersion) {
50
if (protocolVersion.useTLS13PlusSpec()) {
51
if (t13HelloCookieManager != null) {
52
return t13HelloCookieManager;
53
}
54
55
synchronized (this) {
56
if (t13HelloCookieManager == null) {
57
t13HelloCookieManager =
58
new T13HelloCookieManager(secureRandom);
59
}
60
}
61
62
return t13HelloCookieManager;
63
}
64
65
return null;
66
}
67
}
68
69
abstract byte[] createCookie(ServerHandshakeContext context,
70
ClientHelloMessage clientHello) throws IOException;
71
72
abstract boolean isCookieValid(ServerHandshakeContext context,
73
ClientHelloMessage clientHello, byte[] cookie) throws IOException;
74
75
private static final
76
class T13HelloCookieManager extends HelloCookieManager {
77
78
final SecureRandom secureRandom;
79
private int cookieVersion; // version + sequence
80
private final byte[] cookieSecret;
81
private final byte[] legacySecret;
82
83
T13HelloCookieManager(SecureRandom secureRandom) {
84
this.secureRandom = secureRandom;
85
this.cookieVersion = secureRandom.nextInt();
86
this.cookieSecret = new byte[64];
87
this.legacySecret = new byte[64];
88
89
secureRandom.nextBytes(cookieSecret);
90
System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
91
}
92
93
@Override
94
byte[] createCookie(ServerHandshakeContext context,
95
ClientHelloMessage clientHello) throws IOException {
96
int version;
97
byte[] secret;
98
99
synchronized (this) {
100
version = cookieVersion;
101
secret = cookieSecret;
102
103
// the cookie secret usage limit is 2^24
104
if ((cookieVersion & 0xFFFFFF) == 0) { // reset the secret
105
System.arraycopy(cookieSecret, 0, legacySecret, 0, 64);
106
secureRandom.nextBytes(cookieSecret);
107
}
108
109
cookieVersion++; // allow wrapped version number
110
}
111
112
MessageDigest md = JsseJce.getMessageDigest(
113
context.negotiatedCipherSuite.hashAlg.name);
114
byte[] headerBytes = clientHello.getHeaderBytes();
115
md.update(headerBytes);
116
byte[] headerCookie = md.digest(secret);
117
118
// hash of ClientHello handshake message
119
context.handshakeHash.update();
120
byte[] clientHelloHash = context.handshakeHash.digest();
121
122
// version and cipher suite
123
//
124
// Store the negotiated cipher suite in the cookie as well.
125
// cookie[0]/[1]: cipher suite
126
// cookie[2]: cookie version
127
// + (hash length): Mac(ClientHello header)
128
// + (hash length): Hash(ClientHello)
129
byte[] prefix = new byte[] {
130
(byte)((context.negotiatedCipherSuite.id >> 8) & 0xFF),
131
(byte)(context.negotiatedCipherSuite.id & 0xFF),
132
(byte)((version >> 24) & 0xFF)
133
};
134
135
byte[] cookie = Arrays.copyOf(prefix,
136
prefix.length + headerCookie.length + clientHelloHash.length);
137
System.arraycopy(headerCookie, 0, cookie,
138
prefix.length, headerCookie.length);
139
System.arraycopy(clientHelloHash, 0, cookie,
140
prefix.length + headerCookie.length, clientHelloHash.length);
141
142
return cookie;
143
}
144
145
@Override
146
boolean isCookieValid(ServerHandshakeContext context,
147
ClientHelloMessage clientHello, byte[] cookie) throws IOException {
148
// no cookie exchange or not a valid cookie length
149
if ((cookie == null) || (cookie.length <= 32)) { // 32: roughly
150
return false;
151
}
152
153
int csId = ((cookie[0] & 0xFF) << 8) | (cookie[1] & 0xFF);
154
CipherSuite cs = CipherSuite.valueOf(csId);
155
if (cs == null || cs.hashAlg == null || cs.hashAlg.hashLength == 0) {
156
return false;
157
}
158
159
int hashLen = cs.hashAlg.hashLength;
160
if (cookie.length != (3 + hashLen * 2)) {
161
return false;
162
}
163
164
byte[] prevHeadCookie =
165
Arrays.copyOfRange(cookie, 3, 3 + hashLen);
166
byte[] prevClientHelloHash =
167
Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length);
168
169
byte[] secret;
170
synchronized (this) {
171
if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) {
172
secret = cookieSecret;
173
} else {
174
secret = legacySecret; // including out of window cookies
175
}
176
}
177
178
MessageDigest md = JsseJce.getMessageDigest(cs.hashAlg.name);
179
byte[] headerBytes = clientHello.getHeaderBytes();
180
md.update(headerBytes);
181
byte[] headerCookie = md.digest(secret);
182
183
if (!Arrays.equals(headerCookie, prevHeadCookie)) {
184
return false;
185
}
186
187
// Use the ClientHello hash in the cookie for transtript
188
// hash calculation for stateless HelloRetryRequest.
189
//
190
// Transcript-Hash(ClientHello1, HelloRetryRequest, ... Mn) =
191
// Hash(message_hash || /* Handshake type */
192
// 00 00 Hash.length || /* Handshake message length (bytes) */
193
// Hash(ClientHello1) || /* Hash of ClientHello1 */
194
// HelloRetryRequest || ... || Mn)
195
196
// Reproduce HelloRetryRequest handshake message
197
byte[] hrrMessage =
198
ServerHello.hrrReproducer.produce(context, clientHello);
199
context.handshakeHash.push(hrrMessage);
200
201
// Construct the 1st ClientHello message for transcript hash
202
byte[] hashedClientHello = new byte[4 + hashLen];
203
hashedClientHello[0] = SSLHandshake.MESSAGE_HASH.id;
204
hashedClientHello[1] = (byte)0x00;
205
hashedClientHello[2] = (byte)0x00;
206
hashedClientHello[3] = (byte)(hashLen & 0xFF);
207
System.arraycopy(prevClientHelloHash, 0,
208
hashedClientHello, 4, hashLen);
209
210
context.handshakeHash.push(hashedClientHello);
211
212
return true;
213
}
214
}
215
}
216
217