< prev index next >

src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java

Print this page


   1 /*
   2  * Copyright (c) 1997, 2012, 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 
  27 package sun.security.ssl;
  28 
  29 import java.io.IOException;
  30 import java.io.PrintStream;
  31 import java.math.BigInteger;











  32 import javax.net.ssl.SSLHandshakeException;














  33 
  34 /*
  35  * Message used by clients to send their Diffie-Hellman public
  36  * keys to servers.





  37  *
  38  * @author David Brownell

  39  */
  40 final class DHClientKeyExchange extends HandshakeMessage {
















































  41 
  42     @Override
  43     int messageType() {
  44         return ht_client_key_exchange;
  45     }
  46 
  47     /*
  48      * This value may be empty if it was included in the
  49      * client's certificate ...
  50      */
  51     private byte[] dh_Yc;               // 1 to 2^16 -1 bytes
  52 
  53     BigInteger getClientPublicKey() {
  54         return dh_Yc == null ? null : new BigInteger(1, dh_Yc);

  55     }
  56 
  57     /*
  58      * Either pass the client's public key explicitly (because it's
  59      * using DHE or DH_anon), or implicitly (the public key was in the
  60      * certificate).



















  61      */
  62     DHClientKeyExchange(BigInteger publicKey) {
  63         dh_Yc = toByteArray(publicKey);

















  64     }
  65 
  66     DHClientKeyExchange() {
  67         dh_Yc = null;

  68     }
  69 
  70     /*
  71      * Get the client's public key either explicitly or implicitly.
  72      * (It's ugly to have an empty record be sent in the latter case,
  73      * but that's what the protocol spec requires.)
  74      */
  75     DHClientKeyExchange(HandshakeInStream input) throws IOException {
  76         if (input.available() >= 2) {
  77             dh_Yc = input.getBytes16();














  78         } else {
  79             // currently, we don't support cipher suites that requires
  80             // implicit public key of client.
  81             throw new SSLHandshakeException(
  82                     "Unsupported implicit client DiffieHellman public key");










  83         }
  84     }
  85 
  86     @Override
  87     int messageLength() {
  88         if (dh_Yc == null) {
  89             return 0;
  90         } else {
  91             return dh_Yc.length + 2;
  92         }
  93     }
  94 










  95     @Override
  96     void send(HandshakeOutStream s) throws IOException {
  97         if (dh_Yc != null && dh_Yc.length != 0) {
  98             s.putBytes16(dh_Yc);







  99         }
 100     }
 101 
 102     @Override
 103     void print(PrintStream s) throws IOException {
 104         s.println("*** ClientKeyExchange, DH");










 105 
 106         if (debug != null && Debug.isOn("verbose")) {
 107             Debug.println(s, "DH Public key", dh_Yc);














































 108         }
 109     }
 110 }
   1 /*
   2  * Copyright (c) 2003, 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.math.BigInteger;
  30 import java.nio.ByteBuffer;
  31 import java.security.CryptoPrimitive;
  32 import java.security.GeneralSecurityException;
  33 import java.security.KeyFactory;
  34 import java.text.MessageFormat;
  35 import java.util.EnumSet;
  36 import java.util.Locale;
  37 import javax.crypto.SecretKey;
  38 import javax.crypto.interfaces.DHPublicKey;
  39 import javax.crypto.spec.DHParameterSpec;
  40 import javax.crypto.spec.DHPublicKeySpec;
  41 import javax.net.ssl.SSLHandshakeException;
  42 import sun.security.ssl.DHKeyExchange.DHECredentials;
  43 import sun.security.ssl.DHKeyExchange.DHEPossession;
  44 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  45 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
  46 import sun.security.util.HexDumpEncoder;
  47 
  48 /**
  49  * Pack of the "ClientKeyExchange" handshake message.
  50  */
  51 final class DHClientKeyExchange {
  52     static final DHClientKeyExchangeConsumer dhHandshakeConsumer =
  53             new DHClientKeyExchangeConsumer();
  54     static final DHClientKeyExchangeProducer dhHandshakeProducer =
  55             new DHClientKeyExchangeProducer();
  56 
  57     /**
  58      * The DiffieHellman ClientKeyExchange handshake message.
  59      *
  60      * If the client has sent a certificate which contains a suitable
  61      * DiffieHellman key (for fixed_dh client authentication), then the
  62      * client public value is implicit and does not need to be sent again.
  63      * In this case, the client key exchange message will be sent, but it
  64      * MUST be empty.
  65      *
  66      * Currently, we don't support cipher suite that requires implicit public
  67      * key of client.
  68      */
  69     private static final
  70             class DHClientKeyExchangeMessage extends HandshakeMessage {
  71         private byte[] y;        // 1 to 2^16 - 1 bytes
  72 
  73         DHClientKeyExchangeMessage(
  74                 HandshakeContext handshakeContext) throws IOException {
  75             super(handshakeContext);
  76             // This happens in client side only.
  77             ClientHandshakeContext chc =
  78                     (ClientHandshakeContext)handshakeContext;
  79 
  80             DHEPossession dhePossession = null;
  81             for (SSLPossession possession : chc.handshakePossessions) {
  82                 if (possession instanceof DHEPossession) {
  83                     dhePossession = (DHEPossession)possession;
  84                     break;
  85                 }
  86             }
  87 
  88             if (dhePossession == null) {
  89                 // unlikely
  90                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
  91                     "No DHE credentials negotiated for client key exchange");
  92             }
  93 
  94             DHPublicKey publicKey = dhePossession.publicKey;
  95             DHParameterSpec params = publicKey.getParams();
  96             this.y = Utilities.toByteArray(publicKey.getY());
  97         }
  98 
  99         DHClientKeyExchangeMessage(HandshakeContext handshakeContext,
 100                 ByteBuffer m) throws IOException {
 101             super(handshakeContext);
 102             // This happens in server side only.
 103             ServerHandshakeContext shc =
 104                     (ServerHandshakeContext)handshakeContext;
 105 
 106             if (m.remaining() < 3) {
 107                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 108                     "Invalid DH ClientKeyExchange message: insufficient data");
 109             }
 110 
 111             this.y = Record.getBytes16(m);
 112 
 113             if (m.hasRemaining()) {
 114                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 115                     "Invalid DH ClientKeyExchange message: unknown extra data");
 116             }
 117         }
 118 
 119         @Override
 120         public SSLHandshake handshakeType() {
 121             return SSLHandshake.CLIENT_KEY_EXCHANGE;
 122         }
 123 
 124         @Override
 125         public int messageLength() {
 126             return y.length + 2;    // 2: length filed
 127         }

 128 
 129         @Override
 130         public void send(HandshakeOutStream hos) throws IOException {
 131             hos.putBytes16(y);
 132         }
 133 
 134         @Override
 135         public String toString() {
 136             MessageFormat messageFormat = new MessageFormat(
 137                 "\"DH ClientKeyExchange\": '{'\n" +
 138                 "  \"parameters\": '{'\n" +
 139                 "    \"dh_Yc\": '{'\n" +
 140                 "{0}\n" +
 141                 "    '}',\n" +
 142                 "  '}'\n" +
 143                 "'}'",
 144                 Locale.ENGLISH);
 145 
 146             HexDumpEncoder hexEncoder = new HexDumpEncoder();
 147             Object[] messageFields = {
 148                 Utilities.indent(
 149                         hexEncoder.encodeBuffer(y), "      "),
 150             };
 151             return messageFormat.format(messageFields);
 152         }
 153     }
 154 
 155     /**
 156      * The DiffieHellman "ClientKeyExchange" handshake message producer.
 157      */
 158     private static final
 159             class DHClientKeyExchangeProducer implements HandshakeProducer {
 160         // Prevent instantiation of this class.
 161         private DHClientKeyExchangeProducer() {
 162             // blank
 163         }
 164 
 165         @Override
 166         public byte[] produce(ConnectionContext context,
 167                 HandshakeMessage message) throws IOException {
 168             // The producing happens in client side only.
 169             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 170 
 171             DHECredentials dheCredentials = null;
 172             for (SSLCredentials cd : chc.handshakeCredentials) {
 173                 if (cd instanceof DHECredentials) {
 174                     dheCredentials = (DHECredentials)cd;
 175                     break;
 176                 }
 177             }
 178 
 179             if (dheCredentials == null) {
 180                 chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 181                     "No DHE credentials negotiated for client key exchange");
 182             }
 183 
 184 
 185             DHEPossession dhePossession = new DHEPossession(
 186                     dheCredentials, chc.sslContext.getSecureRandom());
 187             chc.handshakePossessions.add(dhePossession);
 188             DHClientKeyExchangeMessage ckem =
 189                     new DHClientKeyExchangeMessage(chc);
 190             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 191                 SSLLogger.fine(
 192                     "Produced DH ClientKeyExchange handshake message", ckem);
 193             }
 194 
 195             // Output the handshake message.
 196             ckem.write(chc.handshakeOutput);
 197             chc.handshakeOutput.flush();
 198 
 199             // update the states
 200             SSLKeyExchange ke =
 201                 SSLKeyExchange.valueOf(chc.negotiatedCipherSuite.keyExchange);
 202             if (ke == null) {
 203                 // unlikely
 204                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 205                         "Not supported key exchange type");
 206             } else {
 207                 SSLKeyDerivation masterKD = ke.createKeyDerivation(chc);
 208                 SecretKey masterSecret = masterKD.deriveKey("TODO", null);
 209                 chc.handshakeSession.setMasterSecret(masterSecret);
 210 
 211                 SSLTrafficKeyDerivation kd =
 212                         SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol);
 213                 if (kd == null) {
 214                     // unlikely
 215                     chc.conContext.fatal(Alert.INTERNAL_ERROR,
 216                             "Not supported key derivation: " +
 217                             chc.negotiatedProtocol);
 218                 } else {
 219                     chc.handshakeKeyDerivation =
 220                         kd.createKeyDerivation(chc, masterSecret);
 221                 }
 222             }
 223 
 224             // The handshake message has been delivered.
 225             return null;




 226         }
 227     }
 228 
 229     /**
 230      * The DiffieHellman "ClientKeyExchange" handshake message consumer.
 231      */
 232     private static final
 233             class DHClientKeyExchangeConsumer implements SSLConsumer {
 234         // Prevent instantiation of this class.
 235         private DHClientKeyExchangeConsumer() {
 236             // blank
 237         }
 238 
 239         @Override
 240         public void consume(ConnectionContext context,
 241                 ByteBuffer message) throws IOException {
 242             // The consuming happens in server side only.
 243             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 244 
 245             DHEPossession dhePossession = null;
 246             for (SSLPossession possession : shc.handshakePossessions) {
 247                 if (possession instanceof DHEPossession) {
 248                     dhePossession = (DHEPossession)possession;
 249                     break;
 250                 }
 251             }
 252 
 253             if (dhePossession == null) {
 254                 // unlikely
 255                 shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 256                     "No expected DHE possessions for client key exchange");
 257             }
 258 
 259             SSLKeyExchange ke = SSLKeyExchange.valueOf(
 260                     shc.negotiatedCipherSuite.keyExchange);
 261             if (ke == null) {
 262                 // unlikely
 263                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 264                         "Not supported key exchange type");
 265             }
 266 
 267             DHClientKeyExchangeMessage ckem =
 268                     new DHClientKeyExchangeMessage(shc, message);
 269             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 270                 SSLLogger.fine(
 271                     "Consuming DH ClientKeyExchange handshake message", ckem);
 272             }
 273 
 274             // create the credentials
 275             try {
 276                 DHParameterSpec params = dhePossession.publicKey.getParams();
 277                 DHPublicKeySpec spec = new DHPublicKeySpec(
 278                         new BigInteger(1, ckem.y),
 279                         params.getP(), params.getG());
 280                 KeyFactory kf = JsseJce.getKeyFactory("DH");
 281                 DHPublicKey peerPublicKey =
 282                         (DHPublicKey)kf.generatePublic(spec);
 283 
 284                 // check constraints of peer DHPublicKey
 285                 if (!shc.algorithmConstraints.permits(
 286                         EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 287                         peerPublicKey)) {
 288                     throw new SSLHandshakeException(
 289                         "DHPublicKey does not comply to algorithm constraints");
 290                 }
 291 
 292                 NamedGroup namedGroup = NamedGroup.valueOf(params);
 293                 shc.handshakeCredentials.add(
 294                         new DHECredentials(peerPublicKey, namedGroup));
 295             } catch (GeneralSecurityException | java.io.IOException e) {
 296                 throw (SSLHandshakeException)(new SSLHandshakeException(
 297                         "Could not generate DHPublicKey").initCause(e));
 298             }
 299 
 300             // update the states
 301             SSLKeyDerivation masterKD = ke.createKeyDerivation(shc);
 302             SecretKey masterSecret = masterKD.deriveKey("TODO", null);
 303             shc.handshakeSession.setMasterSecret(masterSecret);
 304 
 305             SSLTrafficKeyDerivation kd =
 306                     SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol);
 307             if (kd == null) {
 308                 // unlikely
 309                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
 310                     "Not supported key derivation: " + shc.negotiatedProtocol);
 311             } else {
 312                 shc.handshakeKeyDerivation =
 313                     kd.createKeyDerivation(shc, masterSecret);
 314             }
 315         }
 316     }
 317 }
< prev index next >