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