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.ECGenParameterSpec;
40 import java.security.spec.ECParameterSpec;
41 import java.security.spec.ECPoint;
42 import java.security.spec.ECPublicKeySpec;
43 import java.util.EnumSet;
44 import javax.crypto.KeyAgreement;
45 import javax.crypto.SecretKey;
46 import javax.net.ssl.SSLHandshakeException;
47 import sun.security.ssl.NamedGroup.NamedGroupType;
48 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
49 import sun.security.ssl.X509Authentication.X509Credentials;
50 import sun.security.ssl.X509Authentication.X509Possession;
51 import sun.security.ssl.XDHKeyExchange.XDHECredentials;
52 import sun.security.ssl.XDHKeyExchange.XDHEPossession;
53 import sun.security.util.ECUtil;
54
55 final class ECDHKeyExchange {
56 static final SSLPossessionGenerator poGenerator =
57 new ECDHEPossessionGenerator();
58 static final SSLKeyAgreementGenerator ecdhKAGenerator =
59 new ECDHKAGenerator();
60
61 // TLSv1.3
62 static final SSLKeyAgreementGenerator ecdheKAGenerator =
63 new ECDHEKAGenerator();
64
65 // TLSv1-1.2, the KA gets more difficult with EC/XEC keys
66 static final SSLKeyAgreementGenerator ecdheXdhKAGenerator =
67 new ECDHEXDHKAGenerator();
71 final NamedGroup namedGroup;
72
73 ECDHECredentials(ECPublicKey popPublicKey, NamedGroup namedGroup) {
74 this.popPublicKey = popPublicKey;
75 this.namedGroup = namedGroup;
76 }
77
78 @Override
79 public PublicKey getPublicKey() {
80 return popPublicKey;
81 }
82
83 @Override
84 public NamedGroup getNamedGroup() {
85 return namedGroup;
86 }
87
88 static ECDHECredentials valueOf(NamedGroup namedGroup,
89 byte[] encodedPoint) throws IOException, GeneralSecurityException {
90
91 if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
92 throw new RuntimeException(
93 "Credentials decoding: Not ECDHE named group");
94 }
95
96 if (encodedPoint == null || encodedPoint.length == 0) {
97 return null;
98 }
99
100 ECParameterSpec parameters =
101 JsseJce.getECParameterSpec(namedGroup.oid);
102 if (parameters == null) {
103 return null;
104 }
105
106 ECPoint point = JsseJce.decodePoint(
107 encodedPoint, parameters.getCurve());
108 KeyFactory factory = JsseJce.getKeyFactory("EC");
109 ECPublicKey publicKey = (ECPublicKey)factory.generatePublic(
110 new ECPublicKeySpec(point, parameters));
111 return new ECDHECredentials(publicKey, namedGroup);
112 }
113 }
114
115 static final class ECDHEPossession implements NamedGroupPossession {
116 final PrivateKey privateKey;
117 final ECPublicKey publicKey;
118 final NamedGroup namedGroup;
119
120 ECDHEPossession(NamedGroup namedGroup, SecureRandom random) {
121 try {
122 KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
123 ECGenParameterSpec params =
124 (ECGenParameterSpec)namedGroup.getParameterSpec();
125 kpg.initialize(params, random);
126 KeyPair kp = kpg.generateKeyPair();
127 privateKey = kp.getPrivate();
128 publicKey = (ECPublicKey)kp.getPublic();
129 } catch (GeneralSecurityException e) {
130 throw new RuntimeException(
131 "Could not generate ECDH keypair", e);
132 }
133
134 this.namedGroup = namedGroup;
135 }
136
137 ECDHEPossession(ECDHECredentials credentials, SecureRandom random) {
138 ECParameterSpec params = credentials.popPublicKey.getParams();
139 try {
140 KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
141 kpg.initialize(params, random);
142 KeyPair kp = kpg.generateKeyPair();
143 privateKey = kp.getPrivate();
144 publicKey = (ECPublicKey)kp.getPublic();
145 } catch (GeneralSecurityException e) {
231 }
232
233 private static final
234 class ECDHEPossessionGenerator implements SSLPossessionGenerator {
235 // Prevent instantiation of this class.
236 private ECDHEPossessionGenerator() {
237 // blank
238 }
239
240 @Override
241 public SSLPossession createPossession(HandshakeContext context) {
242
243 NamedGroup preferableNamedGroup;
244
245 // Find most preferred EC or XEC groups
246 if ((context.clientRequestedNamedGroups != null) &&
247 (!context.clientRequestedNamedGroups.isEmpty())) {
248 preferableNamedGroup = SupportedGroups.getPreferredGroup(
249 context.negotiatedProtocol,
250 context.algorithmConstraints,
251 new NamedGroupType[] {
252 NamedGroupType.NAMED_GROUP_ECDHE,
253 NamedGroupType.NAMED_GROUP_XDH },
254 context.clientRequestedNamedGroups);
255 } else {
256 preferableNamedGroup = SupportedGroups.getPreferredGroup(
257 context.negotiatedProtocol,
258 context.algorithmConstraints,
259 new NamedGroupType[] {
260 NamedGroupType.NAMED_GROUP_ECDHE,
261 NamedGroupType.NAMED_GROUP_XDH });
262 }
263
264 if (preferableNamedGroup != null) {
265 return preferableNamedGroup.createPossession(
266 context.sslContext.getSecureRandom());
267 }
268
269 // no match found, cannot use this cipher suite.
270 //
271 return null;
272 }
273 }
274
275 private static final
276 class ECDHKAGenerator implements SSLKeyAgreementGenerator {
277 // Prevent instantiation of this class.
278 private ECDHKAGenerator() {
279 // blank
280 }
281
291 }
292 }
293
294 private SSLKeyDerivation createServerKeyDerivation(
295 ServerHandshakeContext shc) throws IOException {
296 X509Possession x509Possession = null;
297 ECDHECredentials ecdheCredentials = null;
298 for (SSLPossession poss : shc.handshakePossessions) {
299 if (!(poss instanceof X509Possession)) {
300 continue;
301 }
302
303 ECParameterSpec params =
304 ((X509Possession)poss).getECParameterSpec();
305 if (params == null) {
306 continue;
307 }
308
309 NamedGroup ng = NamedGroup.valueOf(params);
310 if (ng == null) {
311 // unlikely, have been checked during cipher suite negotiation.
312 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
313 "Unsupported EC server cert for ECDH key exchange");
314 }
315
316 for (SSLCredentials cred : shc.handshakeCredentials) {
317 if (!(cred instanceof ECDHECredentials)) {
318 continue;
319 }
320 if (ng.equals(((ECDHECredentials)cred).namedGroup)) {
321 ecdheCredentials = (ECDHECredentials)cred;
322 break;
323 }
324 }
325
326 if (ecdheCredentials != null) {
327 x509Possession = (X509Possession)poss;
328 break;
329 }
330 }
331
463 NamedGroupCredentials c = (NamedGroupCredentials)cred;
464 if (p.getNamedGroup() != c.getNamedGroup()) {
465 continue;
466 } else {
467 namedGroup = p.getNamedGroup();
468 }
469 namedGroupPossession = p;
470 namedGroupCredentials = c;
471 break search;
472 }
473 }
474 }
475
476 if (namedGroupPossession == null || namedGroupCredentials == null) {
477 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
478 "No sufficient ECDHE/XDH key agreement " +
479 "parameters negotiated");
480 }
481
482 String alg;
483 switch (namedGroup.type) {
484 case NAMED_GROUP_ECDHE:
485 alg = "ECDH";
486 break;
487 case NAMED_GROUP_XDH:
488 alg = "XDH";
489 break;
490 default:
491 throw new RuntimeException("Unexpected named group type");
492 }
493
494 return new KAKeyDerivation(alg, context,
495 namedGroupPossession.getPrivateKey(),
496 namedGroupCredentials.getPublicKey());
497 }
498 }
499 }
|
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();
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
102 ECPoint point = JsseJce.decodePoint(
103 encodedPoint, parameters.getCurve());
104 KeyFactory factory = JsseJce.getKeyFactory("EC");
105 ECPublicKey publicKey = (ECPublicKey)factory.generatePublic(
106 new ECPublicKeySpec(point, parameters));
107 return new ECDHECredentials(publicKey, namedGroup);
108 }
109 }
110
111 static final class ECDHEPossession implements NamedGroupPossession {
112 final PrivateKey privateKey;
113 final ECPublicKey publicKey;
114 final NamedGroup namedGroup;
115
116 ECDHEPossession(NamedGroup namedGroup, SecureRandom random) {
117 try {
118 KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
119 kpg.initialize(namedGroup.keAlgParamSpec, random);
120 KeyPair kp = kpg.generateKeyPair();
121 privateKey = kp.getPrivate();
122 publicKey = (ECPublicKey)kp.getPublic();
123 } catch (GeneralSecurityException e) {
124 throw new RuntimeException(
125 "Could not generate ECDH keypair", e);
126 }
127
128 this.namedGroup = namedGroup;
129 }
130
131 ECDHEPossession(ECDHECredentials credentials, SecureRandom random) {
132 ECParameterSpec params = credentials.popPublicKey.getParams();
133 try {
134 KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
135 kpg.initialize(params, random);
136 KeyPair kp = kpg.generateKeyPair();
137 privateKey = kp.getPrivate();
138 publicKey = (ECPublicKey)kp.getPublic();
139 } catch (GeneralSecurityException e) {
225 }
226
227 private static final
228 class ECDHEPossessionGenerator implements SSLPossessionGenerator {
229 // Prevent instantiation of this class.
230 private ECDHEPossessionGenerator() {
231 // blank
232 }
233
234 @Override
235 public SSLPossession createPossession(HandshakeContext context) {
236
237 NamedGroup preferableNamedGroup;
238
239 // Find most preferred EC or XEC groups
240 if ((context.clientRequestedNamedGroups != null) &&
241 (!context.clientRequestedNamedGroups.isEmpty())) {
242 preferableNamedGroup = SupportedGroups.getPreferredGroup(
243 context.negotiatedProtocol,
244 context.algorithmConstraints,
245 new NamedGroupSpec[] {
246 NamedGroupSpec.NAMED_GROUP_ECDHE,
247 NamedGroupSpec.NAMED_GROUP_XDH },
248 context.clientRequestedNamedGroups);
249 } else {
250 preferableNamedGroup = SupportedGroups.getPreferredGroup(
251 context.negotiatedProtocol,
252 context.algorithmConstraints,
253 new NamedGroupSpec[] {
254 NamedGroupSpec.NAMED_GROUP_ECDHE,
255 NamedGroupSpec.NAMED_GROUP_XDH });
256 }
257
258 if (preferableNamedGroup != null) {
259 return preferableNamedGroup.createPossession(
260 context.sslContext.getSecureRandom());
261 }
262
263 // no match found, cannot use this cipher suite.
264 //
265 return null;
266 }
267 }
268
269 private static final
270 class ECDHKAGenerator implements SSLKeyAgreementGenerator {
271 // Prevent instantiation of this class.
272 private ECDHKAGenerator() {
273 // blank
274 }
275
285 }
286 }
287
288 private SSLKeyDerivation createServerKeyDerivation(
289 ServerHandshakeContext shc) throws IOException {
290 X509Possession x509Possession = null;
291 ECDHECredentials ecdheCredentials = null;
292 for (SSLPossession poss : shc.handshakePossessions) {
293 if (!(poss instanceof X509Possession)) {
294 continue;
295 }
296
297 ECParameterSpec params =
298 ((X509Possession)poss).getECParameterSpec();
299 if (params == null) {
300 continue;
301 }
302
303 NamedGroup ng = NamedGroup.valueOf(params);
304 if (ng == null) {
305 // unlikely, have been checked during cipher suite
306 // negotiation.
307 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
308 "Unsupported EC server cert for ECDH key exchange");
309 }
310
311 for (SSLCredentials cred : shc.handshakeCredentials) {
312 if (!(cred instanceof ECDHECredentials)) {
313 continue;
314 }
315 if (ng.equals(((ECDHECredentials)cred).namedGroup)) {
316 ecdheCredentials = (ECDHECredentials)cred;
317 break;
318 }
319 }
320
321 if (ecdheCredentials != null) {
322 x509Possession = (X509Possession)poss;
323 break;
324 }
325 }
326
458 NamedGroupCredentials c = (NamedGroupCredentials)cred;
459 if (p.getNamedGroup() != c.getNamedGroup()) {
460 continue;
461 } else {
462 namedGroup = p.getNamedGroup();
463 }
464 namedGroupPossession = p;
465 namedGroupCredentials = c;
466 break search;
467 }
468 }
469 }
470
471 if (namedGroupPossession == null || namedGroupCredentials == null) {
472 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
473 "No sufficient ECDHE/XDH key agreement " +
474 "parameters negotiated");
475 }
476
477 String alg;
478 switch (namedGroup.spec) {
479 case NAMED_GROUP_ECDHE:
480 alg = "ECDH";
481 break;
482 case NAMED_GROUP_XDH:
483 alg = "XDH";
484 break;
485 default:
486 throw new RuntimeException("Unexpected named group type");
487 }
488
489 return new KAKeyDerivation(alg, context,
490 namedGroupPossession.getPrivateKey(),
491 namedGroupCredentials.getPublicKey());
492 }
493 }
494 }
|