1 /*
   2  * Copyright (c) 2015, 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.InvalidKeyException;
  34 import java.security.KeyFactory;
  35 import java.security.NoSuchAlgorithmException;
  36 import java.security.Signature;
  37 import java.security.SignatureException;
  38 import java.security.interfaces.RSAPublicKey;
  39 import java.security.spec.RSAPublicKeySpec;
  40 import java.text.MessageFormat;
  41 import java.util.EnumSet;
  42 import java.util.Locale;
  43 import sun.security.ssl.RSAKeyExchange.EphemeralRSACredentials;
  44 import sun.security.ssl.RSAKeyExchange.EphemeralRSAPossession;
  45 import sun.security.ssl.SSLHandshake.HandshakeMessage;
  46 import sun.security.ssl.X509Authentication.X509Credentials;
  47 import sun.security.ssl.X509Authentication.X509Possession;
  48 import sun.security.util.HexDumpEncoder;
  49 
  50 /**
  51  * Pack of the ServerKeyExchange handshake message.
  52  */
  53 final class RSAServerKeyExchange {
  54     static final SSLConsumer rsaHandshakeConsumer =
  55         new RSAServerKeyExchangeConsumer();
  56     static final HandshakeProducer rsaHandshakeProducer =
  57         new RSAServerKeyExchangeProducer();
  58 
  59     /**
  60      * The ephemeral RSA ServerKeyExchange handshake message.
  61      *
  62      * Used for RSA_EXPORT, SSL 3.0 and TLS 1.0 only.
  63      */
  64     private static final
  65             class RSAServerKeyExchangeMessage extends HandshakeMessage {
  66         // public key encapsulated in this message
  67         private final byte[] modulus;     // 1 to 2^16 - 1 bytes
  68         private final byte[] exponent;    // 1 to 2^16 - 1 bytes
  69 
  70         // signature bytes, none-null as no anonymous RSA key exchange.
  71         private final byte[] paramsSignature;
  72 
  73         private RSAServerKeyExchangeMessage(HandshakeContext handshakeContext,
  74                 X509Possession x509Possession,
  75                 EphemeralRSAPossession rsaPossession) throws IOException {
  76             super(handshakeContext);
  77 
  78             // This happens in server side only.
  79             ServerHandshakeContext shc =
  80                     (ServerHandshakeContext)handshakeContext;
  81 
  82             RSAPublicKey publicKey = rsaPossession.popPublicKey;
  83             RSAPublicKeySpec spec = JsseJce.getRSAPublicKeySpec(publicKey);
  84             this.modulus = Utilities.toByteArray(spec.getModulus());
  85             this.exponent = Utilities.toByteArray(spec.getPublicExponent());
  86             byte[] signature = null;
  87             try {
  88                 Signature signer = RSASignature.getInstance();
  89                 signer.initSign(x509Possession.popPrivateKey,
  90                         shc.sslContext.getSecureRandom());
  91                 updateSignature(signer,
  92                           shc.clientHelloRandom.randomBytes,
  93                           shc.serverHelloRandom.randomBytes);
  94                 signature = signer.sign();
  95             } catch (NoSuchAlgorithmException |
  96                     InvalidKeyException | SignatureException ex) {
  97                 shc.conContext.fatal(Alert.INTERNAL_ERROR,
  98                         "Failed to sign ephemeral RSA parameters", ex);
  99             }
 100 
 101             this.paramsSignature = signature;
 102         }
 103 
 104         RSAServerKeyExchangeMessage(HandshakeContext handshakeContext,
 105                 ByteBuffer m) throws IOException {
 106             super(handshakeContext);
 107 
 108             // This happens in client side only.
 109             ClientHandshakeContext chc =
 110                     (ClientHandshakeContext)handshakeContext;
 111 
 112             this.modulus = Record.getBytes16(m);
 113             this.exponent = Record.getBytes16(m);
 114             this.paramsSignature = Record.getBytes16(m);
 115 
 116             X509Credentials x509Credentials = null;
 117             for (SSLCredentials cd : chc.handshakeCredentials) {
 118                 if (cd instanceof X509Credentials) {
 119                     x509Credentials = (X509Credentials)cd;
 120                     break;
 121                 }
 122             }
 123 
 124             if (x509Credentials == null) {
 125                 chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 126                     "No RSA credentials negotiated for server key exchange");
 127             }
 128 
 129             try {
 130                 Signature signer = RSASignature.getInstance();
 131                 signer.initVerify(x509Credentials.popPublicKey);
 132                 updateSignature(signer,
 133                           chc.clientHelloRandom.randomBytes,
 134                           chc.serverHelloRandom.randomBytes);
 135                 if (!signer.verify(paramsSignature)) {
 136                     chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
 137                         "Invalid signature of RSA ServerKeyExchange message");
 138                 }
 139             } catch (NoSuchAlgorithmException |
 140                     InvalidKeyException | SignatureException ex) {
 141                 chc.conContext.fatal(Alert.INTERNAL_ERROR,
 142                     "Failed to sign ephemeral RSA parameters", ex);
 143             }
 144         }
 145 
 146         @Override
 147         SSLHandshake handshakeType() {
 148             return SSLHandshake.SERVER_KEY_EXCHANGE;
 149         }
 150 
 151         @Override
 152         int messageLength() {
 153             return 6 + modulus.length + exponent.length
 154                    + paramsSignature.length;
 155         }
 156 
 157         @Override
 158         void send(HandshakeOutStream hos) throws IOException {
 159             hos.putBytes16(modulus);
 160             hos.putBytes16(exponent);
 161             hos.putBytes16(paramsSignature);
 162         }
 163 
 164         @Override
 165         public String toString() {
 166             MessageFormat messageFormat = new MessageFormat(
 167                 "\"RSA ServerKeyExchange\": '{'\n" +
 168                 "  \"parameters\": '{'\n" +
 169                 "    \"rsa_modulus\": '{'\n" +
 170                 "{0}\n" +
 171                 "    '}',\n" +
 172                 "    \"rsa_exponent\": '{'\n" +
 173                 "{1}\n" +
 174                 "    '}'\n" +
 175                 "  '}',\n" +
 176                 "  \"digital signature\":  '{'\n" +
 177                 "    \"signature\": '{'\n" +
 178                 "{2}\n" +
 179                 "    '}',\n" +
 180                 "  '}'\n" +
 181                 "'}'",
 182                 Locale.ENGLISH);
 183 
 184             HexDumpEncoder hexEncoder = new HexDumpEncoder();
 185             Object[] messageFields = {
 186                 Utilities.indent(
 187                         hexEncoder.encodeBuffer(modulus), "      "),
 188                 Utilities.indent(
 189                         hexEncoder.encodeBuffer(exponent), "      "),
 190                 Utilities.indent(
 191                         hexEncoder.encodeBuffer(paramsSignature), "      ")
 192             };
 193             return messageFormat.format(messageFields);
 194         }
 195 
 196         /*
 197          * Hash the nonces and the ephemeral RSA public key.
 198          */
 199         private void updateSignature(Signature signature,
 200                 byte[] clntNonce, byte[] svrNonce) throws SignatureException {
 201             signature.update(clntNonce);
 202             signature.update(svrNonce);
 203 
 204             signature.update((byte)(modulus.length >> 8));
 205             signature.update((byte)(modulus.length & 0x0ff));
 206             signature.update(modulus);
 207 
 208             signature.update((byte)(exponent.length >> 8));
 209             signature.update((byte)(exponent.length & 0x0ff));
 210             signature.update(exponent);
 211         }
 212     }
 213 
 214     /**
 215      * The RSA "ServerKeyExchange" handshake message producer.
 216      */
 217     private static final
 218             class RSAServerKeyExchangeProducer implements HandshakeProducer {
 219         static final RSAServerKeyExchangeProducer INSTANCE =
 220                 new RSAServerKeyExchangeProducer();
 221 
 222         // Prevent instantiation of this class.
 223         private RSAServerKeyExchangeProducer() {
 224             // blank
 225         }
 226 
 227         @Override
 228         public byte[] produce(ConnectionContext context,
 229                 HandshakeMessage message) throws IOException {
 230             // The producing happens in server side only.
 231             ServerHandshakeContext shc = (ServerHandshakeContext)context;
 232 
 233             EphemeralRSAPossession rsaPossession = null;
 234             X509Possession x509Possession = null;
 235             for (SSLPossession possession : shc.handshakePossessions) {
 236                 if (possession instanceof EphemeralRSAPossession) {
 237                     rsaPossession = (EphemeralRSAPossession)possession;
 238                     if (x509Possession != null) {
 239                         break;
 240                     }
 241                 } else if (possession instanceof X509Possession) {
 242                     x509Possession = (X509Possession)possession;
 243                     if (rsaPossession != null) {
 244                         break;
 245                     }
 246                 }
 247             }
 248 
 249             if (rsaPossession == null) {
 250                 // The X.509 certificate itself should be used for RSA_EXPORT
 251                 // key exchange.  The ServerKeyExchange handshake message is
 252                 // not needed.
 253                 return null;
 254             } else if (x509Possession == null) {
 255                 // unlikely
 256                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 257                     "No RSA certificate negotiated for server key exchange");
 258             } else if (!"RSA".equals(
 259                     x509Possession.popPrivateKey.getAlgorithm())) {
 260                 // unlikely
 261                 shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
 262                         "No X.509 possession can be used for " +
 263                         "ephemeral RSA ServerKeyExchange");
 264             }
 265 
 266             RSAServerKeyExchangeMessage skem =
 267                     new RSAServerKeyExchangeMessage(
 268                             shc, x509Possession, rsaPossession);
 269             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 270                 SSLLogger.fine(
 271                     "Produced RSA ServerKeyExchange handshake message", skem);
 272             }
 273 
 274             // Output the handshake message.
 275             skem.write(shc.handshakeOutput);
 276             shc.handshakeOutput.flush();
 277 
 278             // The handshake message has been delivered.
 279             return null;
 280         }
 281     }
 282 
 283     /**
 284      * The RSA "ServerKeyExchange" handshake message consumer.
 285      */
 286     private static final
 287             class RSAServerKeyExchangeConsumer implements SSLConsumer {
 288         // Prevent instantiation of this class.
 289         private RSAServerKeyExchangeConsumer() {
 290             // blank
 291         }
 292 
 293         @Override
 294         public void consume(ConnectionContext context,
 295                 ByteBuffer message) throws IOException {
 296             // The consuming happens in client side only.
 297             ClientHandshakeContext chc = (ClientHandshakeContext)context;
 298 
 299             RSAServerKeyExchangeMessage skem =
 300                     new RSAServerKeyExchangeMessage(chc, message);
 301             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 302                 SSLLogger.fine(
 303                     "Consuming RSA ServerKeyExchange handshake message", skem);
 304             }
 305 
 306             //
 307             // validate
 308             //
 309             // check constraints of EC PublicKey
 310             RSAPublicKey publicKey;
 311             try {
 312                 KeyFactory kf = JsseJce.getKeyFactory("RSA");
 313                 RSAPublicKeySpec spec = new RSAPublicKeySpec(
 314                     new BigInteger(1, skem.modulus),
 315                     new BigInteger(1, skem.exponent));
 316                 publicKey = (RSAPublicKey)kf.generatePublic(spec);
 317             } catch (GeneralSecurityException gse) {
 318                 chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
 319                         "Could not generate RSAPublicKey", gse);
 320 
 321                 return;     // make the compiler happy
 322             }
 323 
 324             if (!chc.algorithmConstraints.permits(
 325                     EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), publicKey)) {
 326                 chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
 327                         "RSA ServerKeyExchange does not comply to " +
 328                         "algorithm constraints");
 329             }
 330 
 331             //
 332             // update
 333             //
 334             chc.handshakeCredentials.add(new EphemeralRSACredentials(publicKey));
 335 
 336             //
 337             // produce
 338             //
 339             // Need no new handshake message producers here.
 340         }
 341     }
 342 }
 343