|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.ssl; |
|
|
|
import java.io.IOException; |
|
import java.nio.ByteBuffer; |
|
import java.security.GeneralSecurityException; |
|
import java.security.InvalidKeyException; |
|
import java.security.NoSuchAlgorithmException; |
|
import javax.crypto.SecretKey; |
|
import javax.crypto.spec.IvParameterSpec; |
|
import javax.net.ssl.SSLException; |
|
import sun.security.ssl.SSLCipher.SSLReadCipher; |
|
import sun.security.ssl.SSLCipher.SSLWriteCipher; |
|
import sun.security.ssl.SSLHandshake.HandshakeMessage; |
|
import sun.security.ssl.SSLTrafficKeyDerivation.LegacyTrafficKeyDerivation; |
|
|
|
|
|
|
|
*/ |
|
final class ChangeCipherSpec { |
|
static final SSLConsumer t10Consumer = |
|
new T10ChangeCipherSpecConsumer(); |
|
static final HandshakeProducer t10Producer = |
|
new T10ChangeCipherSpecProducer(); |
|
static final SSLConsumer t13Consumer = |
|
new T13ChangeCipherSpecConsumer(); |
|
|
|
|
|
|
|
*/ |
|
private static final |
|
class T10ChangeCipherSpecProducer implements HandshakeProducer { |
|
|
|
private T10ChangeCipherSpecProducer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public byte[] produce(ConnectionContext context, |
|
HandshakeMessage message) throws IOException { |
|
HandshakeContext hc = (HandshakeContext)context; |
|
SSLKeyDerivation kd = hc.handshakeKeyDerivation; |
|
|
|
if (!(kd instanceof LegacyTrafficKeyDerivation)) { |
|
throw new UnsupportedOperationException("Not supported."); |
|
} |
|
LegacyTrafficKeyDerivation tkd = (LegacyTrafficKeyDerivation)kd; |
|
CipherSuite ncs = hc.negotiatedCipherSuite; |
|
Authenticator writeAuthenticator; |
|
if (ncs.bulkCipher.cipherType == CipherType.AEAD_CIPHER) { |
|
writeAuthenticator = |
|
Authenticator.valueOf(hc.negotiatedProtocol); |
|
} else { |
|
try { |
|
writeAuthenticator = Authenticator.valueOf( |
|
hc.negotiatedProtocol, ncs.macAlg, |
|
tkd.getTrafficKey(hc.sslConfig.isClientMode ? |
|
"clientMacKey" : "serverMacKey")); |
|
} catch (NoSuchAlgorithmException | InvalidKeyException e) { |
|
|
|
throw new SSLException("Algorithm missing: ", e); |
|
} |
|
} |
|
|
|
SecretKey writeKey = |
|
tkd.getTrafficKey(hc.sslConfig.isClientMode ? |
|
"clientWriteKey" : "serverWriteKey"); |
|
SecretKey writeIv = |
|
tkd.getTrafficKey(hc.sslConfig.isClientMode ? |
|
"clientWriteIv" : "serverWriteIv"); |
|
IvParameterSpec iv = (writeIv == null) ? null : |
|
new IvParameterSpec(writeIv.getEncoded()); |
|
SSLWriteCipher writeCipher; |
|
try { |
|
writeCipher = ncs.bulkCipher.createWriteCipher( |
|
writeAuthenticator, |
|
hc.negotiatedProtocol, writeKey, iv, |
|
hc.sslContext.getSecureRandom()); |
|
} catch (GeneralSecurityException gse) { |
|
|
|
throw new SSLException("Algorithm missing: ", gse); |
|
} |
|
|
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine("Produced ChangeCipherSpec message"); |
|
} |
|
|
|
hc.conContext.outputRecord.changeWriteCiphers(writeCipher, true); |
|
|
|
|
|
return null; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static final |
|
class T10ChangeCipherSpecConsumer implements SSLConsumer { |
|
|
|
private T10ChangeCipherSpecConsumer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public void consume(ConnectionContext context, |
|
ByteBuffer message) throws IOException { |
|
TransportContext tc = (TransportContext)context; |
|
|
|
|
|
tc.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id); |
|
|
|
|
|
if (message.remaining() != 1 || message.get() != 1) { |
|
tc.fatal(Alert.UNEXPECTED_MESSAGE, |
|
"Malformed or unexpected ChangeCipherSpec message"); |
|
} |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine("Consuming ChangeCipherSpec message"); |
|
} |
|
|
|
|
|
if (tc.handshakeContext == null) { |
|
tc.fatal(Alert.HANDSHAKE_FAILURE, |
|
"Unexpected ChangeCipherSpec message"); |
|
} |
|
|
|
|
|
HandshakeContext hc = tc.handshakeContext; |
|
|
|
if (hc.handshakeKeyDerivation == null) { |
|
tc.fatal(Alert.UNEXPECTED_MESSAGE, |
|
"Unexpected ChangeCipherSpec message"); |
|
} |
|
|
|
SSLKeyDerivation kd = hc.handshakeKeyDerivation; |
|
if (kd instanceof LegacyTrafficKeyDerivation) { |
|
LegacyTrafficKeyDerivation tkd = (LegacyTrafficKeyDerivation)kd; |
|
CipherSuite ncs = hc.negotiatedCipherSuite; |
|
Authenticator readAuthenticator; |
|
if (ncs.bulkCipher.cipherType == CipherType.AEAD_CIPHER) { |
|
readAuthenticator = |
|
Authenticator.valueOf(hc.negotiatedProtocol); |
|
} else { |
|
try { |
|
readAuthenticator = Authenticator.valueOf( |
|
hc.negotiatedProtocol, ncs.macAlg, |
|
tkd.getTrafficKey(hc.sslConfig.isClientMode ? |
|
"serverMacKey" : "clientMacKey")); |
|
} catch (NoSuchAlgorithmException | InvalidKeyException e) { |
|
|
|
throw new SSLException("Algorithm missing: ", e); |
|
} |
|
} |
|
|
|
SecretKey readKey = |
|
tkd.getTrafficKey(hc.sslConfig.isClientMode ? |
|
"serverWriteKey" : "clientWriteKey"); |
|
SecretKey readIv = |
|
tkd.getTrafficKey(hc.sslConfig.isClientMode ? |
|
"serverWriteIv" : "clientWriteIv"); |
|
IvParameterSpec iv = (readIv == null) ? null : |
|
new IvParameterSpec(readIv.getEncoded()); |
|
SSLReadCipher readCipher; |
|
try { |
|
readCipher = ncs.bulkCipher.createReadCipher( |
|
readAuthenticator, |
|
hc.negotiatedProtocol, readKey, iv, |
|
hc.sslContext.getSecureRandom()); |
|
} catch (GeneralSecurityException gse) { |
|
|
|
throw new SSLException("Algorithm missing: ", gse); |
|
} |
|
tc.inputRecord.changeReadCiphers(readCipher); |
|
} else { |
|
throw new UnsupportedOperationException("Not supported."); |
|
} |
|
} |
|
} |
|
|
|
private static final |
|
class T13ChangeCipherSpecConsumer implements SSLConsumer { |
|
|
|
private T13ChangeCipherSpecConsumer() { |
|
// blank |
|
} |
|
|
|
// An implementation may receive an unencrypted record of type |
|
// change_cipher_spec consisting of the single byte value 0x01 |
|
// at any time after the first ClientHello message has been |
|
// sent or received and before the peer's Finished message has |
|
// been received and MUST simply drop it without further |
|
|
|
@Override |
|
public void consume(ConnectionContext context, |
|
ByteBuffer message) throws IOException { |
|
TransportContext tc = (TransportContext)context; |
|
|
|
|
|
tc.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id); |
|
|
|
|
|
if (message.remaining() != 1 || message.get() != 1) { |
|
tc.fatal(Alert.UNEXPECTED_MESSAGE, |
|
"Malformed or unexpected ChangeCipherSpec message"); |
|
} |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine("Consuming ChangeCipherSpec message"); |
|
} |
|
|
|
// no further processing |
|
} |
|
} |
|
} |