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/ECDHServerKeyExchange.java
67770 views
1
/*
2
* Copyright (c) 2015, 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.InvalidAlgorithmParameterException;
33
import java.security.InvalidKeyException;
34
import java.security.Key;
35
import java.security.NoSuchAlgorithmException;
36
import java.security.PrivateKey;
37
import java.security.PublicKey;
38
import java.security.Signature;
39
import java.security.SignatureException;
40
import java.text.MessageFormat;
41
import java.util.EnumSet;
42
import java.util.Locale;
43
import java.util.Map;
44
import sun.security.ssl.SSLHandshake.HandshakeMessage;
45
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
46
import sun.security.ssl.X509Authentication.X509Credentials;
47
import sun.security.ssl.X509Authentication.X509Possession;
48
import sun.security.util.HexDumpEncoder;
49
50
/**
51
* Pack of the ServerKeyExchange handshake message.
52
*/
53
final class ECDHServerKeyExchange {
54
static final SSLConsumer ecdheHandshakeConsumer =
55
new ECDHServerKeyExchangeConsumer();
56
static final HandshakeProducer ecdheHandshakeProducer =
57
new ECDHServerKeyExchangeProducer();
58
59
/**
60
* The ECDH ServerKeyExchange handshake message.
61
*/
62
private static final
63
class ECDHServerKeyExchangeMessage extends HandshakeMessage {
64
private static final byte CURVE_NAMED_CURVE = (byte)0x03;
65
66
// id of the named curve
67
private final NamedGroup namedGroup;
68
69
// encoded public point
70
private final byte[] publicPoint;
71
72
// signature bytes, or null if anonymous
73
private final byte[] paramsSignature;
74
75
private final boolean useExplicitSigAlgorithm;
76
77
// the signature algorithm used by this ServerKeyExchange message
78
private final SignatureScheme signatureScheme;
79
80
// the parsed credential object
81
private SSLCredentials sslCredentials;
82
83
ECDHServerKeyExchangeMessage(
84
HandshakeContext handshakeContext) throws IOException {
85
super(handshakeContext);
86
87
// This happens in server side only.
88
ServerHandshakeContext shc =
89
(ServerHandshakeContext)handshakeContext;
90
91
// Find the Possessions needed
92
NamedGroupPossession namedGroupPossession = null;
93
X509Possession x509Possession = null;
94
for (SSLPossession possession : shc.handshakePossessions) {
95
if (possession instanceof NamedGroupPossession) {
96
namedGroupPossession = (NamedGroupPossession)possession;
97
if (x509Possession != null) {
98
break;
99
}
100
} else if (possession instanceof X509Possession) {
101
x509Possession = (X509Possession)possession;
102
if (namedGroupPossession != null) {
103
break;
104
}
105
}
106
}
107
108
if (namedGroupPossession == null) {
109
// unlikely
110
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
111
"No ECDHE credentials negotiated for server key exchange");
112
}
113
114
// Find the NamedGroup used for the ephemeral keys.
115
namedGroup = namedGroupPossession.getNamedGroup();
116
if ((namedGroup == null) || (!namedGroup.isAvailable)) {
117
// unlikely
118
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
119
"Missing or improper named group: " + namedGroup);
120
}
121
122
publicPoint = namedGroup.encodePossessionPublicKey(
123
namedGroupPossession);
124
if (publicPoint == null) {
125
// unlikely
126
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
127
"Missing public point for named group: " + namedGroup);
128
}
129
130
if (x509Possession == null) {
131
// anonymous, no authentication, no signature
132
paramsSignature = null;
133
signatureScheme = null;
134
useExplicitSigAlgorithm = false;
135
} else {
136
useExplicitSigAlgorithm =
137
shc.negotiatedProtocol.useTLS12PlusSpec();
138
Signature signer;
139
if (useExplicitSigAlgorithm) {
140
Map.Entry<SignatureScheme, Signature> schemeAndSigner =
141
SignatureScheme.getSignerOfPreferableAlgorithm(
142
shc.algorithmConstraints,
143
shc.peerRequestedSignatureSchemes,
144
x509Possession,
145
shc.negotiatedProtocol);
146
if (schemeAndSigner == null) {
147
// Unlikely, the credentials generator should have
148
// selected the preferable signature algorithm properly.
149
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
150
"No supported signature algorithm for " +
151
x509Possession.popPrivateKey.getAlgorithm() +
152
" key");
153
} else {
154
signatureScheme = schemeAndSigner.getKey();
155
signer = schemeAndSigner.getValue();
156
}
157
} else {
158
signatureScheme = null;
159
try {
160
signer = getSignature(
161
x509Possession.popPrivateKey.getAlgorithm(),
162
x509Possession.popPrivateKey);
163
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
164
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
165
"Unsupported signature algorithm: " +
166
x509Possession.popPrivateKey.getAlgorithm(), e);
167
}
168
}
169
170
byte[] signature;
171
try {
172
updateSignature(signer, shc.clientHelloRandom.randomBytes,
173
shc.serverHelloRandom.randomBytes,
174
namedGroup.id, publicPoint);
175
signature = signer.sign();
176
} catch (SignatureException ex) {
177
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
178
"Failed to sign ecdhe parameters: " +
179
x509Possession.popPrivateKey.getAlgorithm(), ex);
180
}
181
paramsSignature = signature;
182
}
183
}
184
185
ECDHServerKeyExchangeMessage(HandshakeContext handshakeContext,
186
ByteBuffer m) throws IOException {
187
super(handshakeContext);
188
189
// This happens in client side only.
190
ClientHandshakeContext chc =
191
(ClientHandshakeContext)handshakeContext;
192
193
byte curveType = (byte)Record.getInt8(m);
194
if (curveType != CURVE_NAMED_CURVE) {
195
// Unlikely as only the named curves should be negotiated.
196
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
197
"Unsupported ECCurveType: " + curveType);
198
}
199
200
int namedGroupId = Record.getInt16(m);
201
this.namedGroup = NamedGroup.valueOf(namedGroupId);
202
if (namedGroup == null) {
203
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
204
"Unknown named group ID: " + namedGroupId);
205
}
206
207
if (!SupportedGroups.isSupported(namedGroup)) {
208
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
209
"Unsupported named group: " + namedGroup);
210
}
211
212
publicPoint = Record.getBytes8(m);
213
if (publicPoint.length == 0) {
214
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
215
"Insufficient Point data: " + namedGroup);
216
}
217
218
try {
219
sslCredentials =
220
namedGroup.decodeCredentials(publicPoint);
221
if (handshakeContext.algorithmConstraints != null &&
222
sslCredentials instanceof
223
NamedGroupCredentials namedGroupCredentials) {
224
if (!handshakeContext.algorithmConstraints.permits(
225
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
226
namedGroupCredentials.getPublicKey())) {
227
chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
228
"ServerKeyExchange for " + namedGroup +
229
" does not comply with algorithm constraints");
230
}
231
}
232
} catch (GeneralSecurityException ex) {
233
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
234
"Cannot decode named group: " +
235
NamedGroup.nameOf(namedGroupId));
236
}
237
238
X509Credentials x509Credentials = null;
239
for (SSLCredentials cd : chc.handshakeCredentials) {
240
if (cd instanceof X509Credentials) {
241
x509Credentials = (X509Credentials)cd;
242
break;
243
}
244
}
245
246
if (x509Credentials == null) {
247
// anonymous, no authentication, no signature
248
if (m.hasRemaining()) {
249
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
250
"Invalid DH ServerKeyExchange: unknown extra data");
251
}
252
this.signatureScheme = null;
253
this.paramsSignature = null;
254
this.useExplicitSigAlgorithm = false;
255
256
return;
257
}
258
259
this.useExplicitSigAlgorithm =
260
chc.negotiatedProtocol.useTLS12PlusSpec();
261
if (useExplicitSigAlgorithm) {
262
int ssid = Record.getInt16(m);
263
signatureScheme = SignatureScheme.valueOf(ssid);
264
if (signatureScheme == null) {
265
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
266
"Invalid signature algorithm (" + ssid +
267
") used in ECDH ServerKeyExchange handshake message");
268
}
269
270
if (!chc.localSupportedSignAlgs.contains(signatureScheme)) {
271
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
272
"Unsupported signature algorithm (" +
273
signatureScheme.name +
274
") used in ECDH ServerKeyExchange handshake message");
275
}
276
} else {
277
signatureScheme = null;
278
}
279
280
// read and verify the signature
281
paramsSignature = Record.getBytes16(m);
282
Signature signer;
283
if (useExplicitSigAlgorithm) {
284
try {
285
signer = signatureScheme.getVerifier(
286
x509Credentials.popPublicKey);
287
} catch (NoSuchAlgorithmException | InvalidKeyException |
288
InvalidAlgorithmParameterException nsae) {
289
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
290
"Unsupported signature algorithm: " +
291
signatureScheme.name, nsae);
292
}
293
} else {
294
try {
295
signer = getSignature(
296
x509Credentials.popPublicKey.getAlgorithm(),
297
x509Credentials.popPublicKey);
298
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
299
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
300
"Unsupported signature algorithm: " +
301
x509Credentials.popPublicKey.getAlgorithm(), e);
302
}
303
}
304
305
try {
306
updateSignature(signer,
307
chc.clientHelloRandom.randomBytes,
308
chc.serverHelloRandom.randomBytes,
309
namedGroup.id, publicPoint);
310
311
if (!signer.verify(paramsSignature)) {
312
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
313
"Invalid ECDH ServerKeyExchange signature");
314
}
315
} catch (SignatureException ex) {
316
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
317
"Cannot verify ECDH ServerKeyExchange signature", ex);
318
}
319
}
320
321
@Override
322
public SSLHandshake handshakeType() {
323
return SSLHandshake.SERVER_KEY_EXCHANGE;
324
}
325
326
@Override
327
public int messageLength() {
328
int sigLen = 0;
329
if (paramsSignature != null) {
330
sigLen = 2 + paramsSignature.length;
331
if (useExplicitSigAlgorithm) {
332
sigLen += SignatureScheme.sizeInRecord();
333
}
334
}
335
336
return 4 + publicPoint.length + sigLen;
337
}
338
339
@Override
340
public void send(HandshakeOutStream hos) throws IOException {
341
hos.putInt8(CURVE_NAMED_CURVE);
342
hos.putInt16(namedGroup.id);
343
hos.putBytes8(publicPoint);
344
if (paramsSignature != null) {
345
if (useExplicitSigAlgorithm) {
346
hos.putInt16(signatureScheme.id);
347
}
348
349
hos.putBytes16(paramsSignature);
350
}
351
}
352
353
@Override
354
public String toString() {
355
if (useExplicitSigAlgorithm) {
356
MessageFormat messageFormat = new MessageFormat(
357
"\"ECDH ServerKeyExchange\": '{'\n" +
358
" \"parameters\": '{'\n" +
359
" \"named group\": \"{0}\"\n" +
360
" \"ecdh public\": '{'\n" +
361
"{1}\n" +
362
" '}',\n" +
363
" '}',\n" +
364
" \"digital signature\": '{'\n" +
365
" \"signature algorithm\": \"{2}\"\n" +
366
" \"signature\": '{'\n" +
367
"{3}\n" +
368
" '}',\n" +
369
" '}'\n" +
370
"'}'",
371
Locale.ENGLISH);
372
373
HexDumpEncoder hexEncoder = new HexDumpEncoder();
374
Object[] messageFields = {
375
namedGroup.name,
376
Utilities.indent(
377
hexEncoder.encodeBuffer(publicPoint), " "),
378
signatureScheme.name,
379
Utilities.indent(
380
hexEncoder.encodeBuffer(paramsSignature), " ")
381
};
382
return messageFormat.format(messageFields);
383
} else if (paramsSignature != null) {
384
MessageFormat messageFormat = new MessageFormat(
385
"\"ECDH ServerKeyExchange\": '{'\n" +
386
" \"parameters\": '{'\n" +
387
" \"named group\": \"{0}\"\n" +
388
" \"ecdh public\": '{'\n" +
389
"{1}\n" +
390
" '}',\n" +
391
" '}',\n" +
392
" \"signature\": '{'\n" +
393
"{2}\n" +
394
" '}'\n" +
395
"'}'",
396
Locale.ENGLISH);
397
398
HexDumpEncoder hexEncoder = new HexDumpEncoder();
399
Object[] messageFields = {
400
namedGroup.name,
401
Utilities.indent(
402
hexEncoder.encodeBuffer(publicPoint), " "),
403
Utilities.indent(
404
hexEncoder.encodeBuffer(paramsSignature), " ")
405
};
406
407
return messageFormat.format(messageFields);
408
} else { // anonymous
409
MessageFormat messageFormat = new MessageFormat(
410
"\"ECDH ServerKeyExchange\": '{'\n" +
411
" \"parameters\": '{'\n" +
412
" \"named group\": \"{0}\"\n" +
413
" \"ecdh public\": '{'\n" +
414
"{1}\n" +
415
" '}',\n" +
416
" '}'\n" +
417
"'}'",
418
Locale.ENGLISH);
419
420
HexDumpEncoder hexEncoder = new HexDumpEncoder();
421
Object[] messageFields = {
422
namedGroup.name,
423
Utilities.indent(
424
hexEncoder.encodeBuffer(publicPoint), " "),
425
};
426
427
return messageFormat.format(messageFields);
428
}
429
}
430
431
private static Signature getSignature(String keyAlgorithm,
432
Key key) throws NoSuchAlgorithmException, InvalidKeyException {
433
Signature signer;
434
switch (keyAlgorithm) {
435
case "EC":
436
signer = Signature.getInstance(JsseJce.SIGNATURE_ECDSA);
437
break;
438
case "EdDSA":
439
signer = Signature.getInstance(JsseJce.SIGNATURE_EDDSA);
440
break;
441
case "RSA":
442
signer = RSASignature.getInstance();
443
break;
444
default:
445
throw new NoSuchAlgorithmException(
446
"neither an RSA or a EC key : " + keyAlgorithm);
447
}
448
449
if (signer != null) {
450
if (key instanceof PublicKey) {
451
signer.initVerify((PublicKey)(key));
452
} else {
453
signer.initSign((PrivateKey)key);
454
}
455
}
456
457
return signer;
458
}
459
460
private static void updateSignature(Signature sig,
461
byte[] clntNonce, byte[] svrNonce, int namedGroupId,
462
byte[] publicPoint) throws SignatureException {
463
sig.update(clntNonce);
464
sig.update(svrNonce);
465
466
sig.update(CURVE_NAMED_CURVE);
467
sig.update((byte)((namedGroupId >> 8) & 0xFF));
468
sig.update((byte)(namedGroupId & 0xFF));
469
sig.update((byte)publicPoint.length);
470
sig.update(publicPoint);
471
}
472
}
473
474
/**
475
* The ECDH "ServerKeyExchange" handshake message producer.
476
*/
477
private static final
478
class ECDHServerKeyExchangeProducer implements HandshakeProducer {
479
// Prevent instantiation of this class.
480
private ECDHServerKeyExchangeProducer() {
481
// blank
482
}
483
484
@Override
485
public byte[] produce(ConnectionContext context,
486
HandshakeMessage message) throws IOException {
487
// The producing happens in server side only.
488
ServerHandshakeContext shc = (ServerHandshakeContext)context;
489
ECDHServerKeyExchangeMessage skem =
490
new ECDHServerKeyExchangeMessage(shc);
491
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
492
SSLLogger.fine(
493
"Produced ECDH ServerKeyExchange handshake message", skem);
494
}
495
496
// Output the handshake message.
497
skem.write(shc.handshakeOutput);
498
shc.handshakeOutput.flush();
499
500
// The handshake message has been delivered.
501
return null;
502
}
503
}
504
505
/**
506
* The ECDH "ServerKeyExchange" handshake message consumer.
507
*/
508
private static final
509
class ECDHServerKeyExchangeConsumer implements SSLConsumer {
510
// Prevent instantiation of this class.
511
private ECDHServerKeyExchangeConsumer() {
512
// blank
513
}
514
515
@Override
516
public void consume(ConnectionContext context,
517
ByteBuffer message) throws IOException {
518
// The consuming happens in client side only.
519
ClientHandshakeContext chc = (ClientHandshakeContext)context;
520
521
// AlgorithmConstraints are checked during decoding
522
ECDHServerKeyExchangeMessage skem =
523
new ECDHServerKeyExchangeMessage(chc, message);
524
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
525
SSLLogger.fine(
526
"Consuming ECDH ServerKeyExchange handshake message", skem);
527
}
528
529
//
530
// update
531
//
532
chc.handshakeCredentials.add(skem.sslCredentials);
533
534
//
535
// produce
536
//
537
// Need no new handshake message producers here.
538
}
539
}
540
}
541
542
543