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/ECDHKeyExchange.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.security.AlgorithmConstraints;
30
import java.security.CryptoPrimitive;
31
import java.security.GeneralSecurityException;
32
import java.security.KeyFactory;
33
import java.security.KeyPair;
34
import java.security.KeyPairGenerator;
35
import java.security.PrivateKey;
36
import java.security.PublicKey;
37
import java.security.SecureRandom;
38
import java.security.interfaces.ECPublicKey;
39
import java.security.spec.ECParameterSpec;
40
import java.security.spec.ECPoint;
41
import java.security.spec.ECPublicKeySpec;
42
import java.util.EnumSet;
43
import javax.crypto.KeyAgreement;
44
import javax.crypto.SecretKey;
45
import javax.net.ssl.SSLHandshakeException;
46
import sun.security.ssl.NamedGroup.NamedGroupSpec;
47
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
48
import sun.security.ssl.X509Authentication.X509Credentials;
49
import sun.security.ssl.X509Authentication.X509Possession;
50
import sun.security.ssl.XDHKeyExchange.XDHECredentials;
51
import sun.security.ssl.XDHKeyExchange.XDHEPossession;
52
import sun.security.util.ECUtil;
53
54
final class ECDHKeyExchange {
55
static final SSLPossessionGenerator poGenerator =
56
new ECDHEPossessionGenerator();
57
static final SSLKeyAgreementGenerator ecdhKAGenerator =
58
new ECDHKAGenerator();
59
60
// TLSv1.3
61
static final SSLKeyAgreementGenerator ecdheKAGenerator =
62
new ECDHEKAGenerator();
63
64
// TLSv1-1.2, the KA gets more difficult with EC/XEC keys
65
static final SSLKeyAgreementGenerator ecdheXdhKAGenerator =
66
new ECDHEXDHKAGenerator();
67
68
static final class ECDHECredentials implements NamedGroupCredentials {
69
final ECPublicKey popPublicKey;
70
final NamedGroup namedGroup;
71
72
ECDHECredentials(ECPublicKey popPublicKey, NamedGroup namedGroup) {
73
this.popPublicKey = popPublicKey;
74
this.namedGroup = namedGroup;
75
}
76
77
@Override
78
public PublicKey getPublicKey() {
79
return popPublicKey;
80
}
81
82
@Override
83
public NamedGroup getNamedGroup() {
84
return namedGroup;
85
}
86
87
static ECDHECredentials valueOf(NamedGroup namedGroup,
88
byte[] encodedPoint) throws IOException, GeneralSecurityException {
89
90
if (namedGroup.spec != NamedGroupSpec.NAMED_GROUP_ECDHE) {
91
throw new RuntimeException(
92
"Credentials decoding: Not ECDHE named group");
93
}
94
95
if (encodedPoint == null || encodedPoint.length == 0) {
96
return null;
97
}
98
99
ECParameterSpec parameters =
100
(ECParameterSpec)namedGroup.keAlgParamSpec;
101
ECPoint point = ECUtil.decodePoint(
102
encodedPoint, parameters.getCurve());
103
KeyFactory factory = KeyFactory.getInstance("EC");
104
ECPublicKey publicKey = (ECPublicKey)factory.generatePublic(
105
new ECPublicKeySpec(point, parameters));
106
return new ECDHECredentials(publicKey, namedGroup);
107
}
108
}
109
110
static final class ECDHEPossession implements NamedGroupPossession {
111
final PrivateKey privateKey;
112
final ECPublicKey publicKey;
113
final NamedGroup namedGroup;
114
115
ECDHEPossession(NamedGroup namedGroup, SecureRandom random) {
116
try {
117
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
118
kpg.initialize(namedGroup.keAlgParamSpec, random);
119
KeyPair kp = kpg.generateKeyPair();
120
privateKey = kp.getPrivate();
121
publicKey = (ECPublicKey)kp.getPublic();
122
} catch (GeneralSecurityException e) {
123
throw new RuntimeException(
124
"Could not generate ECDH keypair", e);
125
}
126
127
this.namedGroup = namedGroup;
128
}
129
130
ECDHEPossession(ECDHECredentials credentials, SecureRandom random) {
131
ECParameterSpec params = credentials.popPublicKey.getParams();
132
try {
133
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
134
kpg.initialize(params, random);
135
KeyPair kp = kpg.generateKeyPair();
136
privateKey = kp.getPrivate();
137
publicKey = (ECPublicKey)kp.getPublic();
138
} catch (GeneralSecurityException e) {
139
throw new RuntimeException(
140
"Could not generate ECDH keypair", e);
141
}
142
143
this.namedGroup = credentials.namedGroup;
144
}
145
146
@Override
147
public byte[] encode() {
148
return ECUtil.encodePoint(
149
publicKey.getW(), publicKey.getParams().getCurve());
150
}
151
152
// called by ClientHandshaker with either the server's static or
153
// ephemeral public key
154
SecretKey getAgreedSecret(
155
PublicKey peerPublicKey) throws SSLHandshakeException {
156
157
try {
158
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
159
ka.init(privateKey);
160
ka.doPhase(peerPublicKey, true);
161
return ka.generateSecret("TlsPremasterSecret");
162
} catch (GeneralSecurityException e) {
163
throw (SSLHandshakeException) new SSLHandshakeException(
164
"Could not generate secret").initCause(e);
165
}
166
}
167
168
// called by ServerHandshaker
169
SecretKey getAgreedSecret(
170
byte[] encodedPoint) throws SSLHandshakeException {
171
try {
172
ECParameterSpec params = publicKey.getParams();
173
ECPoint point =
174
ECUtil.decodePoint(encodedPoint, params.getCurve());
175
KeyFactory kf = KeyFactory.getInstance("EC");
176
ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
177
PublicKey peerPublicKey = kf.generatePublic(spec);
178
return getAgreedSecret(peerPublicKey);
179
} catch (GeneralSecurityException | java.io.IOException e) {
180
throw (SSLHandshakeException) new SSLHandshakeException(
181
"Could not generate secret").initCause(e);
182
}
183
}
184
185
// Check constraints of the specified EC public key.
186
void checkConstraints(AlgorithmConstraints constraints,
187
byte[] encodedPoint) throws SSLHandshakeException {
188
try {
189
190
ECParameterSpec params = publicKey.getParams();
191
ECPoint point =
192
ECUtil.decodePoint(encodedPoint, params.getCurve());
193
ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
194
195
KeyFactory kf = KeyFactory.getInstance("EC");
196
ECPublicKey pubKey = (ECPublicKey)kf.generatePublic(spec);
197
198
// check constraints of ECPublicKey
199
if (!constraints.permits(
200
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), pubKey)) {
201
throw new SSLHandshakeException(
202
"ECPublicKey does not comply to algorithm constraints");
203
}
204
} catch (GeneralSecurityException | java.io.IOException e) {
205
throw (SSLHandshakeException) new SSLHandshakeException(
206
"Could not generate ECPublicKey").initCause(e);
207
}
208
}
209
210
@Override
211
public PublicKey getPublicKey() {
212
return publicKey;
213
}
214
215
@Override
216
public NamedGroup getNamedGroup() {
217
return namedGroup;
218
}
219
220
@Override
221
public PrivateKey getPrivateKey() {
222
return privateKey;
223
}
224
}
225
226
private static final
227
class ECDHEPossessionGenerator implements SSLPossessionGenerator {
228
// Prevent instantiation of this class.
229
private ECDHEPossessionGenerator() {
230
// blank
231
}
232
233
@Override
234
public SSLPossession createPossession(HandshakeContext context) {
235
236
NamedGroup preferableNamedGroup;
237
238
// Find most preferred EC or XEC groups
239
if ((context.clientRequestedNamedGroups != null) &&
240
(!context.clientRequestedNamedGroups.isEmpty())) {
241
preferableNamedGroup = SupportedGroups.getPreferredGroup(
242
context.negotiatedProtocol,
243
context.algorithmConstraints,
244
new NamedGroupSpec[] {
245
NamedGroupSpec.NAMED_GROUP_ECDHE,
246
NamedGroupSpec.NAMED_GROUP_XDH },
247
context.clientRequestedNamedGroups);
248
} else {
249
preferableNamedGroup = SupportedGroups.getPreferredGroup(
250
context.negotiatedProtocol,
251
context.algorithmConstraints,
252
new NamedGroupSpec[] {
253
NamedGroupSpec.NAMED_GROUP_ECDHE,
254
NamedGroupSpec.NAMED_GROUP_XDH });
255
}
256
257
if (preferableNamedGroup != null) {
258
return preferableNamedGroup.createPossession(
259
context.sslContext.getSecureRandom());
260
}
261
262
// no match found, cannot use this cipher suite.
263
//
264
return null;
265
}
266
}
267
268
private static final
269
class ECDHKAGenerator implements SSLKeyAgreementGenerator {
270
// Prevent instantiation of this class.
271
private ECDHKAGenerator() {
272
// blank
273
}
274
275
@Override
276
public SSLKeyDerivation createKeyDerivation(
277
HandshakeContext context) throws IOException {
278
if (context instanceof ServerHandshakeContext) {
279
return createServerKeyDerivation(
280
(ServerHandshakeContext)context);
281
} else {
282
return createClientKeyDerivation(
283
(ClientHandshakeContext)context);
284
}
285
}
286
287
private SSLKeyDerivation createServerKeyDerivation(
288
ServerHandshakeContext shc) throws IOException {
289
X509Possession x509Possession = null;
290
ECDHECredentials ecdheCredentials = null;
291
for (SSLPossession poss : shc.handshakePossessions) {
292
if (!(poss instanceof X509Possession)) {
293
continue;
294
}
295
296
ECParameterSpec params =
297
((X509Possession)poss).getECParameterSpec();
298
if (params == null) {
299
continue;
300
}
301
302
NamedGroup ng = NamedGroup.valueOf(params);
303
if (ng == null) {
304
// unlikely, have been checked during cipher suite
305
// negotiation.
306
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
307
"Unsupported EC server cert for ECDH key exchange");
308
}
309
310
for (SSLCredentials cred : shc.handshakeCredentials) {
311
if (!(cred instanceof ECDHECredentials)) {
312
continue;
313
}
314
if (ng.equals(((ECDHECredentials)cred).namedGroup)) {
315
ecdheCredentials = (ECDHECredentials)cred;
316
break;
317
}
318
}
319
320
if (ecdheCredentials != null) {
321
x509Possession = (X509Possession)poss;
322
break;
323
}
324
}
325
326
if (x509Possession == null || ecdheCredentials == null) {
327
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
328
"No sufficient ECDHE key agreement parameters negotiated");
329
}
330
331
return new KAKeyDerivation("ECDH", shc,
332
x509Possession.popPrivateKey, ecdheCredentials.popPublicKey);
333
}
334
335
private SSLKeyDerivation createClientKeyDerivation(
336
ClientHandshakeContext chc) throws IOException {
337
ECDHEPossession ecdhePossession = null;
338
X509Credentials x509Credentials = null;
339
for (SSLPossession poss : chc.handshakePossessions) {
340
if (!(poss instanceof ECDHEPossession)) {
341
continue;
342
}
343
344
NamedGroup ng = ((ECDHEPossession)poss).namedGroup;
345
for (SSLCredentials cred : chc.handshakeCredentials) {
346
if (!(cred instanceof X509Credentials)) {
347
continue;
348
}
349
350
PublicKey publicKey = ((X509Credentials)cred).popPublicKey;
351
if (!publicKey.getAlgorithm().equals("EC")) {
352
continue;
353
}
354
ECParameterSpec params =
355
((ECPublicKey)publicKey).getParams();
356
NamedGroup namedGroup = NamedGroup.valueOf(params);
357
if (namedGroup == null) {
358
// unlikely, should have been checked previously
359
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
360
"Unsupported EC server cert for ECDH key exchange");
361
}
362
363
if (ng.equals(namedGroup)) {
364
x509Credentials = (X509Credentials)cred;
365
break;
366
}
367
}
368
369
if (x509Credentials != null) {
370
ecdhePossession = (ECDHEPossession)poss;
371
break;
372
}
373
}
374
375
if (ecdhePossession == null || x509Credentials == null) {
376
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
377
"No sufficient ECDH key agreement parameters negotiated");
378
}
379
380
return new KAKeyDerivation("ECDH", chc,
381
ecdhePossession.privateKey, x509Credentials.popPublicKey);
382
}
383
}
384
385
private static final
386
class ECDHEKAGenerator implements SSLKeyAgreementGenerator {
387
// Prevent instantiation of this class.
388
private ECDHEKAGenerator() {
389
// blank
390
}
391
392
@Override
393
public SSLKeyDerivation createKeyDerivation(
394
HandshakeContext context) throws IOException {
395
ECDHEPossession ecdhePossession = null;
396
ECDHECredentials ecdheCredentials = null;
397
for (SSLPossession poss : context.handshakePossessions) {
398
if (!(poss instanceof ECDHEPossession)) {
399
continue;
400
}
401
402
NamedGroup ng = ((ECDHEPossession)poss).namedGroup;
403
for (SSLCredentials cred : context.handshakeCredentials) {
404
if (!(cred instanceof ECDHECredentials)) {
405
continue;
406
}
407
if (ng.equals(((ECDHECredentials)cred).namedGroup)) {
408
ecdheCredentials = (ECDHECredentials)cred;
409
break;
410
}
411
}
412
413
if (ecdheCredentials != null) {
414
ecdhePossession = (ECDHEPossession)poss;
415
break;
416
}
417
}
418
419
if (ecdhePossession == null || ecdheCredentials == null) {
420
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
421
"No sufficient ECDHE key agreement parameters negotiated");
422
}
423
424
return new KAKeyDerivation("ECDH", context,
425
ecdhePossession.privateKey, ecdheCredentials.popPublicKey);
426
}
427
}
428
429
/*
430
* A Generator for TLSv1-1.2 to create a ECDHE or a XDH KeyDerivation
431
* object depending on the negotiated group.
432
*/
433
private static final
434
class ECDHEXDHKAGenerator implements SSLKeyAgreementGenerator {
435
// Prevent instantiation of this class.
436
private ECDHEXDHKAGenerator() {
437
// blank
438
}
439
440
@Override
441
public SSLKeyDerivation createKeyDerivation(
442
HandshakeContext context) throws IOException {
443
444
NamedGroupPossession namedGroupPossession = null;
445
NamedGroupCredentials namedGroupCredentials = null;
446
NamedGroup namedGroup = null;
447
448
// Find a possession/credential combo using the same named group
449
search:
450
for (SSLPossession poss : context.handshakePossessions) {
451
for (SSLCredentials cred : context.handshakeCredentials) {
452
if (((poss instanceof ECDHEPossession) &&
453
(cred instanceof ECDHECredentials)) ||
454
(((poss instanceof XDHEPossession) &&
455
(cred instanceof XDHECredentials)))) {
456
NamedGroupPossession p = (NamedGroupPossession)poss;
457
NamedGroupCredentials c = (NamedGroupCredentials)cred;
458
if (p.getNamedGroup() != c.getNamedGroup()) {
459
continue;
460
} else {
461
namedGroup = p.getNamedGroup();
462
}
463
namedGroupPossession = p;
464
namedGroupCredentials = c;
465
break search;
466
}
467
}
468
}
469
470
if (namedGroupPossession == null || namedGroupCredentials == null) {
471
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
472
"No sufficient ECDHE/XDH key agreement " +
473
"parameters negotiated");
474
}
475
476
String alg;
477
switch (namedGroup.spec) {
478
case NAMED_GROUP_ECDHE:
479
alg = "ECDH";
480
break;
481
case NAMED_GROUP_XDH:
482
alg = "XDH";
483
break;
484
default:
485
throw new RuntimeException("Unexpected named group type");
486
}
487
488
return new KAKeyDerivation(alg, context,
489
namedGroupPossession.getPrivateKey(),
490
namedGroupCredentials.getPublicKey());
491
}
492
}
493
}
494
495