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/KrbClientKeyExchange.java
38830 views
1
/*
2
* Copyright (c) 2020, Azul Systems, Inc. All rights reserved.
3
* Copyright (c) 2020, Red Hat, Inc.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation. Oracle designates this
9
* particular file as subject to the "Classpath" exception as provided
10
* by Oracle in the LICENSE file that accompanied this code.
11
*
12
* This code is distributed in the hope that it will be useful, but WITHOUT
13
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15
* version 2 for more details (a copy is included in the LICENSE file that
16
* accompanied this code).
17
*
18
* You should have received a copy of the GNU General Public License version
19
* 2 along with this work; if not, write to the Free Software Foundation,
20
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21
*
22
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23
* or visit www.oracle.com if you need additional information or have any
24
* questions.
25
*/
26
27
package sun.security.ssl;
28
29
import java.io.IOException;
30
import java.lang.reflect.InvocationTargetException;
31
import java.nio.ByteBuffer;
32
import java.security.AccessControlContext;
33
import java.security.AccessController;
34
import java.security.Principal;
35
import java.security.PrivilegedAction;
36
import java.text.MessageFormat;
37
import java.util.Locale;
38
import javax.crypto.SecretKey;
39
import javax.net.ssl.SNIHostName;
40
import javax.net.ssl.StandardConstants;
41
42
import sun.misc.HexDumpEncoder;
43
import sun.security.ssl.KrbKeyExchange.KrbPremasterSecret;
44
import sun.security.ssl.SSLHandshake.HandshakeMessage;
45
46
/**
47
* Pack of the "ClientKeyExchange" handshake message.
48
*/
49
final class KrbClientKeyExchange {
50
static final SSLConsumer krbHandshakeConsumer =
51
new KrbClientKeyExchangeConsumer();
52
static final HandshakeProducer krbHandshakeProducer =
53
new KrbClientKeyExchangeProducer();
54
55
/**
56
* The KRB5 ClientKeyExchange handshake message (CLIENT -> SERVER).
57
* It holds the Kerberos ticket and the encrypted pre-master secret
58
* encrypted with the session key sealed in the ticket.
59
*
60
* From RFC 2712:
61
*
62
* struct
63
* {
64
* opaque Ticket;
65
* opaque authenticator; // optional, ignored
66
* opaque EncryptedPreMasterSecret; // encrypted with the session key
67
* // sealed in the ticket
68
* } KerberosWrapper;
69
*
70
*/
71
private static final
72
class KrbClientKeyExchangeMessage extends HandshakeMessage {
73
74
private static final String KRB5_CLASS_NAME =
75
"sun.security.ssl.krb5.KrbClientKeyExchangeHelperImpl";
76
77
private static final Class<?> krb5Class = AccessController.doPrivileged(
78
new PrivilegedAction<Class<?>>() {
79
@Override
80
public Class<?> run() {
81
try {
82
return Class.forName(KRB5_CLASS_NAME, true, null);
83
} catch (ClassNotFoundException cnf) {
84
return null;
85
}
86
}
87
});
88
89
private static KrbClientKeyExchangeHelper newKrb5Instance() {
90
if (krb5Class != null) {
91
try {
92
return (KrbClientKeyExchangeHelper)krb5Class.
93
getDeclaredConstructor().newInstance();
94
} catch (InstantiationException | IllegalAccessException |
95
NoSuchMethodException | InvocationTargetException e) {
96
throw new AssertionError(e);
97
}
98
}
99
return null;
100
}
101
102
private final KrbClientKeyExchangeHelper krb5Helper;
103
104
private KrbClientKeyExchangeMessage(HandshakeContext context) {
105
super(context);
106
if ((krb5Helper = newKrb5Instance()) == null)
107
throw new IllegalStateException("Kerberos is unavailable");
108
}
109
110
KrbClientKeyExchangeMessage(HandshakeContext context,
111
byte[] preMaster, String serverName,
112
AccessControlContext acc) throws IOException {
113
this(context);
114
krb5Helper.init(preMaster, serverName, acc);
115
}
116
117
KrbClientKeyExchangeMessage(HandshakeContext context,
118
ByteBuffer message, Object serverKeys,
119
AccessControlContext acc) throws IOException {
120
this(context);
121
byte[] encodedTicket = Record.getBytes16(message);
122
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
123
SSLLogger.fine("encoded Kerberos service ticket",
124
encodedTicket);
125
}
126
// Read and ignore the authenticator
127
Record.getBytes16(message);
128
byte[] encryptedPreMasterSecret = Record.getBytes16(message);
129
if (encryptedPreMasterSecret != null && SSLLogger.isOn &&
130
SSLLogger.isOn("ssl,handshake")) {
131
SSLLogger.fine("encrypted Kerberos pre-master secret",
132
encryptedPreMasterSecret);
133
}
134
krb5Helper.init(encodedTicket, encryptedPreMasterSecret,
135
serverKeys, acc);
136
}
137
138
@Override
139
SSLHandshake handshakeType() {
140
return SSLHandshake.CLIENT_KEY_EXCHANGE;
141
}
142
143
@Override
144
int messageLength() {
145
return (6 + krb5Helper.getEncodedTicket().length +
146
krb5Helper.getEncryptedPreMasterSecret().length);
147
}
148
149
@Override
150
void send(HandshakeOutStream hos) throws IOException {
151
hos.putBytes16(krb5Helper.getEncodedTicket());
152
hos.putBytes16(null); // XXX no authenticator
153
hos.putBytes16(krb5Helper.getEncryptedPreMasterSecret());
154
}
155
156
byte[] getPlainPreMasterSecret() {
157
return krb5Helper.getPlainPreMasterSecret();
158
}
159
160
Principal getPeerPrincipal() {
161
return krb5Helper.getPeerPrincipal();
162
}
163
164
Principal getLocalPrincipal() {
165
return krb5Helper.getLocalPrincipal();
166
}
167
168
@Override
169
public String toString() {
170
MessageFormat messageFormat = new MessageFormat(
171
"\"KRB5 ClientKeyExchange\": '{'\n" +
172
" \"ticket\": '{'\n" +
173
"{0}\n" +
174
" '}'\n" +
175
" \"pre-master\": '{'\n" +
176
" \"plain\": '{'\n" +
177
"{1}\n" +
178
" '}'\n" +
179
" \"encrypted\": '{'\n" +
180
"{2}\n" +
181
" '}'\n" +
182
" '}'\n" +
183
"'}'",
184
Locale.ENGLISH);
185
186
HexDumpEncoder hexEncoder = new HexDumpEncoder();
187
Object[] messageFields = {
188
Utilities.indent(
189
hexEncoder.encodeBuffer(
190
krb5Helper.getEncodedTicket()), " "),
191
Utilities.indent(
192
hexEncoder.encodeBuffer(
193
krb5Helper.getPlainPreMasterSecret()), " "),
194
Utilities.indent(
195
hexEncoder.encodeBuffer(
196
krb5Helper.getEncryptedPreMasterSecret()), " "),
197
};
198
return messageFormat.format(messageFields);
199
}
200
}
201
202
/**
203
* The KRB5 "ClientKeyExchange" handshake message producer.
204
*/
205
private static final
206
class KrbClientKeyExchangeProducer implements HandshakeProducer {
207
// Prevent instantiation of this class.
208
private KrbClientKeyExchangeProducer() {
209
// blank
210
}
211
212
@Override
213
public byte[] produce(ConnectionContext context,
214
HandshakeMessage message) throws IOException {
215
// This happens in client side only.
216
ClientHandshakeContext chc = (ClientHandshakeContext)context;
217
218
KrbClientKeyExchangeMessage kerberosMsg = null;
219
String hostName = null;
220
if (chc.negotiatedServerName != null) {
221
if (chc.negotiatedServerName.getType() ==
222
StandardConstants.SNI_HOST_NAME) {
223
SNIHostName sniHostName = null;
224
if (chc.negotiatedServerName instanceof SNIHostName) {
225
sniHostName = (SNIHostName) chc.negotiatedServerName;
226
} else {
227
try {
228
sniHostName = new SNIHostName(
229
chc.negotiatedServerName.getEncoded());
230
} catch (IllegalArgumentException iae) {
231
// unlikely to happen, just in case ...
232
}
233
}
234
if (sniHostName != null)
235
hostName = sniHostName.getAsciiName();
236
}
237
} else {
238
hostName = chc.handshakeSession.getPeerHost();
239
}
240
try {
241
KrbPremasterSecret premasterSecret =
242
KrbPremasterSecret.createPremasterSecret(
243
chc.negotiatedProtocol,
244
chc.sslContext.getSecureRandom());
245
kerberosMsg = new KrbClientKeyExchangeMessage(chc,
246
premasterSecret.preMaster, hostName,
247
chc.conContext.acc);
248
chc.handshakePossessions.add(premasterSecret);
249
} catch (IOException e) {
250
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
251
SSLLogger.fine(
252
"Error generating KRB premaster secret." +
253
" Hostname: " + hostName + " - Negotiated" +
254
" server name: " + chc.negotiatedServerName);
255
}
256
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
257
"Cannot generate KRB premaster secret", e);
258
}
259
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
260
SSLLogger.fine(
261
"Produced KRB5 ClientKeyExchange handshake message",
262
kerberosMsg);
263
}
264
265
// Record the principals involved in the exchange
266
chc.handshakeSession.setPeerPrincipal(kerberosMsg.getPeerPrincipal());
267
chc.handshakeSession.setLocalPrincipal(kerberosMsg.getLocalPrincipal());
268
269
// Output the handshake message.
270
kerberosMsg.write(chc.handshakeOutput);
271
chc.handshakeOutput.flush();
272
273
// update the states
274
SSLKeyExchange ke = SSLKeyExchange.valueOf(
275
chc.negotiatedCipherSuite.keyExchange,
276
chc.negotiatedProtocol);
277
if (ke == null) {
278
// unlikely
279
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
280
"Not supported key exchange type");
281
} else {
282
SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
283
SecretKey masterSecret =
284
masterKD.deriveKey("MasterSecret", null);
285
286
chc.handshakeSession.setMasterSecret(masterSecret);
287
288
SSLTrafficKeyDerivation kd =
289
SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
290
if (kd == null) {
291
// unlikely
292
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
293
"Not supported key derivation: " +
294
chc.negotiatedProtocol);
295
} else {
296
chc.handshakeKeyDerivation =
297
kd.createKeyDerivation(chc, masterSecret);
298
}
299
}
300
301
// The handshake message has been delivered.
302
return null;
303
}
304
}
305
306
/**
307
* The KRB5 "ClientKeyExchange" handshake message consumer.
308
*/
309
private static final
310
class KrbClientKeyExchangeConsumer implements SSLConsumer {
311
// Prevent instantiation of this class.
312
private KrbClientKeyExchangeConsumer() {
313
// blank
314
}
315
316
@Override
317
public void consume(ConnectionContext context,
318
ByteBuffer message) throws IOException {
319
// The consuming happens in server side only.
320
ServerHandshakeContext shc = (ServerHandshakeContext)context;
321
322
Object serviceCreds = null;
323
for (SSLPossession possession : shc.handshakePossessions) {
324
if (possession instanceof KrbKeyExchange.KrbServiceCreds) {
325
serviceCreds = ((KrbKeyExchange.KrbServiceCreds) possession)
326
.serviceCreds;
327
break;
328
}
329
}
330
if (serviceCreds == null) { // unlikely
331
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
332
"No Kerberos service credentials for KRB Client Key Exchange");
333
}
334
335
KrbClientKeyExchangeMessage kerberosMsg =
336
new KrbClientKeyExchangeMessage(shc,
337
message, serviceCreds, shc.conContext.acc);
338
KrbPremasterSecret premasterSecret = KrbPremasterSecret.decode(
339
shc.negotiatedProtocol,
340
ProtocolVersion.valueOf(shc.clientHelloVersion),
341
kerberosMsg.getPlainPreMasterSecret(),
342
shc.sslContext.getSecureRandom());
343
shc.handshakeSession.setPeerPrincipal(kerberosMsg.getPeerPrincipal());
344
shc.handshakeSession.setLocalPrincipal(kerberosMsg.getLocalPrincipal());
345
shc.handshakeCredentials.add(premasterSecret);
346
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
347
SSLLogger.fine(
348
"Consuming KRB5 ClientKeyExchange handshake message",
349
kerberosMsg);
350
}
351
352
// update the states
353
SSLKeyExchange ke = SSLKeyExchange.valueOf(
354
shc.negotiatedCipherSuite.keyExchange,
355
shc.negotiatedProtocol);
356
if (ke == null) { // unlikely
357
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
358
"Not supported key exchange type");
359
} else {
360
SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
361
SecretKey masterSecret =
362
masterKD.deriveKey("MasterSecret", null);
363
364
// update the states
365
shc.handshakeSession.setMasterSecret(masterSecret);
366
SSLTrafficKeyDerivation kd =
367
SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
368
if (kd == null) { // unlikely
369
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
370
"Not supported key derivation: " +
371
shc.negotiatedProtocol);
372
} else {
373
shc.handshakeKeyDerivation =
374
kd.createKeyDerivation(shc, masterSecret);
375
}
376
}
377
}
378
}
379
}
380
381