|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.ssl; |
|
|
|
import java.io.IOException; |
|
import java.nio.ByteBuffer; |
|
import java.security.GeneralSecurityException; |
|
import java.security.PrivateKey; |
|
import java.security.PublicKey; |
|
import java.text.MessageFormat; |
|
import java.util.Locale; |
|
import javax.crypto.SecretKey; |
|
import sun.security.ssl.RSAKeyExchange.EphemeralRSACredentials; |
|
import sun.security.ssl.RSAKeyExchange.EphemeralRSAPossession; |
|
import sun.security.ssl.RSAKeyExchange.RSAPremasterSecret; |
|
import sun.security.ssl.SSLHandshake.HandshakeMessage; |
|
import sun.security.ssl.X509Authentication.X509Credentials; |
|
import sun.security.ssl.X509Authentication.X509Possession; |
|
import sun.security.util.HexDumpEncoder; |
|
|
|
|
|
|
|
*/ |
|
final class RSAClientKeyExchange { |
|
static final SSLConsumer rsaHandshakeConsumer = |
|
new RSAClientKeyExchangeConsumer(); |
|
static final HandshakeProducer rsaHandshakeProducer = |
|
new RSAClientKeyExchangeProducer(); |
|
|
|
|
|
|
|
*/ |
|
private static final |
|
class RSAClientKeyExchangeMessage extends HandshakeMessage { |
|
final int protocolVersion; |
|
final boolean useTLS10PlusSpec; |
|
final byte[] encrypted; |
|
|
|
RSAClientKeyExchangeMessage(HandshakeContext context, |
|
RSAPremasterSecret premaster, |
|
PublicKey publicKey) throws GeneralSecurityException { |
|
super(context); |
|
this.protocolVersion = context.clientHelloVersion; |
|
this.encrypted = premaster.getEncoded( |
|
publicKey, context.sslContext.getSecureRandom()); |
|
this.useTLS10PlusSpec = ProtocolVersion.useTLS10PlusSpec( |
|
protocolVersion, context.sslContext.isDTLS()); |
|
} |
|
|
|
RSAClientKeyExchangeMessage(HandshakeContext context, |
|
ByteBuffer m) throws IOException { |
|
super(context); |
|
|
|
if (m.remaining() < 2) { |
|
context.conContext.fatal(Alert.HANDSHAKE_FAILURE, |
|
"Invalid RSA ClientKeyExchange message: insufficient data"); |
|
} |
|
|
|
this.protocolVersion = context.clientHelloVersion; |
|
this.useTLS10PlusSpec = ProtocolVersion.useTLS10PlusSpec( |
|
protocolVersion, context.sslContext.isDTLS()); |
|
if (useTLS10PlusSpec) { |
|
this.encrypted = Record.getBytes16(m); |
|
} else { |
|
this.encrypted = new byte[m.remaining()]; |
|
m.get(encrypted); |
|
} |
|
} |
|
|
|
@Override |
|
public SSLHandshake handshakeType() { |
|
return SSLHandshake.CLIENT_KEY_EXCHANGE; |
|
} |
|
|
|
@Override |
|
public int messageLength() { |
|
if (useTLS10PlusSpec) { |
|
return encrypted.length + 2; |
|
} else { |
|
return encrypted.length; |
|
} |
|
} |
|
|
|
@Override |
|
public void send(HandshakeOutStream hos) throws IOException { |
|
if (useTLS10PlusSpec) { |
|
hos.putBytes16(encrypted); |
|
} else { |
|
hos.write(encrypted); |
|
} |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
MessageFormat messageFormat = new MessageFormat( |
|
"\"RSA ClientKeyExchange\": '{'\n" + |
|
" \"client_version\": {0}\n" + |
|
" \"encncrypted\": '{'\n" + |
|
"{1}\n" + |
|
" '}'\n" + |
|
"'}'", |
|
Locale.ENGLISH); |
|
|
|
HexDumpEncoder hexEncoder = new HexDumpEncoder(); |
|
Object[] messageFields = { |
|
ProtocolVersion.nameOf(protocolVersion), |
|
Utilities.indent( |
|
hexEncoder.encodeBuffer(encrypted), " "), |
|
}; |
|
return messageFormat.format(messageFields); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static final |
|
class RSAClientKeyExchangeProducer implements HandshakeProducer { |
|
|
|
private RSAClientKeyExchangeProducer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public byte[] produce(ConnectionContext context, |
|
HandshakeMessage message) throws IOException { |
|
|
|
ClientHandshakeContext chc = (ClientHandshakeContext)context; |
|
|
|
EphemeralRSACredentials rsaCredentials = null; |
|
X509Credentials x509Credentials = null; |
|
for (SSLCredentials credential : chc.handshakeCredentials) { |
|
if (credential instanceof EphemeralRSACredentials) { |
|
rsaCredentials = (EphemeralRSACredentials)credential; |
|
if (x509Credentials != null) { |
|
break; |
|
} |
|
} else if (credential instanceof X509Credentials) { |
|
x509Credentials = (X509Credentials)credential; |
|
if (rsaCredentials != null) { |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (rsaCredentials == null && x509Credentials == null) { |
|
chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
"No RSA credentials negotiated for client key exchange"); |
|
} |
|
|
|
PublicKey publicKey = (rsaCredentials != null) ? |
|
rsaCredentials.popPublicKey : x509Credentials.popPublicKey; |
|
if (!publicKey.getAlgorithm().equals("RSA")) { |
|
chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
"Not RSA public key for client key exchange"); |
|
} |
|
|
|
RSAPremasterSecret premaster; |
|
RSAClientKeyExchangeMessage ckem; |
|
try { |
|
premaster = RSAPremasterSecret.createPremasterSecret(chc); |
|
chc.handshakePossessions.add(premaster); |
|
ckem = new RSAClientKeyExchangeMessage( |
|
chc, premaster, publicKey); |
|
} catch (GeneralSecurityException gse) { |
|
chc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
"Cannot generate RSA premaster secret", gse); |
|
|
|
return null; |
|
} |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine( |
|
"Produced RSA ClientKeyExchange handshake message", ckem); |
|
} |
|
|
|
|
|
ckem.write(chc.handshakeOutput); |
|
chc.handshakeOutput.flush(); |
|
|
|
|
|
SSLKeyExchange ke = SSLKeyExchange.valueOf( |
|
chc.negotiatedCipherSuite.keyExchange, |
|
chc.negotiatedProtocol); |
|
if (ke == null) { |
|
chc.conContext.fatal(Alert.INTERNAL_ERROR, |
|
"Not supported key exchange type"); |
|
} else { |
|
SSLKeyDerivation masterKD = ke.createKeyDerivation(chc); |
|
SecretKey masterSecret = |
|
masterKD.deriveKey("MasterSecret", null); |
|
|
|
|
|
chc.handshakeSession.setMasterSecret(masterSecret); |
|
SSLTrafficKeyDerivation kd = |
|
SSLTrafficKeyDerivation.valueOf(chc.negotiatedProtocol); |
|
if (kd == null) { |
|
chc.conContext.fatal(Alert.INTERNAL_ERROR, |
|
"Not supported key derivation: " + |
|
chc.negotiatedProtocol); |
|
} else { |
|
chc.handshakeKeyDerivation = |
|
kd.createKeyDerivation(chc, masterSecret); |
|
} |
|
} |
|
|
|
|
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static final |
|
class RSAClientKeyExchangeConsumer implements SSLConsumer { |
|
|
|
private RSAClientKeyExchangeConsumer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public void consume(ConnectionContext context, |
|
ByteBuffer message) throws IOException { |
|
|
|
ServerHandshakeContext shc = (ServerHandshakeContext)context; |
|
|
|
EphemeralRSAPossession rsaPossession = null; |
|
X509Possession x509Possession = null; |
|
for (SSLPossession possession : shc.handshakePossessions) { |
|
if (possession instanceof EphemeralRSAPossession) { |
|
rsaPossession = (EphemeralRSAPossession)possession; |
|
break; |
|
} else if (possession instanceof X509Possession) { |
|
x509Possession = (X509Possession)possession; |
|
if (rsaPossession != null) { |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (rsaPossession == null && x509Possession == null) { |
|
shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
"No RSA possessions negotiated for client key exchange"); |
|
} |
|
|
|
PrivateKey privateKey = (rsaPossession != null) ? |
|
rsaPossession.popPrivateKey : x509Possession.popPrivateKey; |
|
if (!privateKey.getAlgorithm().equals("RSA")) { |
|
shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
"Not RSA private key for client key exchange"); |
|
} |
|
|
|
RSAClientKeyExchangeMessage ckem = |
|
new RSAClientKeyExchangeMessage(shc, message); |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine( |
|
"Consuming RSA ClientKeyExchange handshake message", ckem); |
|
} |
|
|
|
|
|
RSAPremasterSecret premaster; |
|
try { |
|
premaster = |
|
RSAPremasterSecret.decode(shc, privateKey, ckem.encrypted); |
|
shc.handshakeCredentials.add(premaster); |
|
} catch (GeneralSecurityException gse) { |
|
shc.conContext.fatal(Alert.ILLEGAL_PARAMETER, |
|
"Cannot decode RSA premaster secret", gse); |
|
} |
|
|
|
|
|
SSLKeyExchange ke = SSLKeyExchange.valueOf( |
|
shc.negotiatedCipherSuite.keyExchange, |
|
shc.negotiatedProtocol); |
|
if (ke == null) { |
|
shc.conContext.fatal(Alert.INTERNAL_ERROR, |
|
"Not supported key exchange type"); |
|
} else { |
|
SSLKeyDerivation masterKD = ke.createKeyDerivation(shc); |
|
SecretKey masterSecret = |
|
masterKD.deriveKey("MasterSecret", null); |
|
|
|
|
|
shc.handshakeSession.setMasterSecret(masterSecret); |
|
SSLTrafficKeyDerivation kd = |
|
SSLTrafficKeyDerivation.valueOf(shc.negotiatedProtocol); |
|
if (kd == null) { |
|
shc.conContext.fatal(Alert.INTERNAL_ERROR, |
|
"Not supported key derivation: " + |
|
shc.negotiatedProtocol); |
|
} else { |
|
shc.handshakeKeyDerivation = |
|
kd.createKeyDerivation(shc, masterSecret); |
|
} |
|
} |
|
} |
|
} |
|
} |