Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/DHKeyExchange.java
38830 views
1
/*
2
* Copyright (c) 2018, 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.security.GeneralSecurityException;
31
import java.security.InvalidKeyException;
32
import java.security.KeyFactory;
33
import java.security.KeyPair;
34
import java.security.KeyPairGenerator;
35
import java.security.NoSuchAlgorithmException;
36
import java.security.PrivateKey;
37
import java.security.PublicKey;
38
import java.security.SecureRandom;
39
import java.security.spec.AlgorithmParameterSpec;
40
import java.security.spec.InvalidKeySpecException;
41
import javax.crypto.KeyAgreement;
42
import javax.crypto.SecretKey;
43
import javax.crypto.interfaces.DHPublicKey;
44
import javax.crypto.spec.DHParameterSpec;
45
import javax.crypto.spec.DHPublicKeySpec;
46
import javax.crypto.spec.SecretKeySpec;
47
import javax.net.ssl.SSLHandshakeException;
48
import sun.security.action.GetPropertyAction;
49
import sun.security.ssl.CipherSuite.HashAlg;
50
import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
51
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
52
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
53
import sun.security.ssl.X509Authentication.X509Possession;
54
import sun.security.util.KeyUtil;
55
56
final class DHKeyExchange {
57
static final SSLPossessionGenerator poGenerator =
58
new DHEPossessionGenerator(false);
59
static final SSLPossessionGenerator poExportableGenerator =
60
new DHEPossessionGenerator(true);
61
static final SSLKeyAgreementGenerator kaGenerator =
62
new DHEKAGenerator();
63
64
static final class DHECredentials implements SSLCredentials {
65
final DHPublicKey popPublicKey;
66
final NamedGroup namedGroup;
67
68
DHECredentials(DHPublicKey popPublicKey, NamedGroup namedGroup) {
69
this.popPublicKey = popPublicKey;
70
this.namedGroup = namedGroup;
71
}
72
73
static DHECredentials valueOf(NamedGroup ng,
74
byte[] encodedPublic) throws IOException, GeneralSecurityException {
75
76
if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
77
throw new RuntimeException(
78
"Credentials decoding: Not FFDHE named group");
79
}
80
81
if (encodedPublic == null || encodedPublic.length == 0) {
82
return null;
83
}
84
85
DHParameterSpec params = (DHParameterSpec)ng.getParameterSpec();
86
if (params == null) {
87
return null;
88
}
89
90
KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman");
91
DHPublicKeySpec spec = new DHPublicKeySpec(
92
new BigInteger(1, encodedPublic),
93
params.getP(), params.getG());
94
DHPublicKey publicKey =
95
(DHPublicKey)kf.generatePublic(spec);
96
97
return new DHECredentials(publicKey, ng);
98
}
99
}
100
101
static final class DHEPossession implements SSLPossession {
102
final PrivateKey privateKey;
103
final DHPublicKey publicKey;
104
final NamedGroup namedGroup;
105
106
DHEPossession(NamedGroup namedGroup, SecureRandom random) {
107
try {
108
KeyPairGenerator kpg =
109
JsseJce.getKeyPairGenerator("DiffieHellman");
110
DHParameterSpec params =
111
(DHParameterSpec)namedGroup.getParameterSpec();
112
kpg.initialize(params, random);
113
KeyPair kp = generateDHKeyPair(kpg);
114
if (kp == null) {
115
throw new RuntimeException("Could not generate DH keypair");
116
}
117
privateKey = kp.getPrivate();
118
publicKey = (DHPublicKey)kp.getPublic();
119
} catch (GeneralSecurityException gse) {
120
throw new RuntimeException(
121
"Could not generate DH keypair", gse);
122
}
123
124
this.namedGroup = namedGroup;
125
}
126
127
DHEPossession(int keyLength, SecureRandom random) {
128
DHParameterSpec params =
129
PredefinedDHParameterSpecs.definedParams.get(keyLength);
130
try {
131
KeyPairGenerator kpg =
132
JsseJce.getKeyPairGenerator("DiffieHellman");
133
if (params != null) {
134
kpg.initialize(params, random);
135
} else {
136
kpg.initialize(keyLength, random);
137
}
138
139
KeyPair kp = generateDHKeyPair(kpg);
140
if (kp == null) {
141
throw new RuntimeException(
142
"Could not generate DH keypair of " +
143
keyLength + " bits");
144
}
145
privateKey = kp.getPrivate();
146
publicKey = (DHPublicKey)kp.getPublic();
147
} catch (GeneralSecurityException gse) {
148
throw new RuntimeException(
149
"Could not generate DH keypair", gse);
150
}
151
152
this.namedGroup = NamedGroup.valueOf(publicKey.getParams());
153
}
154
155
DHEPossession(DHECredentials credentials, SecureRandom random) {
156
try {
157
KeyPairGenerator kpg =
158
JsseJce.getKeyPairGenerator("DiffieHellman");
159
kpg.initialize(credentials.popPublicKey.getParams(), random);
160
KeyPair kp = generateDHKeyPair(kpg);
161
if (kp == null) {
162
throw new RuntimeException("Could not generate DH keypair");
163
}
164
privateKey = kp.getPrivate();
165
publicKey = (DHPublicKey)kp.getPublic();
166
} catch (GeneralSecurityException gse) {
167
throw new RuntimeException(
168
"Could not generate DH keypair", gse);
169
}
170
171
this.namedGroup = credentials.namedGroup;
172
}
173
174
// Generate and validate DHPublicKeySpec
175
private KeyPair generateDHKeyPair(
176
KeyPairGenerator kpg) throws GeneralSecurityException {
177
boolean doExtraValiadtion =
178
(!KeyUtil.isOracleJCEProvider(kpg.getProvider().getName()));
179
boolean isRecovering = false;
180
for (int i = 0; i <= 2; i++) { // Try to recover from failure.
181
KeyPair kp = kpg.generateKeyPair();
182
// validate the Diffie-Hellman public key
183
if (doExtraValiadtion) {
184
DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
185
try {
186
KeyUtil.validate(spec);
187
} catch (InvalidKeyException ivke) {
188
if (isRecovering) {
189
throw ivke;
190
}
191
// otherwise, ignore the exception and try again
192
isRecovering = true;
193
continue;
194
}
195
}
196
197
return kp;
198
}
199
200
return null;
201
}
202
203
private static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) {
204
if (key instanceof DHPublicKey) {
205
DHPublicKey dhKey = (DHPublicKey)key;
206
DHParameterSpec params = dhKey.getParams();
207
return new DHPublicKeySpec(dhKey.getY(),
208
params.getP(), params.getG());
209
}
210
try {
211
KeyFactory factory = JsseJce.getKeyFactory("DiffieHellman");
212
return factory.getKeySpec(key, DHPublicKeySpec.class);
213
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
214
// unlikely
215
throw new RuntimeException("Unable to get DHPublicKeySpec", e);
216
}
217
}
218
219
@Override
220
public byte[] encode() {
221
// Note: the DH public value is encoded as a big-endian integer
222
// and padded to the left with zeros to the size of p in bytes.
223
byte[] encoded = Utilities.toByteArray(publicKey.getY());
224
int pSize = (KeyUtil.getKeySize(publicKey) + 7) >>> 3;
225
if (pSize > 0 && encoded.length < pSize) {
226
byte[] buffer = new byte[pSize];
227
System.arraycopy(encoded, 0,
228
buffer, pSize - encoded.length, encoded.length);
229
encoded = buffer;
230
}
231
232
return encoded;
233
}
234
}
235
236
private static final class
237
DHEPossessionGenerator implements SSLPossessionGenerator {
238
// Flag to use smart ephemeral DH key which size matches the
239
// corresponding authentication key
240
private static final boolean useSmartEphemeralDHKeys;
241
242
// Flag to use legacy ephemeral DH key which size is 512 bits for
243
// exportable cipher suites, and 768 bits for others
244
private static final boolean useLegacyEphemeralDHKeys;
245
246
// The customized ephemeral DH key size for non-exportable
247
// cipher suites.
248
private static final int customizedDHKeySize;
249
250
// Is it for exportable cipher suite?
251
private final boolean exportable;
252
253
static {
254
String property = GetPropertyAction.privilegedGetProperty(
255
"jdk.tls.ephemeralDHKeySize");
256
if (property == null || property.isEmpty()) {
257
useLegacyEphemeralDHKeys = false;
258
useSmartEphemeralDHKeys = false;
259
customizedDHKeySize = -1;
260
} else if ("matched".equals(property)) {
261
useLegacyEphemeralDHKeys = false;
262
useSmartEphemeralDHKeys = true;
263
customizedDHKeySize = -1;
264
} else if ("legacy".equals(property)) {
265
useLegacyEphemeralDHKeys = true;
266
useSmartEphemeralDHKeys = false;
267
customizedDHKeySize = -1;
268
} else {
269
useLegacyEphemeralDHKeys = false;
270
useSmartEphemeralDHKeys = false;
271
272
try {
273
// DH parameter generation can be extremely slow, best to
274
// use one of the supported pre-computed DH parameters
275
// (see DHCrypt class).
276
customizedDHKeySize = Integer.parseUnsignedInt(property);
277
if (customizedDHKeySize < 1024 ||
278
customizedDHKeySize > 8192 ||
279
(customizedDHKeySize & 0x3f) != 0) {
280
throw new IllegalArgumentException(
281
"Unsupported customized DH key size: " +
282
customizedDHKeySize + ". " +
283
"The key size must be multiple of 64, " +
284
"and range from 1024 to 8192 (inclusive)");
285
}
286
} catch (NumberFormatException nfe) {
287
throw new IllegalArgumentException(
288
"Invalid system property jdk.tls.ephemeralDHKeySize");
289
}
290
}
291
}
292
293
// Prevent instantiation of this class.
294
private DHEPossessionGenerator(boolean exportable) {
295
this.exportable = exportable;
296
}
297
298
// Used for ServerKeyExchange, TLS 1.2 and prior versions.
299
@Override
300
public SSLPossession createPossession(HandshakeContext context) {
301
NamedGroup preferableNamedGroup = null;
302
if (!useLegacyEphemeralDHKeys &&
303
(context.clientRequestedNamedGroups != null) &&
304
(!context.clientRequestedNamedGroups.isEmpty())) {
305
preferableNamedGroup =
306
SupportedGroups.getPreferredGroup(
307
context.negotiatedProtocol,
308
context.algorithmConstraints,
309
NamedGroupType.NAMED_GROUP_FFDHE,
310
context.clientRequestedNamedGroups);
311
if (preferableNamedGroup != null) {
312
return new DHEPossession(preferableNamedGroup,
313
context.sslContext.getSecureRandom());
314
}
315
}
316
317
/*
318
* 768 bits ephemeral DH private keys were used to be used in
319
* ServerKeyExchange except that exportable ciphers max out at 512
320
* bits modulus values. We still adhere to this behavior in legacy
321
* mode (system property "jdk.tls.ephemeralDHKeySize" is defined
322
* as "legacy").
323
*
324
* Old JDK (JDK 7 and previous) releases don't support DH keys
325
* bigger than 1024 bits. We have to consider the compatibility
326
* requirement. 1024 bits DH key is always used for non-exportable
327
* cipher suites in default mode (system property
328
* "jdk.tls.ephemeralDHKeySize" is not defined).
329
*
330
* However, if applications want more stronger strength, setting
331
* system property "jdk.tls.ephemeralDHKeySize" to "matched"
332
* is a workaround to use ephemeral DH key which size matches the
333
* corresponding authentication key. For example, if the public key
334
* size of an authentication certificate is 2048 bits, then the
335
* ephemeral DH key size should be 2048 bits accordingly unless
336
* the cipher suite is exportable. This key sizing scheme keeps
337
* the cryptographic strength consistent between authentication
338
* keys and key-exchange keys.
339
*
340
* Applications may also want to customize the ephemeral DH key
341
* size to a fixed length for non-exportable cipher suites. This
342
* can be approached by setting system property
343
* "jdk.tls.ephemeralDHKeySize" to a valid positive integer between
344
* 1024 and 8192 bits, inclusive.
345
*
346
* Note that the minimum acceptable key size is 1024 bits except
347
* exportable cipher suites or legacy mode.
348
*
349
* Note that per RFC 2246, the key size limit of DH is 512 bits for
350
* exportable cipher suites. Because of the weakness, exportable
351
* cipher suites are deprecated since TLS v1.1 and they are not
352
* enabled by default in Oracle provider. The legacy behavior is
353
* reserved and 512 bits DH key is always used for exportable
354
* cipher suites.
355
*/
356
int keySize = exportable ? 512 : 1024; // default mode
357
if (!exportable) {
358
if (useLegacyEphemeralDHKeys) { // legacy mode
359
keySize = 768;
360
} else if (useSmartEphemeralDHKeys) { // matched mode
361
PrivateKey key = null;
362
ServerHandshakeContext shc =
363
(ServerHandshakeContext)context;
364
if (shc.interimAuthn instanceof X509Possession) {
365
key = ((X509Possession)shc.interimAuthn).popPrivateKey;
366
}
367
368
if (key != null) {
369
int ks = KeyUtil.getKeySize(key);
370
371
// DH parameter generation can be extremely slow, make
372
// sure to use one of the supported pre-computed DH
373
// parameters.
374
//
375
// Old deployed applications may not be ready to
376
// support DH key sizes bigger than 2048 bits. Please
377
// DON'T use value other than 1024 and 2048 at present.
378
// May improve the underlying providers and key size
379
// limit in the future when the compatibility and
380
// interoperability impact is limited.
381
keySize = ks <= 1024 ? 1024 : 2048;
382
} // Otherwise, anonymous cipher suites, 1024-bit is used.
383
} else if (customizedDHKeySize > 0) { // customized mode
384
keySize = customizedDHKeySize;
385
}
386
}
387
388
return new DHEPossession(
389
keySize, context.sslContext.getSecureRandom());
390
}
391
}
392
393
private static final
394
class DHEKAGenerator implements SSLKeyAgreementGenerator {
395
static private DHEKAGenerator instance = new DHEKAGenerator();
396
397
// Prevent instantiation of this class.
398
private DHEKAGenerator() {
399
// blank
400
}
401
402
@Override
403
public SSLKeyDerivation createKeyDerivation(
404
HandshakeContext context) throws IOException {
405
DHEPossession dhePossession = null;
406
DHECredentials dheCredentials = null;
407
for (SSLPossession poss : context.handshakePossessions) {
408
if (!(poss instanceof DHEPossession)) {
409
continue;
410
}
411
412
DHEPossession dhep = (DHEPossession)poss;
413
for (SSLCredentials cred : context.handshakeCredentials) {
414
if (!(cred instanceof DHECredentials)) {
415
continue;
416
}
417
DHECredentials dhec = (DHECredentials)cred;
418
if (dhep.namedGroup != null && dhec.namedGroup != null) {
419
if (dhep.namedGroup.equals(dhec.namedGroup)) {
420
dheCredentials = (DHECredentials)cred;
421
break;
422
}
423
} else {
424
DHParameterSpec pps = dhep.publicKey.getParams();
425
DHParameterSpec cps = dhec.popPublicKey.getParams();
426
if (pps.getP().equals(cps.getP()) &&
427
pps.getG().equals(cps.getG())) {
428
dheCredentials = (DHECredentials)cred;
429
break;
430
}
431
}
432
}
433
434
if (dheCredentials != null) {
435
dhePossession = (DHEPossession)poss;
436
break;
437
}
438
}
439
440
if (dhePossession == null || dheCredentials == null) {
441
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
442
"No sufficient DHE key agreement parameters negotiated");
443
}
444
445
return new DHEKAKeyDerivation(context,
446
dhePossession.privateKey, dheCredentials.popPublicKey);
447
}
448
449
private static final
450
class DHEKAKeyDerivation implements SSLKeyDerivation {
451
private final HandshakeContext context;
452
private final PrivateKey localPrivateKey;
453
private final PublicKey peerPublicKey;
454
455
DHEKAKeyDerivation(HandshakeContext context,
456
PrivateKey localPrivateKey,
457
PublicKey peerPublicKey) {
458
this.context = context;
459
this.localPrivateKey = localPrivateKey;
460
this.peerPublicKey = peerPublicKey;
461
}
462
463
@Override
464
public SecretKey deriveKey(String algorithm,
465
AlgorithmParameterSpec params) throws IOException {
466
if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
467
return t12DeriveKey(algorithm, params);
468
} else {
469
return t13DeriveKey(algorithm, params);
470
}
471
}
472
473
private SecretKey t12DeriveKey(String algorithm,
474
AlgorithmParameterSpec params) throws IOException {
475
try {
476
KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
477
ka.init(localPrivateKey);
478
ka.doPhase(peerPublicKey, true);
479
SecretKey preMasterSecret =
480
ka.generateSecret("TlsPremasterSecret");
481
SSLMasterKeyDerivation mskd =
482
SSLMasterKeyDerivation.valueOf(
483
context.negotiatedProtocol);
484
if (mskd == null) {
485
// unlikely
486
throw new SSLHandshakeException(
487
"No expected master key derivation for protocol: " +
488
context.negotiatedProtocol.name);
489
}
490
SSLKeyDerivation kd = mskd.createKeyDerivation(
491
context, preMasterSecret);
492
return kd.deriveKey("MasterSecret", params);
493
} catch (GeneralSecurityException gse) {
494
throw (SSLHandshakeException) new SSLHandshakeException(
495
"Could not generate secret").initCause(gse);
496
}
497
}
498
499
private SecretKey t13DeriveKey(String algorithm,
500
AlgorithmParameterSpec params) throws IOException {
501
try {
502
KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
503
ka.init(localPrivateKey);
504
ka.doPhase(peerPublicKey, true);
505
SecretKey sharedSecret =
506
ka.generateSecret("TlsPremasterSecret");
507
508
HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
509
SSLKeyDerivation kd = context.handshakeKeyDerivation;
510
HKDF hkdf = new HKDF(hashAlg.name);
511
if (kd == null) { // No PSK is in use.
512
// If PSK is not in use Early Secret will still be
513
// HKDF-Extract(0, 0).
514
byte[] zeros = new byte[hashAlg.hashLength];
515
SecretKeySpec ikm =
516
new SecretKeySpec(zeros, "TlsPreSharedSecret");
517
SecretKey earlySecret =
518
hkdf.extract(zeros, ikm, "TlsEarlySecret");
519
kd = new SSLSecretDerivation(context, earlySecret);
520
}
521
522
// derive salt secret
523
SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
524
525
// derive handshake secret
526
return hkdf.extract(saltSecret, sharedSecret, algorithm);
527
} catch (GeneralSecurityException gse) {
528
throw (SSLHandshakeException) new SSLHandshakeException(
529
"Could not generate secret").initCause(gse);
530
}
531
}
532
}
533
}
534
}
535
536