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