Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/ECDHServerKeyExchange.java
38830 views
/*1* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ssl;2627import java.io.IOException;28import java.nio.ByteBuffer;29import java.security.CryptoPrimitive;30import java.security.InvalidAlgorithmParameterException;31import java.security.InvalidKeyException;32import java.security.Key;33import java.security.KeyFactory;34import java.security.NoSuchAlgorithmException;35import java.security.PrivateKey;36import java.security.PublicKey;37import java.security.Signature;38import java.security.SignatureException;39import java.security.interfaces.ECPublicKey;40import java.security.spec.ECParameterSpec;41import java.security.spec.ECPoint;42import java.security.spec.ECPublicKeySpec;43import java.security.spec.InvalidKeySpecException;44import java.text.MessageFormat;45import java.util.EnumSet;46import java.util.Locale;47import java.util.Map;48import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;49import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;50import sun.security.ssl.SSLHandshake.HandshakeMessage;51import sun.security.ssl.SupportedGroupsExtension.NamedGroup;52import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;53import sun.security.ssl.X509Authentication.X509Credentials;54import sun.security.ssl.X509Authentication.X509Possession;55import sun.misc.HexDumpEncoder;5657/**58* Pack of the ServerKeyExchange handshake message.59*/60final class ECDHServerKeyExchange {61static final SSLConsumer ecdheHandshakeConsumer =62new ECDHServerKeyExchangeConsumer();63static final HandshakeProducer ecdheHandshakeProducer =64new ECDHServerKeyExchangeProducer();6566/**67* The ECDH ServerKeyExchange handshake message.68*/69private static final70class ECDHServerKeyExchangeMessage extends HandshakeMessage {71private static final byte CURVE_NAMED_CURVE = (byte)0x03;7273// id of the named curve74private final NamedGroup namedGroup;7576// encoded public point77private final byte[] publicPoint;7879// signature bytes, or null if anonymous80private final byte[] paramsSignature;8182// public key object encapsulated in this message83private final ECPublicKey publicKey;8485private final boolean useExplicitSigAlgorithm;8687// the signature algorithm used by this ServerKeyExchange message88private final SignatureScheme signatureScheme;8990ECDHServerKeyExchangeMessage(91HandshakeContext handshakeContext) throws IOException {92super(handshakeContext);9394// This happens in server side only.95ServerHandshakeContext shc =96(ServerHandshakeContext)handshakeContext;9798ECDHEPossession ecdhePossession = null;99X509Possession x509Possession = null;100for (SSLPossession possession : shc.handshakePossessions) {101if (possession instanceof ECDHEPossession) {102ecdhePossession = (ECDHEPossession)possession;103if (x509Possession != null) {104break;105}106} else if (possession instanceof X509Possession) {107x509Possession = (X509Possession)possession;108if (ecdhePossession != null) {109break;110}111}112}113114if (ecdhePossession == null) {115// unlikely116throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,117"No ECDHE credentials negotiated for server key exchange");118}119120publicKey = ecdhePossession.publicKey;121ECParameterSpec params = publicKey.getParams();122ECPoint point = publicKey.getW();123publicPoint = JsseJce.encodePoint(point, params.getCurve());124125this.namedGroup = NamedGroup.valueOf(params);126if ((namedGroup == null) || (namedGroup.oid == null) ) {127// unlikely128throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,129"Unnamed EC parameter spec: " + params);130}131132if (x509Possession == null) {133// anonymous, no authentication, no signature134paramsSignature = null;135signatureScheme = null;136useExplicitSigAlgorithm = false;137} else {138useExplicitSigAlgorithm =139shc.negotiatedProtocol.useTLS12PlusSpec();140Signature signer = null;141if (useExplicitSigAlgorithm) {142Map.Entry<SignatureScheme, Signature> schemeAndSigner =143SignatureScheme.getSignerOfPreferableAlgorithm(144shc.peerRequestedSignatureSchemes,145x509Possession,146shc.negotiatedProtocol);147if (schemeAndSigner == null) {148// Unlikely, the credentials generator should have149// selected the preferable signature algorithm properly.150throw shc.conContext.fatal(Alert.INTERNAL_ERROR,151"No supported signature algorithm for " +152x509Possession.popPrivateKey.getAlgorithm() +153" key");154} else {155signatureScheme = schemeAndSigner.getKey();156signer = schemeAndSigner.getValue();157}158} else {159signatureScheme = null;160try {161signer = getSignature(162x509Possession.popPrivateKey.getAlgorithm(),163x509Possession.popPrivateKey);164} catch (NoSuchAlgorithmException | InvalidKeyException e) {165throw shc.conContext.fatal(Alert.INTERNAL_ERROR,166"Unsupported signature algorithm: " +167x509Possession.popPrivateKey.getAlgorithm(), e);168}169}170171byte[] signature = null;172try {173updateSignature(signer, shc.clientHelloRandom.randomBytes,174shc.serverHelloRandom.randomBytes,175namedGroup.id, publicPoint);176signature = signer.sign();177} catch (SignatureException ex) {178throw shc.conContext.fatal(Alert.INTERNAL_ERROR,179"Failed to sign ecdhe parameters: " +180x509Possession.popPrivateKey.getAlgorithm(), ex);181}182paramsSignature = signature;183}184}185186ECDHServerKeyExchangeMessage(HandshakeContext handshakeContext,187ByteBuffer m) throws IOException {188super(handshakeContext);189190// This happens in client side only.191ClientHandshakeContext chc =192(ClientHandshakeContext)handshakeContext;193194byte curveType = (byte)Record.getInt8(m);195if (curveType != CURVE_NAMED_CURVE) {196// Unlikely as only the named curves should be negotiated.197throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,198"Unsupported ECCurveType: " + curveType);199}200201int namedGroupId = Record.getInt16(m);202this.namedGroup = NamedGroup.valueOf(namedGroupId);203if (namedGroup == null) {204throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,205"Unknown named group ID: " + namedGroupId);206}207208if (!SupportedGroups.isSupported(namedGroup)) {209throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,210"Unsupported named group: " + namedGroup);211}212213if (namedGroup.oid == null) {214throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,215"Unknown named EC curve: " + namedGroup);216}217218ECParameterSpec parameters =219JsseJce.getECParameterSpec(namedGroup.oid);220if (parameters == null) {221throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,222"No supported EC parameter: " + namedGroup);223}224225publicPoint = Record.getBytes8(m);226if (publicPoint.length == 0) {227throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,228"Insufficient ECPoint data: " + namedGroup);229}230231ECPublicKey ecPublicKey = null;232try {233ECPoint point =234JsseJce.decodePoint(publicPoint, parameters.getCurve());235KeyFactory factory = JsseJce.getKeyFactory("EC");236ecPublicKey = (ECPublicKey)factory.generatePublic(237new ECPublicKeySpec(point, parameters));238} catch (NoSuchAlgorithmException |239InvalidKeySpecException | IOException ex) {240throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,241"Invalid ECPoint: " + namedGroup, ex);242}243244publicKey = ecPublicKey;245246X509Credentials x509Credentials = null;247for (SSLCredentials cd : chc.handshakeCredentials) {248if (cd instanceof X509Credentials) {249x509Credentials = (X509Credentials)cd;250break;251}252}253254if (x509Credentials == null) {255// anonymous, no authentication, no signature256if (m.hasRemaining()) {257throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,258"Invalid DH ServerKeyExchange: unknown extra data");259}260this.signatureScheme = null;261this.paramsSignature = null;262this.useExplicitSigAlgorithm = false;263264return;265}266267this.useExplicitSigAlgorithm =268chc.negotiatedProtocol.useTLS12PlusSpec();269if (useExplicitSigAlgorithm) {270int ssid = Record.getInt16(m);271signatureScheme = SignatureScheme.valueOf(ssid);272if (signatureScheme == null) {273throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,274"Invalid signature algorithm (" + ssid +275") used in ECDH ServerKeyExchange handshake message");276}277278if (!chc.localSupportedSignAlgs.contains(signatureScheme)) {279throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,280"Unsupported signature algorithm (" +281signatureScheme.name +282") used in ECDH ServerKeyExchange handshake message");283}284} else {285signatureScheme = null;286}287288// read and verify the signature289paramsSignature = Record.getBytes16(m);290Signature signer;291if (useExplicitSigAlgorithm) {292try {293signer = signatureScheme.getVerifier(294x509Credentials.popPublicKey);295} catch (NoSuchAlgorithmException | InvalidKeyException |296InvalidAlgorithmParameterException nsae) {297throw chc.conContext.fatal(Alert.INTERNAL_ERROR,298"Unsupported signature algorithm: " +299signatureScheme.name, nsae);300}301} else {302try {303signer = getSignature(304x509Credentials.popPublicKey.getAlgorithm(),305x509Credentials.popPublicKey);306} catch (NoSuchAlgorithmException | InvalidKeyException e) {307throw chc.conContext.fatal(Alert.INTERNAL_ERROR,308"Unsupported signature algorithm: " +309x509Credentials.popPublicKey.getAlgorithm(), e);310}311}312313try {314updateSignature(signer,315chc.clientHelloRandom.randomBytes,316chc.serverHelloRandom.randomBytes,317namedGroup.id, publicPoint);318319if (!signer.verify(paramsSignature)) {320throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,321"Invalid ECDH ServerKeyExchange signature");322}323} catch (SignatureException ex) {324throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,325"Cannot verify ECDH ServerKeyExchange signature", ex);326}327}328329@Override330public SSLHandshake handshakeType() {331return SSLHandshake.SERVER_KEY_EXCHANGE;332}333334@Override335public int messageLength() {336int sigLen = 0;337if (paramsSignature != null) {338sigLen = 2 + paramsSignature.length;339if (useExplicitSigAlgorithm) {340sigLen += SignatureScheme.sizeInRecord();341}342}343344return 4 + publicPoint.length + sigLen;345}346347@Override348public void send(HandshakeOutStream hos) throws IOException {349hos.putInt8(CURVE_NAMED_CURVE);350hos.putInt16(namedGroup.id);351hos.putBytes8(publicPoint);352if (paramsSignature != null) {353if (useExplicitSigAlgorithm) {354hos.putInt16(signatureScheme.id);355}356357hos.putBytes16(paramsSignature);358}359}360361@Override362public String toString() {363if (useExplicitSigAlgorithm) {364MessageFormat messageFormat = new MessageFormat(365"\"ECDH ServerKeyExchange\": '{'\n" +366" \"parameters\": '{'\n" +367" \"named group\": \"{0}\"\n" +368" \"ecdh public\": '{'\n" +369"{1}\n" +370" '}',\n" +371" '}',\n" +372" \"digital signature\": '{'\n" +373" \"signature algorithm\": \"{2}\"\n" +374" \"signature\": '{'\n" +375"{3}\n" +376" '}',\n" +377" '}'\n" +378"'}'",379Locale.ENGLISH);380381HexDumpEncoder hexEncoder = new HexDumpEncoder();382Object[] messageFields = {383namedGroup.name,384Utilities.indent(385hexEncoder.encodeBuffer(publicPoint), " "),386signatureScheme.name,387Utilities.indent(388hexEncoder.encodeBuffer(paramsSignature), " ")389};390return messageFormat.format(messageFields);391} else if (paramsSignature != null) {392MessageFormat messageFormat = new MessageFormat(393"\"ECDH ServerKeyExchange\": '{'\n" +394" \"parameters\": '{'\n" +395" \"named group\": \"{0}\"\n" +396" \"ecdh public\": '{'\n" +397"{1}\n" +398" '}',\n" +399" '}',\n" +400" \"signature\": '{'\n" +401"{2}\n" +402" '}'\n" +403"'}'",404Locale.ENGLISH);405406HexDumpEncoder hexEncoder = new HexDumpEncoder();407Object[] messageFields = {408namedGroup.name,409Utilities.indent(410hexEncoder.encodeBuffer(publicPoint), " "),411Utilities.indent(412hexEncoder.encodeBuffer(paramsSignature), " ")413};414415return messageFormat.format(messageFields);416} else { // anonymous417MessageFormat messageFormat = new MessageFormat(418"\"ECDH ServerKeyExchange\": '{'\n" +419" \"parameters\": '{'\n" +420" \"named group\": \"{0}\"\n" +421" \"ecdh public\": '{'\n" +422"{1}\n" +423" '}',\n" +424" '}'\n" +425"'}'",426Locale.ENGLISH);427428HexDumpEncoder hexEncoder = new HexDumpEncoder();429Object[] messageFields = {430namedGroup.name,431Utilities.indent(432hexEncoder.encodeBuffer(publicPoint), " "),433};434435return messageFormat.format(messageFields);436}437}438439private static Signature getSignature(String keyAlgorithm,440Key key) throws NoSuchAlgorithmException, InvalidKeyException {441Signature signer = null;442switch (keyAlgorithm) {443case "EC":444signer = JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA);445break;446case "RSA":447signer = RSASignature.getInstance();448break;449default:450throw new NoSuchAlgorithmException(451"neither an RSA or a EC key : " + keyAlgorithm);452}453454if (signer != null) {455if (key instanceof PublicKey) {456signer.initVerify((PublicKey)(key));457} else {458signer.initSign((PrivateKey)key);459}460}461462return signer;463}464465private static void updateSignature(Signature sig,466byte[] clntNonce, byte[] svrNonce, int namedGroupId,467byte[] publicPoint) throws SignatureException {468sig.update(clntNonce);469sig.update(svrNonce);470471sig.update(CURVE_NAMED_CURVE);472sig.update((byte)((namedGroupId >> 8) & 0xFF));473sig.update((byte)(namedGroupId & 0xFF));474sig.update((byte)publicPoint.length);475sig.update(publicPoint);476}477}478479/**480* The ECDH "ServerKeyExchange" handshake message producer.481*/482private static final483class ECDHServerKeyExchangeProducer implements HandshakeProducer {484// Prevent instantiation of this class.485private ECDHServerKeyExchangeProducer() {486// blank487}488489@Override490public byte[] produce(ConnectionContext context,491HandshakeMessage message) throws IOException {492// The producing happens in server side only.493ServerHandshakeContext shc = (ServerHandshakeContext)context;494ECDHServerKeyExchangeMessage skem =495new ECDHServerKeyExchangeMessage(shc);496if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {497SSLLogger.fine(498"Produced ECDH ServerKeyExchange handshake message", skem);499}500501// Output the handshake message.502skem.write(shc.handshakeOutput);503shc.handshakeOutput.flush();504505// The handshake message has been delivered.506return null;507}508}509510/**511* The ECDH "ServerKeyExchange" handshake message consumer.512*/513private static final514class ECDHServerKeyExchangeConsumer implements SSLConsumer {515// Prevent instantiation of this class.516private ECDHServerKeyExchangeConsumer() {517// blank518}519520@Override521public void consume(ConnectionContext context,522ByteBuffer message) throws IOException {523// The consuming happens in client side only.524ClientHandshakeContext chc = (ClientHandshakeContext)context;525526ECDHServerKeyExchangeMessage skem =527new ECDHServerKeyExchangeMessage(chc, message);528if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {529SSLLogger.fine(530"Consuming ECDH ServerKeyExchange handshake message", skem);531}532533//534// validate535//536// check constraints of EC PublicKey537if (!chc.algorithmConstraints.permits(538EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),539skem.publicKey)) {540throw chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,541"ECDH ServerKeyExchange does not comply " +542"to algorithm constraints");543}544545//546// update547//548chc.handshakeCredentials.add(549new ECDHECredentials(skem.publicKey, skem.namedGroup));550551//552// produce553//554// Need no new handshake message producers here.555}556}557}558559560561