Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/ECDHClientKeyExchange.java
38830 views
/*1* Copyright (c) 2003, 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.AlgorithmConstraints;30import java.security.CryptoPrimitive;31import java.security.GeneralSecurityException;32import java.security.KeyFactory;33import java.security.PublicKey;34import java.security.interfaces.ECPublicKey;35import java.security.spec.ECParameterSpec;36import java.security.spec.ECPoint;37import java.security.spec.ECPublicKeySpec;38import java.text.MessageFormat;39import java.util.EnumSet;40import java.util.Locale;41import javax.crypto.SecretKey;42import javax.net.ssl.SSLHandshakeException;43import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;44import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;45import sun.security.ssl.SSLHandshake.HandshakeMessage;46import sun.security.ssl.SupportedGroupsExtension.NamedGroup;47import sun.security.ssl.X509Authentication.X509Credentials;48import sun.security.ssl.X509Authentication.X509Possession;49import sun.misc.HexDumpEncoder;5051/**52* Pack of the "ClientKeyExchange" handshake message.53*/54final class ECDHClientKeyExchange {55static final SSLConsumer ecdhHandshakeConsumer =56new ECDHClientKeyExchangeConsumer();57static final HandshakeProducer ecdhHandshakeProducer =58new ECDHClientKeyExchangeProducer();5960static final SSLConsumer ecdheHandshakeConsumer =61new ECDHEClientKeyExchangeConsumer();62static final HandshakeProducer ecdheHandshakeProducer =63new ECDHEClientKeyExchangeProducer();6465/**66* The ECDH/ECDHE ClientKeyExchange handshake message.67*/68private static final69class ECDHClientKeyExchangeMessage extends HandshakeMessage {70private final byte[] encodedPoint;7172ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,73ECPublicKey publicKey) {74super(handshakeContext);7576ECPoint point = publicKey.getW();77ECParameterSpec params = publicKey.getParams();78encodedPoint = JsseJce.encodePoint(point, params.getCurve());79}8081ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,82ByteBuffer m) throws IOException {83super(handshakeContext);84if (m.remaining() != 0) { // explicit PublicValueEncoding85this.encodedPoint = Record.getBytes8(m);86} else {87this.encodedPoint = new byte[0];88}89}9091// Check constraints of the specified EC public key.92static void checkConstraints(AlgorithmConstraints constraints,93ECPublicKey publicKey,94byte[] encodedPoint) throws SSLHandshakeException {9596try {97ECParameterSpec params = publicKey.getParams();98ECPoint point =99JsseJce.decodePoint(encodedPoint, params.getCurve());100ECPublicKeySpec spec = new ECPublicKeySpec(point, params);101102KeyFactory kf = JsseJce.getKeyFactory("EC");103ECPublicKey peerPublicKey =104(ECPublicKey)kf.generatePublic(spec);105106// check constraints of ECPublicKey107if (!constraints.permits(108EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),109peerPublicKey)) {110throw new SSLHandshakeException(111"ECPublicKey does not comply to algorithm constraints");112}113} catch (GeneralSecurityException | java.io.IOException e) {114throw (SSLHandshakeException) new SSLHandshakeException(115"Could not generate ECPublicKey").initCause(e);116}117}118119@Override120public SSLHandshake handshakeType() {121return SSLHandshake.CLIENT_KEY_EXCHANGE;122}123124@Override125public int messageLength() {126if (encodedPoint == null || encodedPoint.length == 0) {127return 0;128} else {129return 1 + encodedPoint.length;130}131}132133@Override134public void send(HandshakeOutStream hos) throws IOException {135if (encodedPoint != null && encodedPoint.length != 0) {136hos.putBytes8(encodedPoint);137}138}139140@Override141public String toString() {142MessageFormat messageFormat = new MessageFormat(143"\"ECDH ClientKeyExchange\": '{'\n" +144" \"ecdh public\": '{'\n" +145"{0}\n" +146" '}',\n" +147"'}'",148Locale.ENGLISH);149if (encodedPoint == null || encodedPoint.length == 0) {150Object[] messageFields = {151" <implicit>"152};153return messageFormat.format(messageFields);154} else {155HexDumpEncoder hexEncoder = new HexDumpEncoder();156Object[] messageFields = {157Utilities.indent(158hexEncoder.encodeBuffer(encodedPoint), " "),159};160return messageFormat.format(messageFields);161}162}163}164165/**166* The ECDH "ClientKeyExchange" handshake message producer.167*/168private static final169class ECDHClientKeyExchangeProducer implements HandshakeProducer {170// Prevent instantiation of this class.171private ECDHClientKeyExchangeProducer() {172// blank173}174175@Override176public byte[] produce(ConnectionContext context,177HandshakeMessage message) throws IOException {178// The producing happens in client side only.179ClientHandshakeContext chc = (ClientHandshakeContext)context;180181X509Credentials x509Credentials = null;182for (SSLCredentials credential : chc.handshakeCredentials) {183if (credential instanceof X509Credentials) {184x509Credentials = (X509Credentials)credential;185break;186}187}188189if (x509Credentials == null) {190throw chc.conContext.fatal(Alert.INTERNAL_ERROR,191"No server certificate for ECDH client key exchange");192}193194PublicKey publicKey = x509Credentials.popPublicKey;195if (!publicKey.getAlgorithm().equals("EC")) {196throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,197"Not EC server certificate for ECDH client key exchange");198}199200ECParameterSpec params = ((ECPublicKey)publicKey).getParams();201NamedGroup namedGroup = NamedGroup.valueOf(params);202if (namedGroup == null) {203throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,204"Unsupported EC server cert for ECDH client key exchange");205}206207ECDHEPossession ecdhePossession = new ECDHEPossession(208namedGroup, chc.sslContext.getSecureRandom());209chc.handshakePossessions.add(ecdhePossession);210ECDHClientKeyExchangeMessage cke =211new ECDHClientKeyExchangeMessage(212chc, ecdhePossession.publicKey);213if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {214SSLLogger.fine(215"Produced ECDH ClientKeyExchange handshake message", cke);216}217218// Output the handshake message.219cke.write(chc.handshakeOutput);220chc.handshakeOutput.flush();221222// update the states223SSLKeyExchange ke = SSLKeyExchange.valueOf(224chc.negotiatedCipherSuite.keyExchange,225chc.negotiatedProtocol);226if (ke == null) {227// unlikely228throw chc.conContext.fatal(Alert.INTERNAL_ERROR,229"Not supported key exchange type");230} else {231SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);232SecretKey masterSecret =233masterKD.deriveKey("MasterSecret", null);234chc.handshakeSession.setMasterSecret(masterSecret);235236SSLTrafficKeyDerivation kd =237SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);238if (kd == null) {239// unlikely240throw chc.conContext.fatal(Alert.INTERNAL_ERROR,241"Not supported key derivation: " +242chc.negotiatedProtocol);243} else {244chc.handshakeKeyDerivation =245kd.createKeyDerivation(chc, masterSecret);246}247}248249// The handshake message has been delivered.250return null;251}252}253254/**255* The ECDH "ClientKeyExchange" handshake message consumer.256*/257private static final258class ECDHClientKeyExchangeConsumer implements SSLConsumer {259// Prevent instantiation of this class.260private ECDHClientKeyExchangeConsumer() {261// blank262}263264@Override265public void consume(ConnectionContext context,266ByteBuffer message) throws IOException {267// The consuming happens in server side only.268ServerHandshakeContext shc = (ServerHandshakeContext)context;269270X509Possession x509Possession = null;271for (SSLPossession possession : shc.handshakePossessions) {272if (possession instanceof X509Possession) {273x509Possession = (X509Possession)possession;274break;275}276}277278if (x509Possession == null) {279// unlikely, have been checked during cipher suite negotiation.280throw shc.conContext.fatal(Alert.INTERNAL_ERROR,281"No expected EC server cert for ECDH client key exchange");282}283284ECParameterSpec params = x509Possession.getECParameterSpec();285if (params == null) {286// unlikely, have been checked during cipher suite negotiation.287throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,288"Not EC server cert for ECDH client key exchange");289}290291NamedGroup namedGroup = NamedGroup.valueOf(params);292if (namedGroup == null) {293// unlikely, have been checked during cipher suite negotiation.294throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,295"Unsupported EC server cert for ECDH client key exchange");296}297298SSLKeyExchange ke = SSLKeyExchange.valueOf(299shc.negotiatedCipherSuite.keyExchange,300shc.negotiatedProtocol);301if (ke == null) {302// unlikely303throw shc.conContext.fatal(Alert.INTERNAL_ERROR,304"Not supported key exchange type");305}306307// parse the handshake message308ECDHClientKeyExchangeMessage cke =309new ECDHClientKeyExchangeMessage(shc, message);310if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {311SSLLogger.fine(312"Consuming ECDH ClientKeyExchange handshake message", cke);313}314315// create the credentials316try {317ECPoint point =318JsseJce.decodePoint(cke.encodedPoint, params.getCurve());319ECPublicKeySpec spec = new ECPublicKeySpec(point, params);320321KeyFactory kf = JsseJce.getKeyFactory("EC");322ECPublicKey peerPublicKey =323(ECPublicKey)kf.generatePublic(spec);324325// check constraints of peer ECPublicKey326if (!shc.algorithmConstraints.permits(327EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),328peerPublicKey)) {329throw new SSLHandshakeException(330"ECPublicKey does not comply to algorithm constraints");331}332333shc.handshakeCredentials.add(new ECDHECredentials(334peerPublicKey, namedGroup));335} catch (GeneralSecurityException | java.io.IOException e) {336throw (SSLHandshakeException)(new SSLHandshakeException(337"Could not generate ECPublicKey").initCause(e));338}339340// update the states341SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);342SecretKey masterSecret =343masterKD.deriveKey("MasterSecret", null);344shc.handshakeSession.setMasterSecret(masterSecret);345346SSLTrafficKeyDerivation kd =347SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);348if (kd == null) {349// unlikely350throw shc.conContext.fatal(Alert.INTERNAL_ERROR,351"Not supported key derivation: " + shc.negotiatedProtocol);352} else {353shc.handshakeKeyDerivation =354kd.createKeyDerivation(shc, masterSecret);355}356}357}358359/**360* The ECDHE "ClientKeyExchange" handshake message producer.361*/362private static final363class ECDHEClientKeyExchangeProducer implements HandshakeProducer {364// Prevent instantiation of this class.365private ECDHEClientKeyExchangeProducer() {366// blank367}368369@Override370public byte[] produce(ConnectionContext context,371HandshakeMessage message) throws IOException {372// The producing happens in client side only.373ClientHandshakeContext chc = (ClientHandshakeContext)context;374375ECDHECredentials ecdheCredentials = null;376for (SSLCredentials cd : chc.handshakeCredentials) {377if (cd instanceof ECDHECredentials) {378ecdheCredentials = (ECDHECredentials)cd;379break;380}381}382383if (ecdheCredentials == null) {384throw chc.conContext.fatal(Alert.INTERNAL_ERROR,385"No ECDHE credentials negotiated for client key exchange");386}387388ECDHEPossession ecdhePossession = new ECDHEPossession(389ecdheCredentials, chc.sslContext.getSecureRandom());390chc.handshakePossessions.add(ecdhePossession);391ECDHClientKeyExchangeMessage cke =392new ECDHClientKeyExchangeMessage(393chc, ecdhePossession.publicKey);394if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {395SSLLogger.fine(396"Produced ECDHE ClientKeyExchange handshake message", cke);397}398399// Output the handshake message.400cke.write(chc.handshakeOutput);401chc.handshakeOutput.flush();402403// update the states404SSLKeyExchange ke = SSLKeyExchange.valueOf(405chc.negotiatedCipherSuite.keyExchange,406chc.negotiatedProtocol);407if (ke == null) {408// unlikely409throw chc.conContext.fatal(Alert.INTERNAL_ERROR,410"Not supported key exchange type");411} else {412SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);413SecretKey masterSecret =414masterKD.deriveKey("MasterSecret", null);415chc.handshakeSession.setMasterSecret(masterSecret);416417SSLTrafficKeyDerivation kd =418SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);419if (kd == null) {420// unlikely421throw chc.conContext.fatal(Alert.INTERNAL_ERROR,422"Not supported key derivation: " +423chc.negotiatedProtocol);424} else {425chc.handshakeKeyDerivation =426kd.createKeyDerivation(chc, masterSecret);427}428}429430// The handshake message has been delivered.431return null;432}433}434435/**436* The ECDHE "ClientKeyExchange" handshake message consumer.437*/438private static final439class ECDHEClientKeyExchangeConsumer implements SSLConsumer {440// Prevent instantiation of this class.441private ECDHEClientKeyExchangeConsumer() {442// blank443}444445@Override446public void consume(ConnectionContext context,447ByteBuffer message) throws IOException {448// The consuming happens in server side only.449ServerHandshakeContext shc = (ServerHandshakeContext)context;450451ECDHEPossession ecdhePossession = null;452for (SSLPossession possession : shc.handshakePossessions) {453if (possession instanceof ECDHEPossession) {454ecdhePossession = (ECDHEPossession)possession;455break;456}457}458if (ecdhePossession == null) {459// unlikely460throw shc.conContext.fatal(Alert.INTERNAL_ERROR,461"No expected ECDHE possessions for client key exchange");462}463464ECParameterSpec params = ecdhePossession.publicKey.getParams();465NamedGroup namedGroup = NamedGroup.valueOf(params);466if (namedGroup == null) {467// unlikely, have been checked during cipher suite negotiation.468throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,469"Unsupported EC server cert for ECDHE client key exchange");470}471472SSLKeyExchange ke = SSLKeyExchange.valueOf(473shc.negotiatedCipherSuite.keyExchange,474shc.negotiatedProtocol);475if (ke == null) {476// unlikely477throw shc.conContext.fatal(Alert.INTERNAL_ERROR,478"Not supported key exchange type");479}480481// parse the handshake message482ECDHClientKeyExchangeMessage cke =483new ECDHClientKeyExchangeMessage(shc, message);484if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {485SSLLogger.fine(486"Consuming ECDHE ClientKeyExchange handshake message", cke);487}488489// create the credentials490try {491ECPoint point =492JsseJce.decodePoint(cke.encodedPoint, params.getCurve());493ECPublicKeySpec spec = new ECPublicKeySpec(point, params);494495KeyFactory kf = JsseJce.getKeyFactory("EC");496ECPublicKey peerPublicKey =497(ECPublicKey)kf.generatePublic(spec);498499// check constraints of peer ECPublicKey500if (!shc.algorithmConstraints.permits(501EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),502peerPublicKey)) {503throw new SSLHandshakeException(504"ECPublicKey does not comply to algorithm constraints");505}506507shc.handshakeCredentials.add(new ECDHECredentials(508peerPublicKey, namedGroup));509} catch (GeneralSecurityException | java.io.IOException e) {510throw (SSLHandshakeException)(new SSLHandshakeException(511"Could not generate ECPublicKey").initCause(e));512}513514// update the states515SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);516SecretKey masterSecret =517masterKD.deriveKey("MasterSecret", null);518shc.handshakeSession.setMasterSecret(masterSecret);519520SSLTrafficKeyDerivation kd =521SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);522if (kd == null) {523// unlikely524throw shc.conContext.fatal(Alert.INTERNAL_ERROR,525"Not supported key derivation: " + shc.negotiatedProtocol);526} else {527shc.handshakeKeyDerivation =528kd.createKeyDerivation(shc, masterSecret);529}530}531}532}533534535