src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java
changeset 50768 68fa3d4026ea
child 53064 103ed9569fc8
equal deleted inserted replaced
50767:356eaea05bf0 50768:68fa3d4026ea
       
     1 /*
       
     2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package sun.security.ssl;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.nio.ByteBuffer;
       
    30 import java.security.CryptoPrimitive;
       
    31 import java.security.InvalidAlgorithmParameterException;
       
    32 import java.security.InvalidKeyException;
       
    33 import java.security.Key;
       
    34 import java.security.KeyFactory;
       
    35 import java.security.NoSuchAlgorithmException;
       
    36 import java.security.PrivateKey;
       
    37 import java.security.PublicKey;
       
    38 import java.security.Signature;
       
    39 import java.security.SignatureException;
       
    40 import java.security.interfaces.ECPublicKey;
       
    41 import java.security.spec.ECParameterSpec;
       
    42 import java.security.spec.ECPoint;
       
    43 import java.security.spec.ECPublicKeySpec;
       
    44 import java.security.spec.InvalidKeySpecException;
       
    45 import java.text.MessageFormat;
       
    46 import java.util.EnumSet;
       
    47 import java.util.Locale;
       
    48 import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
       
    49 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
       
    50 import sun.security.ssl.SSLHandshake.HandshakeMessage;
       
    51 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
       
    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.HexDumpEncoder;
       
    56 
       
    57 /**
       
    58  * Pack of the ServerKeyExchange handshake message.
       
    59  */
       
    60 final class ECDHServerKeyExchange {
       
    61     static final SSLConsumer ecdheHandshakeConsumer =
       
    62             new ECDHServerKeyExchangeConsumer();
       
    63     static final HandshakeProducer ecdheHandshakeProducer =
       
    64             new ECDHServerKeyExchangeProducer();
       
    65 
       
    66     /**
       
    67      * The ECDH ServerKeyExchange handshake message.
       
    68      */
       
    69     private static final
       
    70             class ECDHServerKeyExchangeMessage extends HandshakeMessage {
       
    71         private static final byte CURVE_NAMED_CURVE = (byte)0x03;
       
    72 
       
    73         // id of the named curve
       
    74         private final NamedGroup namedGroup;
       
    75 
       
    76         // encoded public point
       
    77         private final byte[] publicPoint;
       
    78 
       
    79         // signature bytes, or null if anonymous
       
    80         private final byte[] paramsSignature;
       
    81 
       
    82         // public key object encapsulated in this message
       
    83         private final ECPublicKey publicKey;
       
    84 
       
    85         private final boolean useExplicitSigAlgorithm;
       
    86 
       
    87         // the signature algorithm used by this ServerKeyExchange message
       
    88         private final SignatureScheme signatureScheme;
       
    89 
       
    90         ECDHServerKeyExchangeMessage(
       
    91                 HandshakeContext handshakeContext) throws IOException {
       
    92             super(handshakeContext);
       
    93 
       
    94             // This happens in server side only.
       
    95             ServerHandshakeContext shc =
       
    96                     (ServerHandshakeContext)handshakeContext;
       
    97 
       
    98             ECDHEPossession ecdhePossession = null;
       
    99             X509Possession x509Possession = null;
       
   100             for (SSLPossession possession : shc.handshakePossessions) {
       
   101                 if (possession instanceof ECDHEPossession) {
       
   102                     ecdhePossession = (ECDHEPossession)possession;
       
   103                     if (x509Possession != null) {
       
   104                         break;
       
   105                     }
       
   106                 } else if (possession instanceof X509Possession) {
       
   107                     x509Possession = (X509Possession)possession;
       
   108                     if (ecdhePossession != null) {
       
   109                         break;
       
   110                     }
       
   111                 }
       
   112             }
       
   113 
       
   114             if (ecdhePossession == null) {
       
   115                 // unlikely
       
   116                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   117                     "No ECDHE credentials negotiated for server key exchange");
       
   118             }
       
   119 
       
   120             publicKey = ecdhePossession.publicKey;
       
   121             ECParameterSpec params = publicKey.getParams();
       
   122             ECPoint point = publicKey.getW();
       
   123             publicPoint = JsseJce.encodePoint(point, params.getCurve());
       
   124 
       
   125             this.namedGroup = NamedGroup.valueOf(params);
       
   126             if ((namedGroup == null) || (namedGroup.oid == null) ) {
       
   127                 // unlikely
       
   128                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   129                     "Unnamed EC parameter spec: " + params);
       
   130             }
       
   131 
       
   132             if (x509Possession == null) {
       
   133                 // anonymous, no authentication, no signature
       
   134                 paramsSignature = null;
       
   135                 signatureScheme = null;
       
   136                 useExplicitSigAlgorithm = false;
       
   137             } else {
       
   138                 useExplicitSigAlgorithm =
       
   139                         shc.negotiatedProtocol.useTLS12PlusSpec();
       
   140                 Signature signer = null;
       
   141                 if (useExplicitSigAlgorithm) {
       
   142                     signatureScheme = SignatureScheme.getPreferableAlgorithm(
       
   143                             shc.peerRequestedSignatureSchemes,
       
   144                             x509Possession.popPrivateKey,
       
   145                             shc.negotiatedProtocol);
       
   146                     if (signatureScheme == null) {
       
   147                         // Unlikely, the credentials generator should have
       
   148                         // selected the preferable signature algorithm properly.
       
   149                         shc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   150                                 "No preferred signature algorithm for " +
       
   151                                 x509Possession.popPrivateKey.getAlgorithm() +
       
   152                                 "  key");
       
   153                     }
       
   154                     try {
       
   155                         signer = signatureScheme.getSignature(
       
   156                                 x509Possession.popPrivateKey);
       
   157                     } catch (NoSuchAlgorithmException | InvalidKeyException |
       
   158                             InvalidAlgorithmParameterException nsae) {
       
   159                         shc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   160                             "Unsupported signature algorithm: " +
       
   161                             signatureScheme.name, nsae);
       
   162                     }
       
   163                 } else {
       
   164                     signatureScheme = null;
       
   165                     try {
       
   166                         signer = getSignature(
       
   167                                 x509Possession.popPrivateKey.getAlgorithm(),
       
   168                                 x509Possession.popPrivateKey);
       
   169                     } catch (NoSuchAlgorithmException | InvalidKeyException e) {
       
   170                         shc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   171                             "Unsupported signature algorithm: " +
       
   172                             x509Possession.popPrivateKey.getAlgorithm(), e);
       
   173                     }
       
   174                 }
       
   175 
       
   176                 byte[] signature = null;
       
   177                 try {
       
   178                     updateSignature(signer, shc.clientHelloRandom.randomBytes,
       
   179                             shc.serverHelloRandom.randomBytes,
       
   180                             namedGroup.id, publicPoint);
       
   181                     signature = signer.sign();
       
   182                 } catch (SignatureException ex) {
       
   183                     shc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   184                         "Failed to sign ecdhe parameters: " +
       
   185                         x509Possession.popPrivateKey.getAlgorithm(), ex);
       
   186                 }
       
   187                 paramsSignature = signature;
       
   188             }
       
   189         }
       
   190 
       
   191         ECDHServerKeyExchangeMessage(HandshakeContext handshakeContext,
       
   192                 ByteBuffer m) throws IOException {
       
   193             super(handshakeContext);
       
   194 
       
   195             // This happens in client side only.
       
   196             ClientHandshakeContext chc =
       
   197                     (ClientHandshakeContext)handshakeContext;
       
   198 
       
   199             byte curveType = (byte)Record.getInt8(m);
       
   200             if (curveType != CURVE_NAMED_CURVE) {
       
   201                 // Unlikely as only the named curves should be negotiated.
       
   202                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   203                     "Unsupported ECCurveType: " + curveType);
       
   204             }
       
   205 
       
   206             int namedGroupId = Record.getInt16(m);
       
   207             this.namedGroup = NamedGroup.valueOf(namedGroupId);
       
   208             if (namedGroup == null) {
       
   209                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   210                     "Unknown named group ID: " + namedGroupId);
       
   211             }
       
   212 
       
   213             if (!SupportedGroups.isSupported(namedGroup)) {
       
   214                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   215                     "Unsupported named group: " + namedGroup);
       
   216             }
       
   217 
       
   218             if (namedGroup.oid == null) {
       
   219                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   220                     "Unknown named EC curve: " + namedGroup);
       
   221             }
       
   222 
       
   223             ECParameterSpec parameters =
       
   224                     JsseJce.getECParameterSpec(namedGroup.oid);
       
   225             if (parameters == null) {
       
   226                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   227                     "No supported EC parameter: " + namedGroup);
       
   228             }
       
   229 
       
   230             publicPoint = Record.getBytes8(m);
       
   231             if (publicPoint.length == 0) {
       
   232                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   233                     "Insufficient ECPoint data: " + namedGroup);
       
   234             }
       
   235 
       
   236             ECPublicKey ecPublicKey = null;
       
   237             try {
       
   238                 ECPoint point =
       
   239                         JsseJce.decodePoint(publicPoint, parameters.getCurve());
       
   240                 KeyFactory factory = JsseJce.getKeyFactory("EC");
       
   241                 ecPublicKey = (ECPublicKey)factory.generatePublic(
       
   242                     new ECPublicKeySpec(point, parameters));
       
   243             } catch (NoSuchAlgorithmException |
       
   244                     InvalidKeySpecException | IOException ex) {
       
   245                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
       
   246                     "Invalid ECPoint: " + namedGroup, ex);
       
   247             }
       
   248 
       
   249             publicKey = ecPublicKey;
       
   250 
       
   251             X509Credentials x509Credentials = null;
       
   252             for (SSLCredentials cd : chc.handshakeCredentials) {
       
   253                 if (cd instanceof X509Credentials) {
       
   254                     x509Credentials = (X509Credentials)cd;
       
   255                     break;
       
   256                 }
       
   257             }
       
   258 
       
   259             if (x509Credentials == null) {
       
   260                 // anonymous, no authentication, no signature
       
   261                 if (m.hasRemaining()) {
       
   262                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   263                         "Invalid DH ServerKeyExchange: unknown extra data");
       
   264                 }
       
   265                 this.signatureScheme = null;
       
   266                 this.paramsSignature = null;
       
   267                 this.useExplicitSigAlgorithm = false;
       
   268 
       
   269                 return;
       
   270             }
       
   271 
       
   272             this.useExplicitSigAlgorithm =
       
   273                     chc.negotiatedProtocol.useTLS12PlusSpec();
       
   274             if (useExplicitSigAlgorithm) {
       
   275                 int ssid = Record.getInt16(m);
       
   276                 signatureScheme = SignatureScheme.valueOf(ssid);
       
   277                 if (signatureScheme == null) {
       
   278                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   279                         "Invalid signature algorithm (" + ssid +
       
   280                         ") used in ECDH ServerKeyExchange handshake message");
       
   281                 }
       
   282 
       
   283                 if (!chc.localSupportedSignAlgs.contains(signatureScheme)) {
       
   284                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   285                         "Unsupported signature algorithm (" +
       
   286                         signatureScheme.name +
       
   287                         ") used in ECDH ServerKeyExchange handshake message");
       
   288                 }
       
   289             } else {
       
   290                 signatureScheme = null;
       
   291             }
       
   292 
       
   293             // read and verify the signature
       
   294             paramsSignature = Record.getBytes16(m);
       
   295             Signature signer;
       
   296             if (useExplicitSigAlgorithm) {
       
   297                 try {
       
   298                     signer = signatureScheme.getSignature(
       
   299                             x509Credentials.popPublicKey);
       
   300                 } catch (NoSuchAlgorithmException | InvalidKeyException |
       
   301                         InvalidAlgorithmParameterException nsae) {
       
   302                     chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   303                         "Unsupported signature algorithm: " +
       
   304                         signatureScheme.name, nsae);
       
   305 
       
   306                     return;     // make the compiler happe
       
   307                 }
       
   308             } else {
       
   309                 try {
       
   310                     signer = getSignature(
       
   311                             x509Credentials.popPublicKey.getAlgorithm(),
       
   312                             x509Credentials.popPublicKey);
       
   313                 } catch (NoSuchAlgorithmException | InvalidKeyException e) {
       
   314                     chc.conContext.fatal(Alert.INTERNAL_ERROR,
       
   315                         "Unsupported signature algorithm: " +
       
   316                         x509Credentials.popPublicKey.getAlgorithm(), e);
       
   317 
       
   318                     return;     // make the compiler happe
       
   319                 }
       
   320             }
       
   321 
       
   322             try {
       
   323                 updateSignature(signer,
       
   324                         chc.clientHelloRandom.randomBytes,
       
   325                         chc.serverHelloRandom.randomBytes,
       
   326                         namedGroup.id, publicPoint);
       
   327 
       
   328                 if (!signer.verify(paramsSignature)) {
       
   329                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   330                         "Invalid ECDH ServerKeyExchange signature");
       
   331                 }
       
   332             } catch (SignatureException ex) {
       
   333                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
       
   334                         "Cannot verify ECDH ServerKeyExchange signature", ex);
       
   335             }
       
   336         }
       
   337 
       
   338         @Override
       
   339         public SSLHandshake handshakeType() {
       
   340             return SSLHandshake.SERVER_KEY_EXCHANGE;
       
   341         }
       
   342 
       
   343         @Override
       
   344         public int messageLength() {
       
   345             int sigLen = 0;
       
   346             if (paramsSignature != null) {
       
   347                 sigLen = 2 + paramsSignature.length;
       
   348                 if (useExplicitSigAlgorithm) {
       
   349                     sigLen += SignatureScheme.sizeInRecord();
       
   350                 }
       
   351             }
       
   352 
       
   353             return 4 + publicPoint.length + sigLen;
       
   354         }
       
   355 
       
   356         @Override
       
   357         public void send(HandshakeOutStream hos) throws IOException {
       
   358             hos.putInt8(CURVE_NAMED_CURVE);
       
   359             hos.putInt16(namedGroup.id);
       
   360             hos.putBytes8(publicPoint);
       
   361             if (paramsSignature != null) {
       
   362                 if (useExplicitSigAlgorithm) {
       
   363                     hos.putInt16(signatureScheme.id);
       
   364                 }
       
   365 
       
   366                 hos.putBytes16(paramsSignature);
       
   367             }
       
   368         }
       
   369 
       
   370         @Override
       
   371         public String toString() {
       
   372             if (useExplicitSigAlgorithm) {
       
   373                 MessageFormat messageFormat = new MessageFormat(
       
   374                     "\"ECDH ServerKeyExchange\": '{'\n" +
       
   375                     "  \"parameters\": '{'\n" +
       
   376                     "    \"named group\": \"{0}\"\n" +
       
   377                     "    \"ecdh public\": '{'\n" +
       
   378                     "{1}\n" +
       
   379                     "    '}',\n" +
       
   380                     "  '}',\n" +
       
   381                     "  \"digital signature\":  '{'\n" +
       
   382                     "    \"signature algorithm\": \"{2}\"\n" +
       
   383                     "    \"signature\": '{'\n" +
       
   384                     "{3}\n" +
       
   385                     "    '}',\n" +
       
   386                     "  '}'\n" +
       
   387                     "'}'",
       
   388                     Locale.ENGLISH);
       
   389 
       
   390                 HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   391                 Object[] messageFields = {
       
   392                     namedGroup.name,
       
   393                     Utilities.indent(
       
   394                             hexEncoder.encodeBuffer(publicPoint), "      "),
       
   395                     signatureScheme.name,
       
   396                     Utilities.indent(
       
   397                             hexEncoder.encodeBuffer(paramsSignature), "      ")
       
   398                 };
       
   399                 return messageFormat.format(messageFields);
       
   400             } else if (paramsSignature != null) {
       
   401                 MessageFormat messageFormat = new MessageFormat(
       
   402                     "\"ECDH ServerKeyExchange\": '{'\n" +
       
   403                     "  \"parameters\":  '{'\n" +
       
   404                     "    \"named group\": \"{0}\"\n" +
       
   405                     "    \"ecdh public\": '{'\n" +
       
   406                     "{1}\n" +
       
   407                     "    '}',\n" +
       
   408                     "  '}',\n" +
       
   409                     "  \"signature\": '{'\n" +
       
   410                     "{2}\n" +
       
   411                     "  '}'\n" +
       
   412                     "'}'",
       
   413                     Locale.ENGLISH);
       
   414 
       
   415                 HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   416                 Object[] messageFields = {
       
   417                     namedGroup.name,
       
   418                     Utilities.indent(
       
   419                             hexEncoder.encodeBuffer(publicPoint), "      "),
       
   420                     Utilities.indent(
       
   421                             hexEncoder.encodeBuffer(paramsSignature), "    ")
       
   422                 };
       
   423 
       
   424                 return messageFormat.format(messageFields);
       
   425             } else {    // anonymous
       
   426                 MessageFormat messageFormat = new MessageFormat(
       
   427                     "\"ECDH ServerKeyExchange\": '{'\n" +
       
   428                     "  \"parameters\":  '{'\n" +
       
   429                     "    \"named group\": \"{0}\"\n" +
       
   430                     "    \"ecdh public\": '{'\n" +
       
   431                     "{1}\n" +
       
   432                     "    '}',\n" +
       
   433                     "  '}'\n" +
       
   434                     "'}'",
       
   435                     Locale.ENGLISH);
       
   436 
       
   437                 HexDumpEncoder hexEncoder = new HexDumpEncoder();
       
   438                 Object[] messageFields = {
       
   439                     namedGroup.name,
       
   440                     Utilities.indent(
       
   441                             hexEncoder.encodeBuffer(publicPoint), "      "),
       
   442                 };
       
   443 
       
   444                 return messageFormat.format(messageFields);
       
   445             }
       
   446         }
       
   447 
       
   448         private static Signature getSignature(String keyAlgorithm,
       
   449                 Key key) throws NoSuchAlgorithmException, InvalidKeyException {
       
   450             Signature signer = null;
       
   451             switch (keyAlgorithm) {
       
   452                 case "EC":
       
   453                     signer = JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA);
       
   454                     break;
       
   455                 case "RSA":
       
   456                     signer = RSASignature.getInstance();
       
   457                     break;
       
   458                 default:
       
   459                     throw new NoSuchAlgorithmException(
       
   460                         "neither an RSA or a EC key : " + keyAlgorithm);
       
   461             }
       
   462 
       
   463             if (signer != null) {
       
   464                 if (key instanceof PublicKey) {
       
   465                     signer.initVerify((PublicKey)(key));
       
   466                 } else {
       
   467                     signer.initSign((PrivateKey)key);
       
   468                 }
       
   469             }
       
   470 
       
   471             return signer;
       
   472         }
       
   473 
       
   474         private static void updateSignature(Signature sig,
       
   475                 byte[] clntNonce, byte[] svrNonce, int namedGroupId,
       
   476                 byte[] publicPoint) throws SignatureException {
       
   477             sig.update(clntNonce);
       
   478             sig.update(svrNonce);
       
   479 
       
   480             sig.update(CURVE_NAMED_CURVE);
       
   481             sig.update((byte)((namedGroupId >> 8) & 0xFF));
       
   482             sig.update((byte)(namedGroupId & 0xFF));
       
   483             sig.update((byte)publicPoint.length);
       
   484             sig.update(publicPoint);
       
   485         }
       
   486     }
       
   487 
       
   488     /**
       
   489      * The ECDH "ServerKeyExchange" handshake message producer.
       
   490      */
       
   491     private static final
       
   492             class ECDHServerKeyExchangeProducer implements HandshakeProducer {
       
   493         // Prevent instantiation of this class.
       
   494         private ECDHServerKeyExchangeProducer() {
       
   495             // blank
       
   496         }
       
   497 
       
   498         @Override
       
   499         public byte[] produce(ConnectionContext context,
       
   500                 HandshakeMessage message) throws IOException {
       
   501             // The producing happens in server side only.
       
   502             ServerHandshakeContext shc = (ServerHandshakeContext)context;
       
   503             ECDHServerKeyExchangeMessage skem =
       
   504                     new ECDHServerKeyExchangeMessage(shc);
       
   505             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   506                 SSLLogger.fine(
       
   507                     "Produced ECDH ServerKeyExchange handshake message", skem);
       
   508             }
       
   509 
       
   510             // Output the handshake message.
       
   511             skem.write(shc.handshakeOutput);
       
   512             shc.handshakeOutput.flush();
       
   513 
       
   514             // The handshake message has been delivered.
       
   515             return null;
       
   516         }
       
   517     }
       
   518 
       
   519     /**
       
   520      * The ECDH "ServerKeyExchange" handshake message consumer.
       
   521      */
       
   522     private static final
       
   523             class ECDHServerKeyExchangeConsumer implements SSLConsumer {
       
   524         // Prevent instantiation of this class.
       
   525         private ECDHServerKeyExchangeConsumer() {
       
   526             // blank
       
   527         }
       
   528 
       
   529         @Override
       
   530         public void consume(ConnectionContext context,
       
   531                 ByteBuffer message) throws IOException {
       
   532             // The consuming happens in client side only.
       
   533             ClientHandshakeContext chc = (ClientHandshakeContext)context;
       
   534 
       
   535             ECDHServerKeyExchangeMessage skem =
       
   536                     new ECDHServerKeyExchangeMessage(chc, message);
       
   537             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
       
   538                 SSLLogger.fine(
       
   539                     "Consuming ECDH ServerKeyExchange handshake message", skem);
       
   540             }
       
   541 
       
   542             //
       
   543             // validate
       
   544             //
       
   545             // check constraints of EC PublicKey
       
   546             if (!chc.algorithmConstraints.permits(
       
   547                     EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
       
   548                     skem.publicKey)) {
       
   549                 chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
       
   550                         "ECDH ServerKeyExchange does not comply " +
       
   551                         "to algorithm constraints");
       
   552             }
       
   553 
       
   554             //
       
   555             // update
       
   556             //
       
   557             chc.handshakeCredentials.add(
       
   558                     new ECDHECredentials(skem.publicKey, skem.namedGroup));
       
   559 
       
   560             //
       
   561             // produce
       
   562             //
       
   563             // Need no new handshake message producers here.
       
   564         }
       
   565     }
       
   566 }
       
   567