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