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