< prev index next >

src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java

Print this page




  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();
  68 
  69     static final class ECDHECredentials implements NamedGroupCredentials {
  70         final ECPublicKey popPublicKey;
  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                     ECUtil.getECParameterSpec(null, namedGroup.oid);
 102             if (parameters == null) {
 103                 return null;
 104             }
 105 
 106             ECPoint point = ECUtil.decodePoint(
 107                     encodedPoint, parameters.getCurve());
 108             KeyFactory factory = KeyFactory.getInstance("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 = KeyPairGenerator.getInstance("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         }


 196 
 197                 ECParameterSpec params = publicKey.getParams();
 198                 ECPoint point =
 199                         ECUtil.decodePoint(encodedPoint, params.getCurve());
 200                 ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
 201 
 202                 KeyFactory kf = KeyFactory.getInstance("EC");
 203                 ECPublicKey pubKey = (ECPublicKey)kf.generatePublic(spec);
 204 
 205                 // check constraints of ECPublicKey
 206                 if (!constraints.permits(
 207                         EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), pubKey)) {
 208                     throw new SSLHandshakeException(
 209                         "ECPublicKey does not comply to algorithm constraints");
 210                 }
 211             } catch (GeneralSecurityException | java.io.IOException e) {
 212                 throw (SSLHandshakeException) new SSLHandshakeException(
 213                         "Could not generate ECPublicKey").initCause(e);
 214             }
 215         }
 216 
 217         @Override
 218         public PublicKey getPublicKey() {
 219             return publicKey;
 220         }
 221 
 222         @Override
 223         public NamedGroup getNamedGroup() {
 224             return namedGroup;
 225         }
 226 
 227         @Override
 228         public PrivateKey getPrivateKey() {
 229             return privateKey;
 230         }
 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 
 282         @Override
 283         public SSLKeyDerivation createKeyDerivation(
 284                 HandshakeContext context) throws IOException {
 285             if (context instanceof ServerHandshakeContext) {
 286                 return createServerKeyDerivation(


 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 
 332             if (x509Possession == null || ecdheCredentials == null) {
 333                 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 334                     "No sufficient ECDHE key agreement parameters negotiated");
 335             }
 336 
 337             return new KAKeyDerivation("ECDH", shc,
 338                 x509Possession.popPrivateKey, ecdheCredentials.popPublicKey);
 339         }
 340 
 341         private SSLKeyDerivation createClientKeyDerivation(
 342                 ClientHandshakeContext chc) throws IOException {
 343             ECDHEPossession ecdhePossession = null;
 344             X509Credentials x509Credentials = null;
 345             for (SSLPossession poss : chc.handshakePossessions) {
 346                 if (!(poss instanceof ECDHEPossession)) {
 347                     continue;
 348                 }
 349 
 350                 NamedGroup ng = ((ECDHEPossession)poss).namedGroup;
 351                 for (SSLCredentials cred : chc.handshakeCredentials) {
 352                     if (!(cred instanceof X509Credentials)) {
 353                         continue;
 354                     }
 355 
 356                     PublicKey publicKey = ((X509Credentials)cred).popPublicKey;
 357                     if (!publicKey.getAlgorithm().equals("EC")) {


 366                             "Unsupported EC server cert for ECDH key exchange");
 367                     }
 368 
 369                     if (ng.equals(namedGroup)) {
 370                         x509Credentials = (X509Credentials)cred;
 371                         break;
 372                     }
 373                 }
 374 
 375                 if (x509Credentials != null) {
 376                     ecdhePossession = (ECDHEPossession)poss;
 377                     break;
 378                 }
 379             }
 380 
 381             if (ecdhePossession == null || x509Credentials == null) {
 382                 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 383                     "No sufficient ECDH key agreement parameters negotiated");
 384             }
 385 
 386             return new KAKeyDerivation("ECDH", chc,
 387                 ecdhePossession.privateKey, x509Credentials.popPublicKey);
 388         }
 389     }
 390 
 391     private static final
 392             class ECDHEKAGenerator implements SSLKeyAgreementGenerator {
 393         // Prevent instantiation of this class.
 394         private ECDHEKAGenerator() {
 395             // blank
 396         }
 397 
 398         @Override
 399         public SSLKeyDerivation createKeyDerivation(
 400                 HandshakeContext context) throws IOException {
 401             ECDHEPossession ecdhePossession = null;
 402             ECDHECredentials ecdheCredentials = null;
 403             for (SSLPossession poss : context.handshakePossessions) {
 404                 if (!(poss instanceof ECDHEPossession)) {
 405                     continue;
 406                 }


 410                     if (!(cred instanceof ECDHECredentials)) {
 411                         continue;
 412                     }
 413                     if (ng.equals(((ECDHECredentials)cred).namedGroup)) {
 414                         ecdheCredentials = (ECDHECredentials)cred;
 415                         break;
 416                     }
 417                 }
 418 
 419                 if (ecdheCredentials != null) {
 420                     ecdhePossession = (ECDHEPossession)poss;
 421                     break;
 422                 }
 423             }
 424 
 425             if (ecdhePossession == null || ecdheCredentials == null) {
 426                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 427                     "No sufficient ECDHE key agreement parameters negotiated");
 428             }
 429 
 430             return new KAKeyDerivation("ECDH", context,
 431                 ecdhePossession.privateKey, ecdheCredentials.popPublicKey);
 432         }
 433     }
 434 
 435     /*
 436      * A Generator for TLSv1-1.2 to create a ECDHE or a XDH KeyDerivation
 437      * object depending on the negotiated group.
 438      */
 439     private static final
 440             class ECDHEXDHKAGenerator implements SSLKeyAgreementGenerator {
 441         // Prevent instantiation of this class.
 442         private ECDHEXDHKAGenerator() {
 443             // blank







 444         }
 445 
 446         @Override
 447         public SSLKeyDerivation createKeyDerivation(
 448                 HandshakeContext context) throws IOException {






 449 
 450             NamedGroupPossession namedGroupPossession = null;
 451             NamedGroupCredentials namedGroupCredentials = null;
 452             NamedGroup namedGroup = null;





 453 
 454             // Find a possession/credential combo using the same named group
 455             search:
 456             for (SSLPossession poss : context.handshakePossessions) {
 457                 for (SSLCredentials cred : context.handshakeCredentials) {
 458                     if (((poss instanceof ECDHEPossession) &&
 459                             (cred instanceof ECDHECredentials)) ||
 460                             (((poss instanceof XDHEPossession) &&
 461                             (cred instanceof XDHECredentials)))) {
 462                         NamedGroupPossession p = (NamedGroupPossession)poss;
 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.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                     ECUtil.getECParameterSpec(null, namedGroup.oid);
  88             if (parameters == null) {
  89                 return null;
  90             }
  91 
  92             ECPoint point = ECUtil.decodePoint(
  93                     encodedPoint, parameters.getCurve());
  94             KeyFactory factory = KeyFactory.getInstance("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 = KeyPairGenerator.getInstance("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         }


 182 
 183                 ECParameterSpec params = publicKey.getParams();
 184                 ECPoint point =
 185                         ECUtil.decodePoint(encodedPoint, params.getCurve());
 186                 ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
 187 
 188                 KeyFactory kf = KeyFactory.getInstance("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(


 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")) {


 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                 }


 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 = KeyAgreement.getInstance("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 = KeyAgreement.getInstance("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 }
< prev index next >