< prev index next >

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

Print this page




  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.nio.ByteBuffer;


  30 import java.security.GeneralSecurityException;

  31 import java.security.PublicKey;
  32 import java.security.interfaces.ECPublicKey;
  33 import java.security.interfaces.XECPublicKey;
  34 import java.security.spec.AlgorithmParameterSpec;
  35 import java.security.spec.ECParameterSpec;
  36 import java.security.spec.NamedParameterSpec;

  37 import java.text.MessageFormat;

  38 import java.util.Locale;
  39 import javax.crypto.SecretKey;



  40 import sun.security.ssl.SSLHandshake.HandshakeMessage;

  41 import sun.security.ssl.X509Authentication.X509Credentials;
  42 import sun.security.ssl.X509Authentication.X509Possession;

  43 import sun.security.util.HexDumpEncoder;
  44 
  45 /**
  46  * Pack of the "ClientKeyExchange" handshake message.
  47  *
  48  * This file is used by both the ECDH/ECDHE/XDH code since much of the
  49  * code is the same between the EC named groups (i.e.
  50  * x25519/x448/secp*r1), even though the APIs are very different (i.e.
  51  * ECPublicKey/XECPublicKey, KeyExchange.getInstance("EC"/"XDH"), etc.).
  52  */
  53 final class ECDHClientKeyExchange {
  54     static final SSLConsumer ecdhHandshakeConsumer =
  55             new ECDHClientKeyExchangeConsumer();
  56     static final HandshakeProducer ecdhHandshakeProducer =
  57             new ECDHClientKeyExchangeProducer();
  58 
  59     static final SSLConsumer ecdheHandshakeConsumer =
  60             new ECDHEClientKeyExchangeConsumer();
  61     static final HandshakeProducer ecdheHandshakeProducer =
  62             new ECDHEClientKeyExchangeProducer();
  63 
  64     /**
  65      * The ECDH/ECDHE/XDH ClientKeyExchange handshake message.
  66      */
  67     private static final
  68             class ECDHClientKeyExchangeMessage extends HandshakeMessage {
  69         private final byte[] encodedPoint;
  70 
  71         ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
  72                 byte[] encodedPublicKey) {
  73             super(handshakeContext);
  74 
  75             this.encodedPoint = encodedPublicKey;


  76         }
  77 
  78         ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
  79                 ByteBuffer m) throws IOException {
  80             super(handshakeContext);
  81             if (m.remaining() != 0) {       // explicit PublicValueEncoding
  82                 this.encodedPoint = Record.getBytes8(m);
  83             } else {
  84                 this.encodedPoint = new byte[0];
  85             }
  86         }
  87 




























  88         @Override
  89         public SSLHandshake handshakeType() {
  90             return SSLHandshake.CLIENT_KEY_EXCHANGE;
  91         }
  92 
  93         @Override
  94         public int messageLength() {
  95             if (encodedPoint == null || encodedPoint.length == 0) {
  96                 return 0;
  97             } else {
  98                 return 1 + encodedPoint.length;
  99             }
 100         }
 101 
 102         @Override
 103         public void send(HandshakeOutStream hos) throws IOException {
 104             if (encodedPoint != null && encodedPoint.length != 0) {
 105                 hos.putBytes8(encodedPoint);
 106             }
 107         }


 144         @Override
 145         public byte[] produce(ConnectionContext context,
 146                 HandshakeMessage message) throws IOException {
 147             // The producing happens in client side only.
 148             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 149 
 150             X509Credentials x509Credentials = null;
 151             for (SSLCredentials credential : chc.handshakeCredentials) {
 152                 if (credential instanceof X509Credentials) {
 153                     x509Credentials = (X509Credentials)credential;
 154                     break;
 155                 }
 156             }
 157 
 158             if (x509Credentials == null) {
 159                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 160                     "No server certificate for ECDH client key exchange");
 161             }
 162 
 163             PublicKey publicKey = x509Credentials.popPublicKey;
 164 
 165             NamedGroup namedGroup = null;
 166             String algorithm = publicKey.getAlgorithm();
 167 
 168             // Determine which NamedGroup we'll be using, then use
 169             // the creator functions.
 170             if (algorithm.equals("EC")) {
 171                 ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
 172                 namedGroup = NamedGroup.valueOf(params);
 173             } else if (algorithm.equals("XDH")) {
 174                 AlgorithmParameterSpec params =
 175                         ((XECPublicKey)publicKey).getParams();
 176                 if (params instanceof NamedParameterSpec) {
 177                     String name = ((NamedParameterSpec)params).getName();
 178                     namedGroup = NamedGroup.nameOf(name);
 179                 }
 180             } else {
 181                 throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 182                     "Not EC/XDH server certificate for " +
 183                             "ECDH client key exchange");
 184             }
 185 


 186             if (namedGroup == null) {
 187                 throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 188                     "Unsupported EC/XDH server cert for " +
 189                         "ECDH client key exchange");
 190             }
 191 
 192             SSLPossession sslPossession = namedGroup.createPossession(
 193                     chc.sslContext.getSecureRandom());
 194 
 195             chc.handshakePossessions.add(sslPossession);
 196             ECDHClientKeyExchangeMessage cke =
 197                     new ECDHClientKeyExchangeMessage(
 198                             chc, sslPossession.encode());
 199             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 200                 SSLLogger.fine(
 201                     "Produced ECDH ClientKeyExchange handshake message", cke);
 202             }
 203 
 204             // Output the handshake message.
 205             cke.write(chc.handshakeOutput);
 206             chc.handshakeOutput.flush();
 207 
 208             // update the states
 209             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 210                     chc.negotiatedCipherSuite.keyExchange,
 211                     chc.negotiatedProtocol);
 212             if (ke == null) {
 213                 // unlikely
 214                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 215                         "Not supported key exchange type");
 216             } else {
 217                 SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
 218                 SecretKey masterSecret =


 250         @Override
 251         public void consume(ConnectionContext context,
 252                 ByteBuffer message) throws IOException {
 253             // The consuming happens in server side only.
 254             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 255 
 256             X509Possession x509Possession = null;
 257             for (SSLPossession possession : shc.handshakePossessions) {
 258                 if (possession instanceof X509Possession) {
 259                     x509Possession = (X509Possession)possession;
 260                     break;
 261                 }
 262             }
 263 
 264             if (x509Possession == null) {
 265                 // unlikely, have been checked during cipher suite negotiation.
 266                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 267                     "No expected EC server cert for ECDH client key exchange");
 268             }
 269 
 270             // Determine which NamedGroup we'll be using, then use
 271             // the creator functions.
 272             NamedGroup namedGroup = null;
 273 
 274             // Iteratively determine the X509Possession type's ParameterSpec.
 275             ECParameterSpec ecParams = x509Possession.getECParameterSpec();
 276             NamedParameterSpec namedParams = null;
 277             if (ecParams != null) {
 278                 namedGroup = NamedGroup.valueOf(ecParams);
 279             }
 280 
 281             // Wasn't EC, try XEC.
 282             if (ecParams == null) {
 283                 namedParams = x509Possession.getXECParameterSpec();
 284                 namedGroup = NamedGroup.nameOf(namedParams.getName());
 285             }
 286 
 287             // Can't figure this out, bail.
 288             if ((ecParams == null) && (namedParams == null)) {
 289                 // unlikely, have been checked during cipher suite negotiation.
 290                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 291                     "Not EC/XDH server cert for ECDH client key exchange");
 292             }
 293 
 294             // unlikely, have been checked during cipher suite negotiation.
 295             if (namedGroup == null) {

 296                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 297                     "Unknown named group in server cert for " +
 298                         "ECDH client key exchange");
 299             }
 300 
 301             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 302                     shc.negotiatedCipherSuite.keyExchange,
 303                     shc.negotiatedProtocol);
 304             if (ke == null) {
 305                 // unlikely
 306                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 307                         "Not supported key exchange type");
 308             }
 309 
 310             // parse either handshake message containing either EC/XEC.
 311             ECDHClientKeyExchangeMessage cke =
 312                     new ECDHClientKeyExchangeMessage(shc, message);
 313             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 314                 SSLLogger.fine(
 315                     "Consuming ECDH ClientKeyExchange handshake message", cke);
 316             }
 317 
 318             // create the credentials
 319             try {
 320                 NamedGroup ng = namedGroup;  // "effectively final" the lambda
 321                 // AlgorithmConstraints are checked internally.
 322                 SSLCredentials sslCredentials = namedGroup.decodeCredentials(
 323                         cke.encodedPoint, shc.algorithmConstraints,
 324                         s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
 325                         "ClientKeyExchange " + ng + ": " + s));
 326 
 327                 shc.handshakeCredentials.add(sslCredentials);
 328             } catch (GeneralSecurityException e) {
 329                 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 330                         "Cannot decode ECDH PublicKey: " + namedGroup);










 331             }
 332 
 333             // update the states
 334             SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
 335             SecretKey masterSecret =
 336                     masterKD.deriveKey("MasterSecret", null);
 337             shc.handshakeSession.setMasterSecret(masterSecret);
 338 
 339             SSLTrafficKeyDerivation kd =
 340                     SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
 341             if (kd == null) {
 342                 // unlikely
 343                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 344                     "Not supported key derivation: " + shc.negotiatedProtocol);
 345             } else {
 346                 shc.handshakeKeyDerivation =
 347                     kd.createKeyDerivation(shc, masterSecret);
 348             }
 349         }
 350     }
 351 
 352     /**
 353      * The ECDHE "ClientKeyExchange" handshake message producer.
 354      */
 355     private static final
 356             class ECDHEClientKeyExchangeProducer implements HandshakeProducer {
 357         // Prevent instantiation of this class.
 358         private ECDHEClientKeyExchangeProducer() {
 359             // blank
 360         }
 361 
 362         @Override
 363         public byte[] produce(ConnectionContext context,
 364                 HandshakeMessage message) throws IOException {
 365             // The producing happens in client side only.
 366             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 367 
 368             SSLCredentials sslCredentials = null;
 369             NamedGroup ng = null;
 370             PublicKey publicKey = null;
 371 
 372             // Find a good EC/XEC credential to use, determine the
 373             // NamedGroup to use for creating Possessions/Credentials/Keys.
 374             for (SSLCredentials cd : chc.handshakeCredentials) {
 375                 if (cd instanceof NamedGroupCredentials) {
 376                     NamedGroupCredentials creds = (NamedGroupCredentials)cd;
 377                     ng = creds.getNamedGroup();
 378                     publicKey = creds.getPublicKey();
 379                     sslCredentials = cd;
 380                     break;
 381                 }
 382             }
 383 
 384             if (sslCredentials == null) {
 385                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 386                     "No ECDHE credentials negotiated for client key exchange");
 387             }
 388 
 389             SSLPossession sslPossession = ng.createPossession(
 390                     chc.sslContext.getSecureRandom());
 391 
 392             chc.handshakePossessions.add(sslPossession);
 393 
 394             // Write the EC/XEC message.
 395             ECDHClientKeyExchangeMessage cke =
 396                     new ECDHClientKeyExchangeMessage(
 397                             chc, sslPossession.encode());
 398 
 399             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 400                 SSLLogger.fine(
 401                     "Produced ECDHE ClientKeyExchange handshake message", cke);
 402             }
 403 
 404             // Output the handshake message.
 405             cke.write(chc.handshakeOutput);
 406             chc.handshakeOutput.flush();
 407 
 408             // update the states
 409             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 410                     chc.negotiatedCipherSuite.keyExchange,
 411                     chc.negotiatedProtocol);
 412             if (ke == null) {
 413                 // unlikely
 414                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 415                         "Not supported key exchange type");
 416             } else {
 417                 SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
 418                 SecretKey masterSecret =


 436             return null;
 437         }
 438     }
 439 
 440     /**
 441      * The ECDHE "ClientKeyExchange" handshake message consumer.
 442      */
 443     private static final
 444             class ECDHEClientKeyExchangeConsumer implements SSLConsumer {
 445         // Prevent instantiation of this class.
 446         private ECDHEClientKeyExchangeConsumer() {
 447             // blank
 448         }
 449 
 450         @Override
 451         public void consume(ConnectionContext context,
 452                 ByteBuffer message) throws IOException {
 453             // The consuming happens in server side only.
 454             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 455 
 456             SSLPossession sslPossession = null;
 457             NamedGroup namedGroup = null;
 458 
 459            // Find a good EC/XEC credential to use, determine the
 460            // NamedGroup to use for creating Possessions/Credentials/Keys.
 461             for (SSLPossession possession : shc.handshakePossessions) {
 462                 if (possession instanceof NamedGroupPossession) {
 463                     NamedGroupPossession poss =
 464                             (NamedGroupPossession)possession;
 465                     namedGroup = poss.getNamedGroup();
 466                     sslPossession = poss;
 467                     break;
 468                 }
 469             }
 470 
 471             if (sslPossession == null) {
 472                 // unlikely
 473                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 474                     "No expected ECDHE possessions for client key exchange");
 475             }
 476 


 477             if (namedGroup == null) {
 478                 // unlikely, have been checked during cipher suite negotiation
 479                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 480                     "Unsupported EC server cert for ECDHE client key exchange");
 481             }
 482 
 483             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 484                     shc.negotiatedCipherSuite.keyExchange,
 485                     shc.negotiatedProtocol);
 486             if (ke == null) {
 487                 // unlikely
 488                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 489                         "Not supported key exchange type");
 490             }
 491 
 492             // parse the EC/XEC handshake message
 493             ECDHClientKeyExchangeMessage cke =
 494                     new ECDHClientKeyExchangeMessage(shc, message);
 495             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 496                 SSLLogger.fine(
 497                     "Consuming ECDHE ClientKeyExchange handshake message", cke);
 498             }
 499 
 500             // create the credentials
 501             try {
 502                 NamedGroup ng = namedGroup; // "effectively final" the lambda
 503                 // AlgorithmConstraints are checked internally.
 504                 SSLCredentials sslCredentials = namedGroup.decodeCredentials(
 505                         cke.encodedPoint, shc.algorithmConstraints,
 506                         s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
 507                         "ClientKeyExchange " + ng + ": " + s));
 508 
 509                 shc.handshakeCredentials.add(sslCredentials);
 510             } catch (GeneralSecurityException e) {
 511                 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
 512                         "Cannot decode named group: " + namedGroup);










 513             }
 514 
 515             // update the states
 516             SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
 517             SecretKey masterSecret =
 518                     masterKD.deriveKey("MasterSecret", null);
 519             shc.handshakeSession.setMasterSecret(masterSecret);
 520 
 521             SSLTrafficKeyDerivation kd =
 522                     SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
 523             if (kd == null) {
 524                 // unlikely
 525                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 526                     "Not supported key derivation: " + shc.negotiatedProtocol);
 527             } else {
 528                 shc.handshakeKeyDerivation =
 529                     kd.createKeyDerivation(shc, masterSecret);
 530             }
 531         }
 532     }


  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.nio.ByteBuffer;
  30 import java.security.AlgorithmConstraints;
  31 import java.security.CryptoPrimitive;
  32 import java.security.GeneralSecurityException;
  33 import java.security.KeyFactory;
  34 import java.security.PublicKey;
  35 import java.security.interfaces.ECPublicKey;


  36 import java.security.spec.ECParameterSpec;
  37 import java.security.spec.ECPoint;
  38 import java.security.spec.ECPublicKeySpec;
  39 import java.text.MessageFormat;
  40 import java.util.EnumSet;
  41 import java.util.Locale;
  42 import javax.crypto.SecretKey;
  43 import javax.net.ssl.SSLHandshakeException;
  44 import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
  45 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
  46 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  47 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
  48 import sun.security.ssl.X509Authentication.X509Credentials;
  49 import sun.security.ssl.X509Authentication.X509Possession;
  50 import sun.security.util.ECUtil;
  51 import sun.security.util.HexDumpEncoder;
  52 
  53 /**
  54  * Pack of the "ClientKeyExchange" handshake message.





  55  */
  56 final class ECDHClientKeyExchange {
  57     static final SSLConsumer ecdhHandshakeConsumer =
  58             new ECDHClientKeyExchangeConsumer();
  59     static final HandshakeProducer ecdhHandshakeProducer =
  60             new ECDHClientKeyExchangeProducer();
  61 
  62     static final SSLConsumer ecdheHandshakeConsumer =
  63             new ECDHEClientKeyExchangeConsumer();
  64     static final HandshakeProducer ecdheHandshakeProducer =
  65             new ECDHEClientKeyExchangeProducer();
  66 
  67     /**
  68      * The ECDH/ECDHE ClientKeyExchange handshake message.
  69      */
  70     private static final
  71             class ECDHClientKeyExchangeMessage extends HandshakeMessage {
  72         private final byte[] encodedPoint;
  73 
  74         ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
  75                 ECPublicKey publicKey) {
  76             super(handshakeContext);
  77 
  78             ECPoint point = publicKey.getW();
  79             ECParameterSpec params = publicKey.getParams();
  80             encodedPoint = ECUtil.encodePoint(point, params.getCurve());
  81         }
  82 
  83         ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
  84                 ByteBuffer m) throws IOException {
  85             super(handshakeContext);
  86             if (m.remaining() != 0) {       // explicit PublicValueEncoding
  87                 this.encodedPoint = Record.getBytes8(m);
  88             } else {
  89                 this.encodedPoint = new byte[0];
  90             }
  91         }
  92 
  93         // Check constraints of the specified EC public key.
  94         static void checkConstraints(AlgorithmConstraints constraints,
  95                 ECPublicKey publicKey,
  96                 byte[] encodedPoint) throws SSLHandshakeException {
  97 
  98             try {
  99                 ECParameterSpec params = publicKey.getParams();
 100                 ECPoint point =
 101                         ECUtil.decodePoint(encodedPoint, params.getCurve());
 102                 ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
 103 
 104                 KeyFactory kf = KeyFactory.getInstance("EC");
 105                 ECPublicKey peerPublicKey =
 106                         (ECPublicKey)kf.generatePublic(spec);
 107 
 108                 // check constraints of ECPublicKey
 109                 if (!constraints.permits(
 110                         EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 111                         peerPublicKey)) {
 112                     throw new SSLHandshakeException(
 113                         "ECPublicKey does not comply to algorithm constraints");
 114                 }
 115             } catch (GeneralSecurityException | java.io.IOException e) {
 116                 throw (SSLHandshakeException) new SSLHandshakeException(
 117                         "Could not generate ECPublicKey").initCause(e);
 118             }
 119         }
 120 
 121         @Override
 122         public SSLHandshake handshakeType() {
 123             return SSLHandshake.CLIENT_KEY_EXCHANGE;
 124         }
 125 
 126         @Override
 127         public int messageLength() {
 128             if (encodedPoint == null || encodedPoint.length == 0) {
 129                 return 0;
 130             } else {
 131                 return 1 + encodedPoint.length;
 132             }
 133         }
 134 
 135         @Override
 136         public void send(HandshakeOutStream hos) throws IOException {
 137             if (encodedPoint != null && encodedPoint.length != 0) {
 138                 hos.putBytes8(encodedPoint);
 139             }
 140         }


 177         @Override
 178         public byte[] produce(ConnectionContext context,
 179                 HandshakeMessage message) throws IOException {
 180             // The producing happens in client side only.
 181             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 182 
 183             X509Credentials x509Credentials = null;
 184             for (SSLCredentials credential : chc.handshakeCredentials) {
 185                 if (credential instanceof X509Credentials) {
 186                     x509Credentials = (X509Credentials)credential;
 187                     break;
 188                 }
 189             }
 190 
 191             if (x509Credentials == null) {
 192                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 193                     "No server certificate for ECDH client key exchange");
 194             }
 195 
 196             PublicKey publicKey = x509Credentials.popPublicKey;
 197             if (!publicKey.getAlgorithm().equals("EC")) {
















 198                 throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 199                     "Not EC server certificate for ECDH client key exchange");

 200             }
 201 
 202             ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
 203             NamedGroup namedGroup = NamedGroup.valueOf(params);
 204             if (namedGroup == null) {
 205                 throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 206                     "Unsupported EC server cert for ECDH client key exchange");

 207             }
 208 
 209             ECDHEPossession ecdhePossession = new ECDHEPossession(
 210                     namedGroup, chc.sslContext.getSecureRandom());
 211             chc.handshakePossessions.add(ecdhePossession);

 212             ECDHClientKeyExchangeMessage cke =
 213                     new ECDHClientKeyExchangeMessage(
 214                             chc, ecdhePossession.publicKey);
 215             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 216                 SSLLogger.fine(
 217                     "Produced ECDH ClientKeyExchange handshake message", cke);
 218             }
 219 
 220             // Output the handshake message.
 221             cke.write(chc.handshakeOutput);
 222             chc.handshakeOutput.flush();
 223 
 224             // update the states
 225             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 226                     chc.negotiatedCipherSuite.keyExchange,
 227                     chc.negotiatedProtocol);
 228             if (ke == null) {
 229                 // unlikely
 230                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 231                         "Not supported key exchange type");
 232             } else {
 233                 SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
 234                 SecretKey masterSecret =


 266         @Override
 267         public void consume(ConnectionContext context,
 268                 ByteBuffer message) throws IOException {
 269             // The consuming happens in server side only.
 270             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 271 
 272             X509Possession x509Possession = null;
 273             for (SSLPossession possession : shc.handshakePossessions) {
 274                 if (possession instanceof X509Possession) {
 275                     x509Possession = (X509Possession)possession;
 276                     break;
 277                 }
 278             }
 279 
 280             if (x509Possession == null) {
 281                 // unlikely, have been checked during cipher suite negotiation.
 282                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 283                     "No expected EC server cert for ECDH client key exchange");
 284             }
 285 
 286             ECParameterSpec params = x509Possession.getECParameterSpec();
 287             if (params == null) {

















 288                 // unlikely, have been checked during cipher suite negotiation.
 289                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 290                     "Not EC server cert for ECDH client key exchange");
 291             }
 292 
 293             NamedGroup namedGroup = NamedGroup.valueOf(params);
 294             if (namedGroup == null) {
 295                 // unlikely, have been checked during cipher suite negotiation.
 296                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 297                     "Unsupported EC server cert for ECDH client key exchange");

 298             }
 299 
 300             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 301                     shc.negotiatedCipherSuite.keyExchange,
 302                     shc.negotiatedProtocol);
 303             if (ke == null) {
 304                 // unlikely
 305                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 306                         "Not supported key exchange type");
 307             }
 308 
 309             // parse the handshake message
 310             ECDHClientKeyExchangeMessage cke =
 311                     new ECDHClientKeyExchangeMessage(shc, message);
 312             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 313                 SSLLogger.fine(
 314                     "Consuming ECDH ClientKeyExchange handshake message", cke);
 315             }
 316 
 317             // create the credentials
 318             try {
 319                 ECPoint point =
 320                     ECUtil.decodePoint(cke.encodedPoint, params.getCurve());
 321                 ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
 322 
 323                 KeyFactory kf = KeyFactory.getInstance("EC");
 324                 ECPublicKey peerPublicKey =
 325                         (ECPublicKey)kf.generatePublic(spec);
 326 
 327                 // check constraints of peer ECPublicKey
 328                 if (!shc.algorithmConstraints.permits(
 329                         EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 330                         peerPublicKey)) {
 331                     throw new SSLHandshakeException(
 332                         "ECPublicKey does not comply to algorithm constraints");
 333                 }
 334 
 335                 shc.handshakeCredentials.add(new ECDHECredentials(
 336                         peerPublicKey, namedGroup));
 337             } catch (GeneralSecurityException | java.io.IOException e) {
 338                 throw (SSLHandshakeException)(new SSLHandshakeException(
 339                         "Could not generate ECPublicKey").initCause(e));
 340             }
 341 
 342             // update the states
 343             SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
 344             SecretKey masterSecret =
 345                     masterKD.deriveKey("MasterSecret", null);
 346             shc.handshakeSession.setMasterSecret(masterSecret);
 347 
 348             SSLTrafficKeyDerivation kd =
 349                     SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
 350             if (kd == null) {
 351                 // unlikely
 352                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 353                     "Not supported key derivation: " + shc.negotiatedProtocol);
 354             } else {
 355                 shc.handshakeKeyDerivation =
 356                     kd.createKeyDerivation(shc, masterSecret);
 357             }
 358         }
 359     }
 360 
 361     /**
 362      * The ECDHE "ClientKeyExchange" handshake message producer.
 363      */
 364     private static final
 365             class ECDHEClientKeyExchangeProducer implements HandshakeProducer {
 366         // Prevent instantiation of this class.
 367         private ECDHEClientKeyExchangeProducer() {
 368             // blank
 369         }
 370 
 371         @Override
 372         public byte[] produce(ConnectionContext context,
 373                 HandshakeMessage message) throws IOException {
 374             // The producing happens in client side only.
 375             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 376 
 377             ECDHECredentials ecdheCredentials = null;





 378             for (SSLCredentials cd : chc.handshakeCredentials) {
 379                 if (cd instanceof ECDHECredentials) {
 380                     ecdheCredentials = (ECDHECredentials)cd;



 381                     break;
 382                 }
 383             }
 384 
 385             if (ecdheCredentials == null) {
 386                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 387                     "No ECDHE credentials negotiated for client key exchange");
 388             }
 389 
 390             ECDHEPossession ecdhePossession = new ECDHEPossession(
 391                     ecdheCredentials, chc.sslContext.getSecureRandom());
 392             chc.handshakePossessions.add(ecdhePossession);



 393             ECDHClientKeyExchangeMessage cke =
 394                     new ECDHClientKeyExchangeMessage(
 395                             chc, ecdhePossession.publicKey);

 396             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 397                 SSLLogger.fine(
 398                     "Produced ECDHE ClientKeyExchange handshake message", cke);
 399             }
 400 
 401             // Output the handshake message.
 402             cke.write(chc.handshakeOutput);
 403             chc.handshakeOutput.flush();
 404 
 405             // update the states
 406             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 407                     chc.negotiatedCipherSuite.keyExchange,
 408                     chc.negotiatedProtocol);
 409             if (ke == null) {
 410                 // unlikely
 411                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
 412                         "Not supported key exchange type");
 413             } else {
 414                 SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
 415                 SecretKey masterSecret =


 433             return null;
 434         }
 435     }
 436 
 437     /**
 438      * The ECDHE "ClientKeyExchange" handshake message consumer.
 439      */
 440     private static final
 441             class ECDHEClientKeyExchangeConsumer implements SSLConsumer {
 442         // Prevent instantiation of this class.
 443         private ECDHEClientKeyExchangeConsumer() {
 444             // blank
 445         }
 446 
 447         @Override
 448         public void consume(ConnectionContext context,
 449                 ByteBuffer message) throws IOException {
 450             // The consuming happens in server side only.
 451             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 452 
 453             ECDHEPossession ecdhePossession = null;




 454             for (SSLPossession possession : shc.handshakePossessions) {
 455                 if (possession instanceof ECDHEPossession) {
 456                     ecdhePossession = (ECDHEPossession)possession;



 457                     break;
 458                 }
 459             }
 460             if (ecdhePossession == null) {

 461                 // unlikely
 462                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 463                     "No expected ECDHE possessions for client key exchange");
 464             }
 465 
 466             ECParameterSpec params = ecdhePossession.publicKey.getParams();
 467             NamedGroup namedGroup = NamedGroup.valueOf(params);
 468             if (namedGroup == null) {
 469                 // unlikely, have been checked during cipher suite negotiation.
 470                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 471                     "Unsupported EC server cert for ECDHE client key exchange");
 472             }
 473 
 474             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 475                     shc.negotiatedCipherSuite.keyExchange,
 476                     shc.negotiatedProtocol);
 477             if (ke == null) {
 478                 // unlikely
 479                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 480                         "Not supported key exchange type");
 481             }
 482 
 483             // parse the handshake message
 484             ECDHClientKeyExchangeMessage cke =
 485                     new ECDHClientKeyExchangeMessage(shc, message);
 486             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 487                 SSLLogger.fine(
 488                     "Consuming ECDHE ClientKeyExchange handshake message", cke);
 489             }
 490 
 491             // create the credentials
 492             try {
 493                 ECPoint point =
 494                     ECUtil.decodePoint(cke.encodedPoint, params.getCurve());
 495                 ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
 496 
 497                 KeyFactory kf = KeyFactory.getInstance("EC");
 498                 ECPublicKey peerPublicKey =
 499                         (ECPublicKey)kf.generatePublic(spec);
 500 
 501                 // check constraints of peer ECPublicKey
 502                 if (!shc.algorithmConstraints.permits(
 503                         EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 504                         peerPublicKey)) {
 505                     throw new SSLHandshakeException(
 506                         "ECPublicKey does not comply to algorithm constraints");
 507                 }
 508 
 509                 shc.handshakeCredentials.add(new ECDHECredentials(
 510                         peerPublicKey, namedGroup));
 511             } catch (GeneralSecurityException | java.io.IOException e) {
 512                 throw (SSLHandshakeException)(new SSLHandshakeException(
 513                         "Could not generate ECPublicKey").initCause(e));
 514             }
 515 
 516             // update the states
 517             SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
 518             SecretKey masterSecret =
 519                     masterKD.deriveKey("MasterSecret", null);
 520             shc.handshakeSession.setMasterSecret(masterSecret);
 521 
 522             SSLTrafficKeyDerivation kd =
 523                     SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
 524             if (kd == null) {
 525                 // unlikely
 526                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
 527                     "Not supported key derivation: " + shc.negotiatedProtocol);
 528             } else {
 529                 shc.handshakeKeyDerivation =
 530                     kd.createKeyDerivation(shc, masterSecret);
 531             }
 532         }
 533     }
< prev index next >