Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/DHClientKeyExchange.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.math.BigInteger;29import java.nio.ByteBuffer;30import java.security.CryptoPrimitive;31import java.security.GeneralSecurityException;32import java.security.KeyFactory;33import java.text.MessageFormat;34import java.util.EnumSet;35import java.util.Locale;36import javax.crypto.SecretKey;37import javax.crypto.interfaces.DHPublicKey;38import javax.crypto.spec.DHParameterSpec;39import javax.crypto.spec.DHPublicKeySpec;40import javax.net.ssl.SSLHandshakeException;41import sun.security.ssl.DHKeyExchange.DHECredentials;42import sun.security.ssl.DHKeyExchange.DHEPossession;43import sun.security.ssl.SSLHandshake.HandshakeMessage;44import sun.security.ssl.SupportedGroupsExtension.NamedGroup;45import sun.misc.HexDumpEncoder;4647/**48* Pack of the "ClientKeyExchange" handshake message.49*/50final class DHClientKeyExchange {51static final DHClientKeyExchangeConsumer dhHandshakeConsumer =52new DHClientKeyExchangeConsumer();53static final DHClientKeyExchangeProducer dhHandshakeProducer =54new DHClientKeyExchangeProducer();5556/**57* The DiffieHellman ClientKeyExchange handshake message.58*59* If the client has sent a certificate which contains a suitable60* DiffieHellman key (for fixed_dh client authentication), then the61* client public value is implicit and does not need to be sent again.62* In this case, the client key exchange message will be sent, but it63* MUST be empty.64*65* Currently, we don't support cipher suite that requires implicit public66* key of client.67*/68private static final69class DHClientKeyExchangeMessage extends HandshakeMessage {70private byte[] y; // 1 to 2^16 - 1 bytes7172DHClientKeyExchangeMessage(73HandshakeContext handshakeContext) throws IOException {74super(handshakeContext);75// This happens in client side only.76ClientHandshakeContext chc =77(ClientHandshakeContext)handshakeContext;7879DHEPossession dhePossession = null;80for (SSLPossession possession : chc.handshakePossessions) {81if (possession instanceof DHEPossession) {82dhePossession = (DHEPossession)possession;83break;84}85}8687if (dhePossession == null) {88// unlikely89throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,90"No DHE credentials negotiated for client key exchange");91}9293DHPublicKey publicKey = dhePossession.publicKey;94DHParameterSpec params = publicKey.getParams();95this.y = Utilities.toByteArray(publicKey.getY());96}9798DHClientKeyExchangeMessage(HandshakeContext handshakeContext,99ByteBuffer m) throws IOException {100super(handshakeContext);101// This happens in server side only.102ServerHandshakeContext shc =103(ServerHandshakeContext)handshakeContext;104105if (m.remaining() < 3) {106throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,107"Invalid DH ClientKeyExchange message: insufficient data");108}109110this.y = Record.getBytes16(m);111112if (m.hasRemaining()) {113throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,114"Invalid DH ClientKeyExchange message: unknown extra data");115}116}117118@Override119public SSLHandshake handshakeType() {120return SSLHandshake.CLIENT_KEY_EXCHANGE;121}122123@Override124public int messageLength() {125return y.length + 2; // 2: length filed126}127128@Override129public void send(HandshakeOutStream hos) throws IOException {130hos.putBytes16(y);131}132133@Override134public String toString() {135MessageFormat messageFormat = new MessageFormat(136"\"DH ClientKeyExchange\": '{'\n" +137" \"parameters\": '{'\n" +138" \"dh_Yc\": '{'\n" +139"{0}\n" +140" '}',\n" +141" '}'\n" +142"'}'",143Locale.ENGLISH);144145HexDumpEncoder hexEncoder = new HexDumpEncoder();146Object[] messageFields = {147Utilities.indent(148hexEncoder.encodeBuffer(y), " "),149};150return messageFormat.format(messageFields);151}152}153154/**155* The DiffieHellman "ClientKeyExchange" handshake message producer.156*/157private static final158class DHClientKeyExchangeProducer implements HandshakeProducer {159// Prevent instantiation of this class.160private DHClientKeyExchangeProducer() {161// blank162}163164@Override165public byte[] produce(ConnectionContext context,166HandshakeMessage message) throws IOException {167// The producing happens in client side only.168ClientHandshakeContext chc = (ClientHandshakeContext)context;169170DHECredentials dheCredentials = null;171for (SSLCredentials cd : chc.handshakeCredentials) {172if (cd instanceof DHECredentials) {173dheCredentials = (DHECredentials)cd;174break;175}176}177178if (dheCredentials == null) {179throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,180"No DHE credentials negotiated for client key exchange");181}182183184DHEPossession dhePossession = new DHEPossession(185dheCredentials, chc.sslContext.getSecureRandom());186chc.handshakePossessions.add(dhePossession);187DHClientKeyExchangeMessage ckem =188new DHClientKeyExchangeMessage(chc);189if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {190SSLLogger.fine(191"Produced DH ClientKeyExchange handshake message", ckem);192}193194// Output the handshake message.195ckem.write(chc.handshakeOutput);196chc.handshakeOutput.flush();197198// update the states199SSLKeyExchange ke = SSLKeyExchange.valueOf(200chc.negotiatedCipherSuite.keyExchange,201chc.negotiatedProtocol);202if (ke == null) {203// unlikely204throw chc.conContext.fatal(Alert.INTERNAL_ERROR,205"Not supported key exchange type");206} else {207SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);208SecretKey masterSecret =209masterKD.deriveKey("MasterSecret", null);210chc.handshakeSession.setMasterSecret(masterSecret);211212SSLTrafficKeyDerivation kd =213SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);214if (kd == null) {215// unlikely216throw chc.conContext.fatal(Alert.INTERNAL_ERROR,217"Not supported key derivation: " +218chc.negotiatedProtocol);219} else {220chc.handshakeKeyDerivation =221kd.createKeyDerivation(chc, masterSecret);222}223}224225// The handshake message has been delivered.226return null;227}228}229230/**231* The DiffieHellman "ClientKeyExchange" handshake message consumer.232*/233private static final234class DHClientKeyExchangeConsumer implements SSLConsumer {235// Prevent instantiation of this class.236private DHClientKeyExchangeConsumer() {237// blank238}239240@Override241public void consume(ConnectionContext context,242ByteBuffer message) throws IOException {243// The consuming happens in server side only.244ServerHandshakeContext shc = (ServerHandshakeContext)context;245246DHEPossession dhePossession = null;247for (SSLPossession possession : shc.handshakePossessions) {248if (possession instanceof DHEPossession) {249dhePossession = (DHEPossession)possession;250break;251}252}253254if (dhePossession == null) {255// unlikely256throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,257"No expected DHE possessions for client key exchange");258}259260SSLKeyExchange ke = SSLKeyExchange.valueOf(261shc.negotiatedCipherSuite.keyExchange,262shc.negotiatedProtocol);263if (ke == null) {264// unlikely265throw shc.conContext.fatal(Alert.INTERNAL_ERROR,266"Not supported key exchange type");267}268269DHClientKeyExchangeMessage ckem =270new DHClientKeyExchangeMessage(shc, message);271if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {272SSLLogger.fine(273"Consuming DH ClientKeyExchange handshake message", ckem);274}275276// create the credentials277try {278DHParameterSpec params = dhePossession.publicKey.getParams();279DHPublicKeySpec spec = new DHPublicKeySpec(280new BigInteger(1, ckem.y),281params.getP(), params.getG());282KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman");283DHPublicKey peerPublicKey =284(DHPublicKey)kf.generatePublic(spec);285286// check constraints of peer DHPublicKey287if (!shc.algorithmConstraints.permits(288EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),289peerPublicKey)) {290throw new SSLHandshakeException(291"DHPublicKey does not comply to algorithm constraints");292}293294NamedGroup namedGroup = NamedGroup.valueOf(params);295shc.handshakeCredentials.add(296new DHECredentials(peerPublicKey, namedGroup));297} catch (GeneralSecurityException | java.io.IOException e) {298throw (SSLHandshakeException)(new SSLHandshakeException(299"Could not generate DHPublicKey").initCause(e));300}301302// update the states303SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);304SecretKey masterSecret =305masterKD.deriveKey("MasterSecret", null);306shc.handshakeSession.setMasterSecret(masterSecret);307308SSLTrafficKeyDerivation kd =309SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);310if (kd == null) {311// unlikely312throw shc.conContext.fatal(Alert.INTERNAL_ERROR,313"Not supported key derivation: " + shc.negotiatedProtocol);314} else {315shc.handshakeKeyDerivation =316kd.createKeyDerivation(shc, masterSecret);317}318}319}320}321322323