|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  |  | 
|  | package sun.security.ssl; | 
|  |  | 
|  | import java.io.IOException; | 
|  | import java.nio.ByteBuffer; | 
|  | import java.security.CryptoPrimitive; | 
|  | import java.security.InvalidAlgorithmParameterException; | 
|  | import java.security.InvalidKeyException; | 
|  | import java.security.Key; | 
|  | import java.security.KeyFactory; | 
|  | import java.security.NoSuchAlgorithmException; | 
|  | import java.security.PrivateKey; | 
|  | import java.security.PublicKey; | 
|  | import java.security.Signature; | 
|  | import java.security.SignatureException; | 
|  | import java.security.interfaces.ECPublicKey; | 
|  | import java.security.spec.ECParameterSpec; | 
|  | import java.security.spec.ECPoint; | 
|  | import java.security.spec.ECPublicKeySpec; | 
|  | import java.security.spec.InvalidKeySpecException; | 
|  | import java.text.MessageFormat; | 
|  | import java.util.EnumSet; | 
|  | import java.util.Locale; | 
|  | import sun.security.ssl.ECDHKeyExchange.ECDHECredentials; | 
|  | import sun.security.ssl.ECDHKeyExchange.ECDHEPossession; | 
|  | import sun.security.ssl.SSLHandshake.HandshakeMessage; | 
|  | import sun.security.ssl.SupportedGroupsExtension.NamedGroup; | 
|  | import sun.security.ssl.SupportedGroupsExtension.SupportedGroups; | 
|  | import sun.security.ssl.X509Authentication.X509Credentials; | 
|  | import sun.security.ssl.X509Authentication.X509Possession; | 
|  | import sun.security.util.HexDumpEncoder; | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  | final class ECDHServerKeyExchange { | 
|  |     static final SSLConsumer ecdheHandshakeConsumer = | 
|  |             new ECDHServerKeyExchangeConsumer(); | 
|  |     static final HandshakeProducer ecdheHandshakeProducer = | 
|  |             new ECDHServerKeyExchangeProducer(); | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     private static final | 
|  |             class ECDHServerKeyExchangeMessage extends HandshakeMessage { | 
|  |         private static final byte CURVE_NAMED_CURVE = (byte)0x03; | 
|  |  | 
|  |          | 
|  |         private final NamedGroup namedGroup; | 
|  |  | 
|  |          | 
|  |         private final byte[] publicPoint; | 
|  |  | 
|  |          | 
|  |         private final byte[] paramsSignature; | 
|  |  | 
|  |          | 
|  |         private final ECPublicKey publicKey; | 
|  |  | 
|  |         private final boolean useExplicitSigAlgorithm; | 
|  |  | 
|  |          | 
|  |         private final SignatureScheme signatureScheme; | 
|  |  | 
|  |         ECDHServerKeyExchangeMessage( | 
|  |                 HandshakeContext handshakeContext) throws IOException { | 
|  |             super(handshakeContext); | 
|  |  | 
|  |              | 
|  |             ServerHandshakeContext shc = | 
|  |                     (ServerHandshakeContext)handshakeContext; | 
|  |  | 
|  |             ECDHEPossession ecdhePossession = null; | 
|  |             X509Possession x509Possession = null; | 
|  |             for (SSLPossession possession : shc.handshakePossessions) { | 
|  |                 if (possession instanceof ECDHEPossession) { | 
|  |                     ecdhePossession = (ECDHEPossession)possession; | 
|  |                     if (x509Possession != null) { | 
|  |                         break; | 
|  |                     } | 
|  |                 } else if (possession instanceof X509Possession) { | 
|  |                     x509Possession = (X509Possession)possession; | 
|  |                     if (ecdhePossession != null) { | 
|  |                         break; | 
|  |                     } | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             if (ecdhePossession == null) { | 
|  |                  | 
|  |                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "No ECDHE credentials negotiated for server key exchange"); | 
|  |             } | 
|  |  | 
|  |             publicKey = ecdhePossession.publicKey; | 
|  |             ECParameterSpec params = publicKey.getParams(); | 
|  |             ECPoint point = publicKey.getW(); | 
|  |             publicPoint = JsseJce.encodePoint(point, params.getCurve()); | 
|  |  | 
|  |             this.namedGroup = NamedGroup.valueOf(params); | 
|  |             if ((namedGroup == null) || (namedGroup.oid == null) ) { | 
|  |                  | 
|  |                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "Unnamed EC parameter spec: " + params); | 
|  |             } | 
|  |  | 
|  |             if (x509Possession == null) { | 
|  |                  | 
|  |                 paramsSignature = null; | 
|  |                 signatureScheme = null; | 
|  |                 useExplicitSigAlgorithm = false; | 
|  |             } else { | 
|  |                 useExplicitSigAlgorithm = | 
|  |                         shc.negotiatedProtocol.useTLS12PlusSpec(); | 
|  |                 Signature signer = null; | 
|  |                 if (useExplicitSigAlgorithm) { | 
|  |                     signatureScheme = SignatureScheme.getPreferableAlgorithm( | 
|  |                             shc.peerRequestedSignatureSchemes, | 
|  |                             x509Possession.popPrivateKey, | 
|  |                             shc.negotiatedProtocol); | 
|  |                     if (signatureScheme == null) { | 
|  |                         // Unlikely, the credentials generator should have | 
|  |                          | 
|  |                         shc.conContext.fatal(Alert.INTERNAL_ERROR, | 
|  |                                 "No preferred signature algorithm for " + | 
|  |                                 x509Possession.popPrivateKey.getAlgorithm() + | 
|  |                                 "  key"); | 
|  |                     } | 
|  |                     try { | 
|  |                         signer = signatureScheme.getSignature( | 
|  |                                 x509Possession.popPrivateKey); | 
|  |                     } catch (NoSuchAlgorithmException | InvalidKeyException | | 
|  |                             InvalidAlgorithmParameterException nsae) { | 
|  |                         shc.conContext.fatal(Alert.INTERNAL_ERROR, | 
|  |                             "Unsupported signature algorithm: " + | 
|  |                             signatureScheme.name, nsae); | 
|  |                     } | 
|  |                 } else { | 
|  |                     signatureScheme = null; | 
|  |                     try { | 
|  |                         signer = getSignature( | 
|  |                                 x509Possession.popPrivateKey.getAlgorithm(), | 
|  |                                 x509Possession.popPrivateKey); | 
|  |                     } catch (NoSuchAlgorithmException | InvalidKeyException e) { | 
|  |                         shc.conContext.fatal(Alert.INTERNAL_ERROR, | 
|  |                             "Unsupported signature algorithm: " + | 
|  |                             x509Possession.popPrivateKey.getAlgorithm(), e); | 
|  |                     } | 
|  |                 } | 
|  |  | 
|  |                 byte[] signature = null; | 
|  |                 try { | 
|  |                     updateSignature(signer, shc.clientHelloRandom.randomBytes, | 
|  |                             shc.serverHelloRandom.randomBytes, | 
|  |                             namedGroup.id, publicPoint); | 
|  |                     signature = signer.sign(); | 
|  |                 } catch (SignatureException ex) { | 
|  |                     shc.conContext.fatal(Alert.INTERNAL_ERROR, | 
|  |                         "Failed to sign ecdhe parameters: " + | 
|  |                         x509Possession.popPrivateKey.getAlgorithm(), ex); | 
|  |                 } | 
|  |                 paramsSignature = signature; | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         ECDHServerKeyExchangeMessage(HandshakeContext handshakeContext, | 
|  |                 ByteBuffer m) throws IOException { | 
|  |             super(handshakeContext); | 
|  |  | 
|  |              | 
|  |             ClientHandshakeContext chc = | 
|  |                     (ClientHandshakeContext)handshakeContext; | 
|  |  | 
|  |             byte curveType = (byte)Record.getInt8(m); | 
|  |             if (curveType != CURVE_NAMED_CURVE) { | 
|  |                  | 
|  |                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "Unsupported ECCurveType: " + curveType); | 
|  |             } | 
|  |  | 
|  |             int namedGroupId = Record.getInt16(m); | 
|  |             this.namedGroup = NamedGroup.valueOf(namedGroupId); | 
|  |             if (namedGroup == null) { | 
|  |                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "Unknown named group ID: " + namedGroupId); | 
|  |             } | 
|  |  | 
|  |             if (!SupportedGroups.isSupported(namedGroup)) { | 
|  |                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "Unsupported named group: " + namedGroup); | 
|  |             } | 
|  |  | 
|  |             if (namedGroup.oid == null) { | 
|  |                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "Unknown named EC curve: " + namedGroup); | 
|  |             } | 
|  |  | 
|  |             ECParameterSpec parameters = | 
|  |                     JsseJce.getECParameterSpec(namedGroup.oid); | 
|  |             if (parameters == null) { | 
|  |                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "No supported EC parameter: " + namedGroup); | 
|  |             } | 
|  |  | 
|  |             publicPoint = Record.getBytes8(m); | 
|  |             if (publicPoint.length == 0) { | 
|  |                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "Insufficient ECPoint data: " + namedGroup); | 
|  |             } | 
|  |  | 
|  |             ECPublicKey ecPublicKey = null; | 
|  |             try { | 
|  |                 ECPoint point = | 
|  |                         JsseJce.decodePoint(publicPoint, parameters.getCurve()); | 
|  |                 KeyFactory factory = JsseJce.getKeyFactory("EC"); | 
|  |                 ecPublicKey = (ECPublicKey)factory.generatePublic( | 
|  |                     new ECPublicKeySpec(point, parameters)); | 
|  |             } catch (NoSuchAlgorithmException | | 
|  |                     InvalidKeySpecException | IOException ex) { | 
|  |                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, | 
|  |                     "Invalid ECPoint: " + namedGroup, ex); | 
|  |             } | 
|  |  | 
|  |             publicKey = ecPublicKey; | 
|  |  | 
|  |             X509Credentials x509Credentials = null; | 
|  |             for (SSLCredentials cd : chc.handshakeCredentials) { | 
|  |                 if (cd instanceof X509Credentials) { | 
|  |                     x509Credentials = (X509Credentials)cd; | 
|  |                     break; | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             if (x509Credentials == null) { | 
|  |                  | 
|  |                 if (m.hasRemaining()) { | 
|  |                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, | 
|  |                         "Invalid DH ServerKeyExchange: unknown extra data"); | 
|  |                 } | 
|  |                 this.signatureScheme = null; | 
|  |                 this.paramsSignature = null; | 
|  |                 this.useExplicitSigAlgorithm = false; | 
|  |  | 
|  |                 return; | 
|  |             } | 
|  |  | 
|  |             this.useExplicitSigAlgorithm = | 
|  |                     chc.negotiatedProtocol.useTLS12PlusSpec(); | 
|  |             if (useExplicitSigAlgorithm) { | 
|  |                 int ssid = Record.getInt16(m); | 
|  |                 signatureScheme = SignatureScheme.valueOf(ssid); | 
|  |                 if (signatureScheme == null) { | 
|  |                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, | 
|  |                         "Invalid signature algorithm (" + ssid + | 
|  |                         ") used in ECDH ServerKeyExchange handshake message"); | 
|  |                 } | 
|  |  | 
|  |                 if (!chc.localSupportedSignAlgs.contains(signatureScheme)) { | 
|  |                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, | 
|  |                         "Unsupported signature algorithm (" + | 
|  |                         signatureScheme.name + | 
|  |                         ") used in ECDH ServerKeyExchange handshake message"); | 
|  |                 } | 
|  |             } else { | 
|  |                 signatureScheme = null; | 
|  |             } | 
|  |  | 
|  |              | 
|  |             paramsSignature = Record.getBytes16(m); | 
|  |             Signature signer; | 
|  |             if (useExplicitSigAlgorithm) { | 
|  |                 try { | 
|  |                     signer = signatureScheme.getSignature( | 
|  |                             x509Credentials.popPublicKey); | 
|  |                 } catch (NoSuchAlgorithmException | InvalidKeyException | | 
|  |                         InvalidAlgorithmParameterException nsae) { | 
|  |                     chc.conContext.fatal(Alert.INTERNAL_ERROR, | 
|  |                         "Unsupported signature algorithm: " + | 
|  |                         signatureScheme.name, nsae); | 
|  |  | 
|  |                     return;      | 
|  |                 } | 
|  |             } else { | 
|  |                 try { | 
|  |                     signer = getSignature( | 
|  |                             x509Credentials.popPublicKey.getAlgorithm(), | 
|  |                             x509Credentials.popPublicKey); | 
|  |                 } catch (NoSuchAlgorithmException | InvalidKeyException e) { | 
|  |                     chc.conContext.fatal(Alert.INTERNAL_ERROR, | 
|  |                         "Unsupported signature algorithm: " + | 
|  |                         x509Credentials.popPublicKey.getAlgorithm(), e); | 
|  |  | 
|  |                     return;      | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             try { | 
|  |                 updateSignature(signer, | 
|  |                         chc.clientHelloRandom.randomBytes, | 
|  |                         chc.serverHelloRandom.randomBytes, | 
|  |                         namedGroup.id, publicPoint); | 
|  |  | 
|  |                 if (!signer.verify(paramsSignature)) { | 
|  |                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, | 
|  |                         "Invalid ECDH ServerKeyExchange signature"); | 
|  |                 } | 
|  |             } catch (SignatureException ex) { | 
|  |                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE, | 
|  |                         "Cannot verify ECDH ServerKeyExchange signature", ex); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         @Override | 
|  |         public SSLHandshake handshakeType() { | 
|  |             return SSLHandshake.SERVER_KEY_EXCHANGE; | 
|  |         } | 
|  |  | 
|  |         @Override | 
|  |         public int messageLength() { | 
|  |             int sigLen = 0; | 
|  |             if (paramsSignature != null) { | 
|  |                 sigLen = 2 + paramsSignature.length; | 
|  |                 if (useExplicitSigAlgorithm) { | 
|  |                     sigLen += SignatureScheme.sizeInRecord(); | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             return 4 + publicPoint.length + sigLen; | 
|  |         } | 
|  |  | 
|  |         @Override | 
|  |         public void send(HandshakeOutStream hos) throws IOException { | 
|  |             hos.putInt8(CURVE_NAMED_CURVE); | 
|  |             hos.putInt16(namedGroup.id); | 
|  |             hos.putBytes8(publicPoint); | 
|  |             if (paramsSignature != null) { | 
|  |                 if (useExplicitSigAlgorithm) { | 
|  |                     hos.putInt16(signatureScheme.id); | 
|  |                 } | 
|  |  | 
|  |                 hos.putBytes16(paramsSignature); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         @Override | 
|  |         public String toString() { | 
|  |             if (useExplicitSigAlgorithm) { | 
|  |                 MessageFormat messageFormat = new MessageFormat( | 
|  |                     "\"ECDH ServerKeyExchange\": '{'\n" + | 
|  |                     "  \"parameters\": '{'\n" + | 
|  |                     "    \"named group\": \"{0}\"\n" + | 
|  |                     "    \"ecdh public\": '{'\n" + | 
|  |                     "{1}\n" + | 
|  |                     "    '}',\n" + | 
|  |                     "  '}',\n" + | 
|  |                     "  \"digital signature\":  '{'\n" + | 
|  |                     "    \"signature algorithm\": \"{2}\"\n" + | 
|  |                     "    \"signature\": '{'\n" + | 
|  |                     "{3}\n" + | 
|  |                     "    '}',\n" + | 
|  |                     "  '}'\n" + | 
|  |                     "'}'", | 
|  |                     Locale.ENGLISH); | 
|  |  | 
|  |                 HexDumpEncoder hexEncoder = new HexDumpEncoder(); | 
|  |                 Object[] messageFields = { | 
|  |                     namedGroup.name, | 
|  |                     Utilities.indent( | 
|  |                             hexEncoder.encodeBuffer(publicPoint), "      "), | 
|  |                     signatureScheme.name, | 
|  |                     Utilities.indent( | 
|  |                             hexEncoder.encodeBuffer(paramsSignature), "      ") | 
|  |                 }; | 
|  |                 return messageFormat.format(messageFields); | 
|  |             } else if (paramsSignature != null) { | 
|  |                 MessageFormat messageFormat = new MessageFormat( | 
|  |                     "\"ECDH ServerKeyExchange\": '{'\n" + | 
|  |                     "  \"parameters\":  '{'\n" + | 
|  |                     "    \"named group\": \"{0}\"\n" + | 
|  |                     "    \"ecdh public\": '{'\n" + | 
|  |                     "{1}\n" + | 
|  |                     "    '}',\n" + | 
|  |                     "  '}',\n" + | 
|  |                     "  \"signature\": '{'\n" + | 
|  |                     "{2}\n" + | 
|  |                     "  '}'\n" + | 
|  |                     "'}'", | 
|  |                     Locale.ENGLISH); | 
|  |  | 
|  |                 HexDumpEncoder hexEncoder = new HexDumpEncoder(); | 
|  |                 Object[] messageFields = { | 
|  |                     namedGroup.name, | 
|  |                     Utilities.indent( | 
|  |                             hexEncoder.encodeBuffer(publicPoint), "      "), | 
|  |                     Utilities.indent( | 
|  |                             hexEncoder.encodeBuffer(paramsSignature), "    ") | 
|  |                 }; | 
|  |  | 
|  |                 return messageFormat.format(messageFields); | 
|  |             } else {     | 
|  |                 MessageFormat messageFormat = new MessageFormat( | 
|  |                     "\"ECDH ServerKeyExchange\": '{'\n" + | 
|  |                     "  \"parameters\":  '{'\n" + | 
|  |                     "    \"named group\": \"{0}\"\n" + | 
|  |                     "    \"ecdh public\": '{'\n" + | 
|  |                     "{1}\n" + | 
|  |                     "    '}',\n" + | 
|  |                     "  '}'\n" + | 
|  |                     "'}'", | 
|  |                     Locale.ENGLISH); | 
|  |  | 
|  |                 HexDumpEncoder hexEncoder = new HexDumpEncoder(); | 
|  |                 Object[] messageFields = { | 
|  |                     namedGroup.name, | 
|  |                     Utilities.indent( | 
|  |                             hexEncoder.encodeBuffer(publicPoint), "      "), | 
|  |                 }; | 
|  |  | 
|  |                 return messageFormat.format(messageFields); | 
|  |             } | 
|  |         } | 
|  |  | 
|  |         private static Signature getSignature(String keyAlgorithm, | 
|  |                 Key key) throws NoSuchAlgorithmException, InvalidKeyException { | 
|  |             Signature signer = null; | 
|  |             switch (keyAlgorithm) { | 
|  |                 case "EC": | 
|  |                     signer = JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA); | 
|  |                     break; | 
|  |                 case "RSA": | 
|  |                     signer = RSASignature.getInstance(); | 
|  |                     break; | 
|  |                 default: | 
|  |                     throw new NoSuchAlgorithmException( | 
|  |                         "neither an RSA or a EC key : " + keyAlgorithm); | 
|  |             } | 
|  |  | 
|  |             if (signer != null) { | 
|  |                 if (key instanceof PublicKey) { | 
|  |                     signer.initVerify((PublicKey)(key)); | 
|  |                 } else { | 
|  |                     signer.initSign((PrivateKey)key); | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             return signer; | 
|  |         } | 
|  |  | 
|  |         private static void updateSignature(Signature sig, | 
|  |                 byte[] clntNonce, byte[] svrNonce, int namedGroupId, | 
|  |                 byte[] publicPoint) throws SignatureException { | 
|  |             sig.update(clntNonce); | 
|  |             sig.update(svrNonce); | 
|  |  | 
|  |             sig.update(CURVE_NAMED_CURVE); | 
|  |             sig.update((byte)((namedGroupId >> 8) & 0xFF)); | 
|  |             sig.update((byte)(namedGroupId & 0xFF)); | 
|  |             sig.update((byte)publicPoint.length); | 
|  |             sig.update(publicPoint); | 
|  |         } | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     private static final | 
|  |             class ECDHServerKeyExchangeProducer implements HandshakeProducer { | 
|  |          | 
|  |         private ECDHServerKeyExchangeProducer() { | 
|  |             // blank | 
|  |         } | 
|  |  | 
|  |         @Override | 
|  |         public byte[] produce(ConnectionContext context, | 
|  |                 HandshakeMessage message) throws IOException { | 
|  |              | 
|  |             ServerHandshakeContext shc = (ServerHandshakeContext)context; | 
|  |             ECDHServerKeyExchangeMessage skem = | 
|  |                     new ECDHServerKeyExchangeMessage(shc); | 
|  |             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
|  |                 SSLLogger.fine( | 
|  |                     "Produced ECDH ServerKeyExchange handshake message", skem); | 
|  |             } | 
|  |  | 
|  |              | 
|  |             skem.write(shc.handshakeOutput); | 
|  |             shc.handshakeOutput.flush(); | 
|  |  | 
|  |              | 
|  |             return null; | 
|  |         } | 
|  |     } | 
|  |  | 
|  |      | 
|  |  | 
|  |      */ | 
|  |     private static final | 
|  |             class ECDHServerKeyExchangeConsumer implements SSLConsumer { | 
|  |          | 
|  |         private ECDHServerKeyExchangeConsumer() { | 
|  |             // blank | 
|  |         } | 
|  |  | 
|  |         @Override | 
|  |         public void consume(ConnectionContext context, | 
|  |                 ByteBuffer message) throws IOException { | 
|  |              | 
|  |             ClientHandshakeContext chc = (ClientHandshakeContext)context; | 
|  |  | 
|  |             ECDHServerKeyExchangeMessage skem = | 
|  |                     new ECDHServerKeyExchangeMessage(chc, message); | 
|  |             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
|  |                 SSLLogger.fine( | 
|  |                     "Consuming ECDH ServerKeyExchange handshake message", skem); | 
|  |             } | 
|  |  | 
|  |             // | 
|  |             // validate | 
|  |             // | 
|  |              | 
|  |             if (!chc.algorithmConstraints.permits( | 
|  |                     EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), | 
|  |                     skem.publicKey)) { | 
|  |                 chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY, | 
|  |                         "ECDH ServerKeyExchange does not comply " + | 
|  |                         "to algorithm constraints"); | 
|  |             } | 
|  |  | 
|  |             // | 
|  |             // update | 
|  |              | 
|  |             chc.handshakeCredentials.add( | 
|  |                     new ECDHECredentials(skem.publicKey, skem.namedGroup)); | 
|  |  | 
|  |             // | 
|  |             // produce | 
|  |             // | 
|  |             // Need no new handshake message producers here. | 
|  |         } | 
|  |     } | 
|  | } | 
|  |  |