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