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