34 import java.security.KeyPairGenerator; |
34 import java.security.KeyPairGenerator; |
35 import java.security.PrivateKey; |
35 import java.security.PrivateKey; |
36 import java.security.PublicKey; |
36 import java.security.PublicKey; |
37 import java.security.SecureRandom; |
37 import java.security.SecureRandom; |
38 import java.security.interfaces.ECPublicKey; |
38 import java.security.interfaces.ECPublicKey; |
39 import java.security.spec.AlgorithmParameterSpec; |
|
40 import java.security.spec.ECGenParameterSpec; |
|
41 import java.security.spec.ECParameterSpec; |
39 import java.security.spec.ECParameterSpec; |
42 import java.security.spec.ECPoint; |
40 import java.security.spec.ECPoint; |
43 import java.security.spec.ECPublicKeySpec; |
41 import java.security.spec.ECPublicKeySpec; |
44 import java.util.EnumSet; |
42 import java.util.EnumSet; |
45 import javax.crypto.KeyAgreement; |
43 import javax.crypto.KeyAgreement; |
46 import javax.crypto.SecretKey; |
44 import javax.crypto.SecretKey; |
47 import javax.crypto.spec.SecretKeySpec; |
|
48 import javax.net.ssl.SSLHandshakeException; |
45 import javax.net.ssl.SSLHandshakeException; |
49 import sun.security.ssl.CipherSuite.HashAlg; |
46 import sun.security.ssl.NamedGroup.NamedGroupSpec; |
50 import sun.security.ssl.SupportedGroupsExtension.NamedGroup; |
|
51 import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; |
|
52 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups; |
47 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups; |
53 import sun.security.ssl.X509Authentication.X509Credentials; |
48 import sun.security.ssl.X509Authentication.X509Credentials; |
54 import sun.security.ssl.X509Authentication.X509Possession; |
49 import sun.security.ssl.X509Authentication.X509Possession; |
|
50 import sun.security.ssl.XDHKeyExchange.XDHECredentials; |
|
51 import sun.security.ssl.XDHKeyExchange.XDHEPossession; |
55 import sun.security.util.ECUtil; |
52 import sun.security.util.ECUtil; |
56 |
53 |
57 final class ECDHKeyExchange { |
54 final class ECDHKeyExchange { |
58 static final SSLPossessionGenerator poGenerator = |
55 static final SSLPossessionGenerator poGenerator = |
59 new ECDHEPossessionGenerator(); |
56 new ECDHEPossessionGenerator(); |
|
57 static final SSLKeyAgreementGenerator ecdhKAGenerator = |
|
58 new ECDHKAGenerator(); |
|
59 |
|
60 // TLSv1.3 |
60 static final SSLKeyAgreementGenerator ecdheKAGenerator = |
61 static final SSLKeyAgreementGenerator ecdheKAGenerator = |
61 new ECDHEKAGenerator(); |
62 new ECDHEKAGenerator(); |
62 static final SSLKeyAgreementGenerator ecdhKAGenerator = |
63 |
63 new ECDHKAGenerator(); |
64 // TLSv1-1.2, the KA gets more difficult with EC/XEC keys |
64 |
65 static final SSLKeyAgreementGenerator ecdheXdhKAGenerator = |
65 static final class ECDHECredentials implements SSLCredentials { |
66 new ECDHEXDHKAGenerator(); |
|
67 |
|
68 static final class ECDHECredentials implements NamedGroupCredentials { |
66 final ECPublicKey popPublicKey; |
69 final ECPublicKey popPublicKey; |
67 final NamedGroup namedGroup; |
70 final NamedGroup namedGroup; |
68 |
71 |
69 ECDHECredentials(ECPublicKey popPublicKey, NamedGroup namedGroup) { |
72 ECDHECredentials(ECPublicKey popPublicKey, NamedGroup namedGroup) { |
70 this.popPublicKey = popPublicKey; |
73 this.popPublicKey = popPublicKey; |
71 this.namedGroup = namedGroup; |
74 this.namedGroup = namedGroup; |
72 } |
75 } |
73 |
76 |
|
77 @Override |
|
78 public PublicKey getPublicKey() { |
|
79 return popPublicKey; |
|
80 } |
|
81 |
|
82 @Override |
|
83 public NamedGroup getNamedGroup() { |
|
84 return namedGroup; |
|
85 } |
|
86 |
74 static ECDHECredentials valueOf(NamedGroup namedGroup, |
87 static ECDHECredentials valueOf(NamedGroup namedGroup, |
75 byte[] encodedPoint) throws IOException, GeneralSecurityException { |
88 byte[] encodedPoint) throws IOException, GeneralSecurityException { |
76 |
89 |
77 if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) { |
90 if (namedGroup.spec != NamedGroupSpec.NAMED_GROUP_ECDHE) { |
78 throw new RuntimeException( |
91 throw new RuntimeException( |
79 "Credentials decoding: Not ECDHE named group"); |
92 "Credentials decoding: Not ECDHE named group"); |
80 } |
93 } |
81 |
94 |
82 if (encodedPoint == null || encodedPoint.length == 0) { |
95 if (encodedPoint == null || encodedPoint.length == 0) { |
83 return null; |
96 return null; |
84 } |
97 } |
85 |
98 |
86 ECParameterSpec parameters = |
99 ECParameterSpec parameters = |
87 ECUtil.getECParameterSpec(null, namedGroup.oid); |
100 (ECParameterSpec)namedGroup.keAlgParamSpec; |
88 if (parameters == null) { |
|
89 return null; |
|
90 } |
|
91 |
|
92 ECPoint point = ECUtil.decodePoint( |
101 ECPoint point = ECUtil.decodePoint( |
93 encodedPoint, parameters.getCurve()); |
102 encodedPoint, parameters.getCurve()); |
94 KeyFactory factory = KeyFactory.getInstance("EC"); |
103 KeyFactory factory = KeyFactory.getInstance("EC"); |
95 ECPublicKey publicKey = (ECPublicKey)factory.generatePublic( |
104 ECPublicKey publicKey = (ECPublicKey)factory.generatePublic( |
96 new ECPublicKeySpec(point, parameters)); |
105 new ECPublicKeySpec(point, parameters)); |
97 return new ECDHECredentials(publicKey, namedGroup); |
106 return new ECDHECredentials(publicKey, namedGroup); |
98 } |
107 } |
99 } |
108 } |
100 |
109 |
101 static final class ECDHEPossession implements SSLPossession { |
110 static final class ECDHEPossession implements NamedGroupPossession { |
102 final PrivateKey privateKey; |
111 final PrivateKey privateKey; |
103 final ECPublicKey publicKey; |
112 final ECPublicKey publicKey; |
104 final NamedGroup namedGroup; |
113 final NamedGroup namedGroup; |
105 |
114 |
106 ECDHEPossession(NamedGroup namedGroup, SecureRandom random) { |
115 ECDHEPossession(NamedGroup namedGroup, SecureRandom random) { |
107 try { |
116 try { |
108 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); |
117 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC"); |
109 ECGenParameterSpec params = |
118 kpg.initialize(namedGroup.keAlgParamSpec, random); |
110 (ECGenParameterSpec)namedGroup.getParameterSpec(); |
|
111 kpg.initialize(params, random); |
|
112 KeyPair kp = kpg.generateKeyPair(); |
119 KeyPair kp = kpg.generateKeyPair(); |
113 privateKey = kp.getPrivate(); |
120 privateKey = kp.getPrivate(); |
114 publicKey = (ECPublicKey)kp.getPublic(); |
121 publicKey = (ECPublicKey)kp.getPublic(); |
115 } catch (GeneralSecurityException e) { |
122 } catch (GeneralSecurityException e) { |
116 throw new RuntimeException( |
123 throw new RuntimeException( |
208 // blank |
230 // blank |
209 } |
231 } |
210 |
232 |
211 @Override |
233 @Override |
212 public SSLPossession createPossession(HandshakeContext context) { |
234 public SSLPossession createPossession(HandshakeContext context) { |
213 NamedGroup preferableNamedGroup = null; |
235 |
|
236 NamedGroup preferableNamedGroup; |
|
237 |
|
238 // Find most preferred EC or XEC groups |
214 if ((context.clientRequestedNamedGroups != null) && |
239 if ((context.clientRequestedNamedGroups != null) && |
215 (!context.clientRequestedNamedGroups.isEmpty())) { |
240 (!context.clientRequestedNamedGroups.isEmpty())) { |
216 preferableNamedGroup = SupportedGroups.getPreferredGroup( |
241 preferableNamedGroup = SupportedGroups.getPreferredGroup( |
217 context.negotiatedProtocol, |
242 context.negotiatedProtocol, |
218 context.algorithmConstraints, |
243 context.algorithmConstraints, |
219 NamedGroupType.NAMED_GROUP_ECDHE, |
244 new NamedGroupSpec[] { |
|
245 NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
246 NamedGroupSpec.NAMED_GROUP_XDH }, |
220 context.clientRequestedNamedGroups); |
247 context.clientRequestedNamedGroups); |
221 } else { |
248 } else { |
222 preferableNamedGroup = SupportedGroups.getPreferredGroup( |
249 preferableNamedGroup = SupportedGroups.getPreferredGroup( |
223 context.negotiatedProtocol, |
250 context.negotiatedProtocol, |
224 context.algorithmConstraints, |
251 context.algorithmConstraints, |
225 NamedGroupType.NAMED_GROUP_ECDHE); |
252 new NamedGroupSpec[] { |
|
253 NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
254 NamedGroupSpec.NAMED_GROUP_XDH }); |
226 } |
255 } |
227 |
256 |
228 if (preferableNamedGroup != null) { |
257 if (preferableNamedGroup != null) { |
229 return new ECDHEPossession(preferableNamedGroup, |
258 return preferableNamedGroup.createPossession( |
230 context.sslContext.getSecureRandom()); |
259 context.sslContext.getSecureRandom()); |
231 } |
260 } |
232 |
261 |
233 // no match found, cannot use this cipher suite. |
262 // no match found, cannot use this cipher suite. |
234 // |
263 // |
235 return null; |
264 return null; |
389 if (ecdhePossession == null || ecdheCredentials == null) { |
419 if (ecdhePossession == null || ecdheCredentials == null) { |
390 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, |
420 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, |
391 "No sufficient ECDHE key agreement parameters negotiated"); |
421 "No sufficient ECDHE key agreement parameters negotiated"); |
392 } |
422 } |
393 |
423 |
394 return new ECDHEKAKeyDerivation(context, |
424 return new KAKeyDerivation("ECDH", context, |
395 ecdhePossession.privateKey, ecdheCredentials.popPublicKey); |
425 ecdhePossession.privateKey, ecdheCredentials.popPublicKey); |
396 } |
426 } |
397 } |
427 } |
398 |
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 */ |
399 private static final |
433 private static final |
400 class ECDHEKAKeyDerivation implements SSLKeyDerivation { |
434 class ECDHEXDHKAGenerator implements SSLKeyAgreementGenerator { |
401 private final HandshakeContext context; |
435 // Prevent instantiation of this class. |
402 private final PrivateKey localPrivateKey; |
436 private ECDHEXDHKAGenerator() { |
403 private final PublicKey peerPublicKey; |
437 // blank |
404 |
438 } |
405 ECDHEKAKeyDerivation(HandshakeContext context, |
439 |
406 PrivateKey localPrivateKey, |
440 @Override |
407 PublicKey peerPublicKey) { |
441 public SSLKeyDerivation createKeyDerivation( |
408 this.context = context; |
442 HandshakeContext context) throws IOException { |
409 this.localPrivateKey = localPrivateKey; |
443 |
410 this.peerPublicKey = peerPublicKey; |
444 NamedGroupPossession namedGroupPossession = null; |
411 } |
445 NamedGroupCredentials namedGroupCredentials = null; |
412 |
446 NamedGroup namedGroup = null; |
413 @Override |
447 |
414 public SecretKey deriveKey(String algorithm, |
448 // Find a possession/credential combo using the same named group |
415 AlgorithmParameterSpec params) throws IOException { |
449 search: |
416 if (!context.negotiatedProtocol.useTLS13PlusSpec()) { |
450 for (SSLPossession poss : context.handshakePossessions) { |
417 return t12DeriveKey(algorithm, params); |
451 for (SSLCredentials cred : context.handshakeCredentials) { |
418 } else { |
452 if (((poss instanceof ECDHEPossession) && |
419 return t13DeriveKey(algorithm, params); |
453 (cred instanceof ECDHECredentials)) || |
420 } |
454 (((poss instanceof XDHEPossession) && |
421 } |
455 (cred instanceof XDHECredentials)))) { |
422 |
456 NamedGroupPossession p = (NamedGroupPossession)poss; |
423 private SecretKey t12DeriveKey(String algorithm, |
457 NamedGroupCredentials c = (NamedGroupCredentials)cred; |
424 AlgorithmParameterSpec params) throws IOException { |
458 if (p.getNamedGroup() != c.getNamedGroup()) { |
425 try { |
459 continue; |
426 KeyAgreement ka = KeyAgreement.getInstance("ECDH"); |
460 } else { |
427 ka.init(localPrivateKey); |
461 namedGroup = p.getNamedGroup(); |
428 ka.doPhase(peerPublicKey, true); |
462 } |
429 SecretKey preMasterSecret = |
463 namedGroupPossession = p; |
430 ka.generateSecret("TlsPremasterSecret"); |
464 namedGroupCredentials = c; |
431 |
465 break search; |
432 SSLMasterKeyDerivation mskd = |
466 } |
433 SSLMasterKeyDerivation.valueOf( |
467 } |
434 context.negotiatedProtocol); |
468 } |
435 if (mskd == null) { |
469 |
436 // unlikely |
470 if (namedGroupPossession == null || namedGroupCredentials == null) { |
437 throw new SSLHandshakeException( |
471 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, |
438 "No expected master key derivation for protocol: " + |
472 "No sufficient ECDHE/XDH key agreement " + |
439 context.negotiatedProtocol.name); |
473 "parameters negotiated"); |
440 } |
474 } |
441 SSLKeyDerivation kd = mskd.createKeyDerivation( |
475 |
442 context, preMasterSecret); |
476 String alg; |
443 return kd.deriveKey("MasterSecret", params); |
477 switch (namedGroup.spec) { |
444 } catch (GeneralSecurityException gse) { |
478 case NAMED_GROUP_ECDHE: |
445 throw (SSLHandshakeException) new SSLHandshakeException( |
479 alg = "ECDH"; |
446 "Could not generate secret").initCause(gse); |
480 break; |
447 } |
481 case NAMED_GROUP_XDH: |
448 } |
482 alg = "XDH"; |
449 |
483 break; |
450 private SecretKey t13DeriveKey(String algorithm, |
484 default: |
451 AlgorithmParameterSpec params) throws IOException { |
485 throw new RuntimeException("Unexpected named group type"); |
452 try { |
486 } |
453 KeyAgreement ka = KeyAgreement.getInstance("ECDH"); |
487 |
454 ka.init(localPrivateKey); |
488 return new KAKeyDerivation(alg, context, |
455 ka.doPhase(peerPublicKey, true); |
489 namedGroupPossession.getPrivateKey(), |
456 SecretKey sharedSecret = |
490 namedGroupCredentials.getPublicKey()); |
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 } |
491 } |
483 } |
492 } |
484 } |
493 } |