Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java
67771 views
1
/*
2
* Copyright (c) 2003, 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.nio.ByteBuffer;
30
import java.security.CryptoPrimitive;
31
import java.security.GeneralSecurityException;
32
import java.security.PublicKey;
33
import java.security.interfaces.ECPublicKey;
34
import java.security.interfaces.XECPublicKey;
35
import java.security.spec.AlgorithmParameterSpec;
36
import java.security.spec.ECParameterSpec;
37
import java.security.spec.NamedParameterSpec;
38
import java.text.MessageFormat;
39
import java.util.EnumSet;
40
import java.util.Locale;
41
import javax.crypto.SecretKey;
42
import sun.security.ssl.SSLHandshake.HandshakeMessage;
43
import sun.security.ssl.X509Authentication.X509Credentials;
44
import sun.security.ssl.X509Authentication.X509Possession;
45
import sun.security.util.HexDumpEncoder;
46
47
/**
48
* Pack of the "ClientKeyExchange" handshake message.
49
*
50
* This file is used by both the ECDH/ECDHE/XDH code since much of the
51
* code is the same between the EC named groups (i.e.
52
* x25519/x448/secp*r1), even though the APIs are very different (i.e.
53
* ECPublicKey/XECPublicKey, KeyExchange.getInstance("EC"/"XDH"), etc.).
54
*/
55
final class ECDHClientKeyExchange {
56
static final SSLConsumer ecdhHandshakeConsumer =
57
new ECDHClientKeyExchangeConsumer();
58
static final HandshakeProducer ecdhHandshakeProducer =
59
new ECDHClientKeyExchangeProducer();
60
61
static final SSLConsumer ecdheHandshakeConsumer =
62
new ECDHEClientKeyExchangeConsumer();
63
static final HandshakeProducer ecdheHandshakeProducer =
64
new ECDHEClientKeyExchangeProducer();
65
66
/**
67
* The ECDH/ECDHE/XDH ClientKeyExchange handshake message.
68
*/
69
private static final
70
class ECDHClientKeyExchangeMessage extends HandshakeMessage {
71
private final byte[] encodedPoint;
72
73
ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
74
byte[] encodedPublicKey) {
75
super(handshakeContext);
76
77
this.encodedPoint = encodedPublicKey;
78
}
79
80
ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
81
ByteBuffer m) throws IOException {
82
super(handshakeContext);
83
if (m.remaining() != 0) { // explicit PublicValueEncoding
84
this.encodedPoint = Record.getBytes8(m);
85
} else {
86
this.encodedPoint = new byte[0];
87
}
88
}
89
90
@Override
91
public SSLHandshake handshakeType() {
92
return SSLHandshake.CLIENT_KEY_EXCHANGE;
93
}
94
95
@Override
96
public int messageLength() {
97
if (encodedPoint == null || encodedPoint.length == 0) {
98
return 0;
99
} else {
100
return 1 + encodedPoint.length;
101
}
102
}
103
104
@Override
105
public void send(HandshakeOutStream hos) throws IOException {
106
if (encodedPoint != null && encodedPoint.length != 0) {
107
hos.putBytes8(encodedPoint);
108
}
109
}
110
111
@Override
112
public String toString() {
113
MessageFormat messageFormat = new MessageFormat(
114
"\"ECDH ClientKeyExchange\": '{'\n" +
115
" \"ecdh public\": '{'\n" +
116
"{0}\n" +
117
" '}',\n" +
118
"'}'",
119
Locale.ENGLISH);
120
if (encodedPoint == null || encodedPoint.length == 0) {
121
Object[] messageFields = {
122
" <implicit>"
123
};
124
return messageFormat.format(messageFields);
125
} else {
126
HexDumpEncoder hexEncoder = new HexDumpEncoder();
127
Object[] messageFields = {
128
Utilities.indent(
129
hexEncoder.encodeBuffer(encodedPoint), " "),
130
};
131
return messageFormat.format(messageFields);
132
}
133
}
134
}
135
136
/**
137
* The ECDH "ClientKeyExchange" handshake message producer.
138
*/
139
private static final
140
class ECDHClientKeyExchangeProducer implements HandshakeProducer {
141
// Prevent instantiation of this class.
142
private ECDHClientKeyExchangeProducer() {
143
// blank
144
}
145
146
@Override
147
public byte[] produce(ConnectionContext context,
148
HandshakeMessage message) throws IOException {
149
// The producing happens in client side only.
150
ClientHandshakeContext chc = (ClientHandshakeContext)context;
151
152
X509Credentials x509Credentials = null;
153
for (SSLCredentials credential : chc.handshakeCredentials) {
154
if (credential instanceof X509Credentials) {
155
x509Credentials = (X509Credentials)credential;
156
break;
157
}
158
}
159
160
if (x509Credentials == null) {
161
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
162
"No server certificate for ECDH client key exchange");
163
}
164
165
PublicKey publicKey = x509Credentials.popPublicKey;
166
167
NamedGroup namedGroup = null;
168
String algorithm = publicKey.getAlgorithm();
169
170
// Determine which NamedGroup we'll be using, then use
171
// the creator functions.
172
if (algorithm.equals("EC")) {
173
ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
174
namedGroup = NamedGroup.valueOf(params);
175
} else if (algorithm.equals("XDH")) {
176
AlgorithmParameterSpec params =
177
((XECPublicKey)publicKey).getParams();
178
if (params instanceof NamedParameterSpec) {
179
String name = ((NamedParameterSpec)params).getName();
180
namedGroup = NamedGroup.nameOf(name);
181
}
182
} else {
183
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
184
"Not EC/XDH server certificate for " +
185
"ECDH client key exchange");
186
}
187
188
if (namedGroup == null) {
189
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
190
"Unsupported EC/XDH server cert for " +
191
"ECDH client key exchange");
192
}
193
194
SSLPossession sslPossession = namedGroup.createPossession(
195
chc.sslContext.getSecureRandom());
196
197
chc.handshakePossessions.add(sslPossession);
198
ECDHClientKeyExchangeMessage cke =
199
new ECDHClientKeyExchangeMessage(
200
chc, sslPossession.encode());
201
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
202
SSLLogger.fine(
203
"Produced ECDH ClientKeyExchange handshake message", cke);
204
}
205
206
// Output the handshake message.
207
cke.write(chc.handshakeOutput);
208
chc.handshakeOutput.flush();
209
210
// update the states
211
SSLKeyExchange ke = SSLKeyExchange.valueOf(
212
chc.negotiatedCipherSuite.keyExchange,
213
chc.negotiatedProtocol);
214
if (ke == null) {
215
// unlikely
216
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
217
"Not supported key exchange type");
218
} else {
219
SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
220
SecretKey masterSecret =
221
masterKD.deriveKey("MasterSecret", null);
222
chc.handshakeSession.setMasterSecret(masterSecret);
223
224
SSLTrafficKeyDerivation kd =
225
SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
226
if (kd == null) {
227
// unlikely
228
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
229
"Not supported key derivation: " +
230
chc.negotiatedProtocol);
231
} else {
232
chc.handshakeKeyDerivation =
233
kd.createKeyDerivation(chc, masterSecret);
234
}
235
}
236
237
// The handshake message has been delivered.
238
return null;
239
}
240
}
241
242
/**
243
* The ECDH "ClientKeyExchange" handshake message consumer.
244
*/
245
private static final
246
class ECDHClientKeyExchangeConsumer implements SSLConsumer {
247
// Prevent instantiation of this class.
248
private ECDHClientKeyExchangeConsumer() {
249
// blank
250
}
251
252
@Override
253
public void consume(ConnectionContext context,
254
ByteBuffer message) throws IOException {
255
// The consuming happens in server side only.
256
ServerHandshakeContext shc = (ServerHandshakeContext)context;
257
258
X509Possession x509Possession = null;
259
for (SSLPossession possession : shc.handshakePossessions) {
260
if (possession instanceof X509Possession) {
261
x509Possession = (X509Possession)possession;
262
break;
263
}
264
}
265
266
if (x509Possession == null) {
267
// unlikely, have been checked during cipher suite negotiation.
268
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
269
"No expected EC server cert for ECDH client key exchange");
270
}
271
272
// Determine which NamedGroup we'll be using, then use
273
// the creator functions.
274
NamedGroup namedGroup = null;
275
276
// Iteratively determine the X509Possession type's ParameterSpec.
277
ECParameterSpec ecParams = x509Possession.getECParameterSpec();
278
NamedParameterSpec namedParams = null;
279
if (ecParams != null) {
280
namedGroup = NamedGroup.valueOf(ecParams);
281
}
282
283
// Wasn't EC, try XEC.
284
if (ecParams == null) {
285
namedParams = x509Possession.getXECParameterSpec();
286
namedGroup = NamedGroup.nameOf(namedParams.getName());
287
}
288
289
// Can't figure this out, bail.
290
if ((ecParams == null) && (namedParams == null)) {
291
// unlikely, have been checked during cipher suite negotiation.
292
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
293
"Not EC/XDH server cert for ECDH client key exchange");
294
}
295
296
// unlikely, have been checked during cipher suite negotiation.
297
if (namedGroup == null) {
298
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
299
"Unknown named group in server cert for " +
300
"ECDH client key exchange");
301
}
302
303
SSLKeyExchange ke = SSLKeyExchange.valueOf(
304
shc.negotiatedCipherSuite.keyExchange,
305
shc.negotiatedProtocol);
306
if (ke == null) {
307
// unlikely
308
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
309
"Not supported key exchange type");
310
}
311
312
// parse either handshake message containing either EC/XEC.
313
ECDHClientKeyExchangeMessage cke =
314
new ECDHClientKeyExchangeMessage(shc, message);
315
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
316
SSLLogger.fine(
317
"Consuming ECDH ClientKeyExchange handshake message", cke);
318
}
319
320
// create the credentials
321
try {
322
SSLCredentials sslCredentials =
323
namedGroup.decodeCredentials(cke.encodedPoint);
324
if (shc.algorithmConstraints != null &&
325
sslCredentials instanceof
326
NamedGroupCredentials namedGroupCredentials) {
327
if (!shc.algorithmConstraints.permits(
328
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
329
namedGroupCredentials.getPublicKey())) {
330
shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
331
"ClientKeyExchange for " + namedGroup +
332
" does not comply with algorithm constraints");
333
}
334
}
335
336
shc.handshakeCredentials.add(sslCredentials);
337
} catch (GeneralSecurityException e) {
338
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
339
"Cannot decode ECDH PublicKey: " + namedGroup);
340
}
341
342
// update the states
343
SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
344
SecretKey masterSecret =
345
masterKD.deriveKey("MasterSecret", null);
346
shc.handshakeSession.setMasterSecret(masterSecret);
347
348
SSLTrafficKeyDerivation kd =
349
SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
350
if (kd == null) {
351
// unlikely
352
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
353
"Not supported key derivation: " + shc.negotiatedProtocol);
354
} else {
355
shc.handshakeKeyDerivation =
356
kd.createKeyDerivation(shc, masterSecret);
357
}
358
}
359
}
360
361
/**
362
* The ECDHE "ClientKeyExchange" handshake message producer.
363
*/
364
private static final
365
class ECDHEClientKeyExchangeProducer implements HandshakeProducer {
366
// Prevent instantiation of this class.
367
private ECDHEClientKeyExchangeProducer() {
368
// blank
369
}
370
371
@Override
372
public byte[] produce(ConnectionContext context,
373
HandshakeMessage message) throws IOException {
374
// The producing happens in client side only.
375
ClientHandshakeContext chc = (ClientHandshakeContext)context;
376
377
SSLCredentials sslCredentials = null;
378
NamedGroup ng = null;
379
380
// Find a good EC/XEC credential to use, determine the
381
// NamedGroup to use for creating Possessions/Credentials/Keys.
382
for (SSLCredentials cd : chc.handshakeCredentials) {
383
if (cd instanceof NamedGroupCredentials) {
384
NamedGroupCredentials creds = (NamedGroupCredentials)cd;
385
ng = creds.getNamedGroup();
386
sslCredentials = cd;
387
break;
388
}
389
}
390
391
if (sslCredentials == null) {
392
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
393
"No ECDHE credentials negotiated for client key exchange");
394
}
395
396
SSLPossession sslPossession = ng.createPossession(
397
chc.sslContext.getSecureRandom());
398
399
chc.handshakePossessions.add(sslPossession);
400
401
// Write the EC/XEC message.
402
ECDHClientKeyExchangeMessage cke =
403
new ECDHClientKeyExchangeMessage(
404
chc, sslPossession.encode());
405
406
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
407
SSLLogger.fine(
408
"Produced ECDHE ClientKeyExchange handshake message", cke);
409
}
410
411
// Output the handshake message.
412
cke.write(chc.handshakeOutput);
413
chc.handshakeOutput.flush();
414
415
// update the states
416
SSLKeyExchange ke = SSLKeyExchange.valueOf(
417
chc.negotiatedCipherSuite.keyExchange,
418
chc.negotiatedProtocol);
419
if (ke == null) {
420
// unlikely
421
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
422
"Not supported key exchange type");
423
} else {
424
SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
425
SecretKey masterSecret =
426
masterKD.deriveKey("MasterSecret", null);
427
chc.handshakeSession.setMasterSecret(masterSecret);
428
429
SSLTrafficKeyDerivation kd =
430
SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
431
if (kd == null) {
432
// unlikely
433
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
434
"Not supported key derivation: " +
435
chc.negotiatedProtocol);
436
} else {
437
chc.handshakeKeyDerivation =
438
kd.createKeyDerivation(chc, masterSecret);
439
}
440
}
441
442
// The handshake message has been delivered.
443
return null;
444
}
445
}
446
447
/**
448
* The ECDHE "ClientKeyExchange" handshake message consumer.
449
*/
450
private static final
451
class ECDHEClientKeyExchangeConsumer implements SSLConsumer {
452
// Prevent instantiation of this class.
453
private ECDHEClientKeyExchangeConsumer() {
454
// blank
455
}
456
457
@Override
458
public void consume(ConnectionContext context,
459
ByteBuffer message) throws IOException {
460
// The consuming happens in server side only.
461
ServerHandshakeContext shc = (ServerHandshakeContext)context;
462
463
SSLPossession sslPossession = null;
464
NamedGroup namedGroup = null;
465
466
// Find a good EC/XEC credential to use, determine the
467
// NamedGroup to use for creating Possessions/Credentials/Keys.
468
for (SSLPossession possession : shc.handshakePossessions) {
469
if (possession instanceof NamedGroupPossession) {
470
NamedGroupPossession poss =
471
(NamedGroupPossession)possession;
472
namedGroup = poss.getNamedGroup();
473
sslPossession = poss;
474
break;
475
}
476
}
477
478
if (sslPossession == null) {
479
// unlikely
480
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
481
"No expected ECDHE possessions for client key exchange");
482
}
483
484
if (namedGroup == null) {
485
// unlikely, have been checked during cipher suite negotiation
486
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
487
"Unsupported EC server cert for ECDHE client key exchange");
488
}
489
490
SSLKeyExchange ke = SSLKeyExchange.valueOf(
491
shc.negotiatedCipherSuite.keyExchange,
492
shc.negotiatedProtocol);
493
if (ke == null) {
494
// unlikely
495
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
496
"Not supported key exchange type");
497
}
498
499
// parse the EC/XEC handshake message
500
ECDHClientKeyExchangeMessage cke =
501
new ECDHClientKeyExchangeMessage(shc, message);
502
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
503
SSLLogger.fine(
504
"Consuming ECDHE ClientKeyExchange handshake message", cke);
505
}
506
507
// create the credentials
508
try {
509
SSLCredentials sslCredentials =
510
namedGroup.decodeCredentials(cke.encodedPoint);
511
if (shc.algorithmConstraints != null &&
512
sslCredentials instanceof
513
NamedGroupCredentials namedGroupCredentials) {
514
if (!shc.algorithmConstraints.permits(
515
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
516
namedGroupCredentials.getPublicKey())) {
517
shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
518
"ClientKeyExchange for " + namedGroup +
519
" does not comply with algorithm constraints");
520
}
521
}
522
523
shc.handshakeCredentials.add(sslCredentials);
524
} catch (GeneralSecurityException e) {
525
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
526
"Cannot decode named group: " + namedGroup);
527
}
528
529
// update the states
530
SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
531
SecretKey masterSecret =
532
masterKD.deriveKey("MasterSecret", null);
533
shc.handshakeSession.setMasterSecret(masterSecret);
534
535
SSLTrafficKeyDerivation kd =
536
SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
537
if (kd == null) {
538
// unlikely
539
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
540
"Not supported key derivation: " + shc.negotiatedProtocol);
541
} else {
542
shc.handshakeKeyDerivation =
543
kd.createKeyDerivation(shc, masterSecret);
544
}
545
}
546
}
547
}
548
549