Path: blob/master/src/java.base/share/classes/sun/security/ssl/ChangeCipherSpec.java
41159 views
/*1* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ssl;2627import java.io.IOException;28import java.nio.ByteBuffer;29import java.security.GeneralSecurityException;30import java.security.InvalidKeyException;31import java.security.NoSuchAlgorithmException;32import javax.crypto.SecretKey;33import javax.crypto.spec.IvParameterSpec;34import javax.net.ssl.SSLException;35import sun.security.ssl.SSLCipher.SSLReadCipher;36import sun.security.ssl.SSLCipher.SSLWriteCipher;37import sun.security.ssl.SSLHandshake.HandshakeMessage;38import sun.security.ssl.SSLTrafficKeyDerivation.LegacyTrafficKeyDerivation;3940/**41* Pack of the ChangeCipherSpec message.42*/43final class ChangeCipherSpec {44static final SSLConsumer t10Consumer =45new T10ChangeCipherSpecConsumer();46static final HandshakeProducer t10Producer =47new T10ChangeCipherSpecProducer();48static final SSLConsumer t13Consumer =49new T13ChangeCipherSpecConsumer();5051/**52* The "ChangeCipherSpec" message producer.53*/54private static final55class T10ChangeCipherSpecProducer implements HandshakeProducer {56// Prevent instantiation of this class.57private T10ChangeCipherSpecProducer() {58// blank59}6061@Override62public byte[] produce(ConnectionContext context,63HandshakeMessage message) throws IOException {64HandshakeContext hc = (HandshakeContext)context;65SSLKeyDerivation kd = hc.handshakeKeyDerivation;6667if (!(kd instanceof LegacyTrafficKeyDerivation)) {68throw new UnsupportedOperationException("Not supported.");69}70LegacyTrafficKeyDerivation tkd = (LegacyTrafficKeyDerivation)kd;71CipherSuite ncs = hc.negotiatedCipherSuite;72Authenticator writeAuthenticator;73if (ncs.bulkCipher.cipherType == CipherType.AEAD_CIPHER) {74writeAuthenticator =75Authenticator.valueOf(hc.negotiatedProtocol);76} else {77try {78writeAuthenticator = Authenticator.valueOf(79hc.negotiatedProtocol, ncs.macAlg,80tkd.getTrafficKey(hc.sslConfig.isClientMode ?81"clientMacKey" : "serverMacKey"));82} catch (NoSuchAlgorithmException | InvalidKeyException e) {83// unlikely84throw new SSLException("Algorithm missing: ", e);85}86}8788SecretKey writeKey =89tkd.getTrafficKey(hc.sslConfig.isClientMode ?90"clientWriteKey" : "serverWriteKey");91SecretKey writeIv =92tkd.getTrafficKey(hc.sslConfig.isClientMode ?93"clientWriteIv" : "serverWriteIv");94IvParameterSpec iv = (writeIv == null) ? null :95new IvParameterSpec(writeIv.getEncoded());96SSLWriteCipher writeCipher;97try {98writeCipher = ncs.bulkCipher.createWriteCipher(99writeAuthenticator,100hc.negotiatedProtocol, writeKey, iv,101hc.sslContext.getSecureRandom());102} catch (GeneralSecurityException gse) {103// unlikely104throw new SSLException("Algorithm missing: ", gse);105}106107if (writeCipher == null) {108throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER,109"Illegal cipher suite (" + ncs +110") and protocol version (" + hc.negotiatedProtocol + ")");111}112113if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {114SSLLogger.fine("Produced ChangeCipherSpec message");115}116117hc.conContext.outputRecord.changeWriteCiphers(writeCipher, true);118119// The handshake message has been delivered.120return null;121}122}123124/**125* The "ChangeCipherSpec" message producer.126*/127private static final128class T10ChangeCipherSpecConsumer implements SSLConsumer {129// Prevent instantiation of this class.130private T10ChangeCipherSpecConsumer() {131// blank132}133134@Override135public void consume(ConnectionContext context,136ByteBuffer message) throws IOException {137TransportContext tc = (TransportContext)context;138139// This consumer can be used only once.140tc.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id);141142// parse143if (message.remaining() != 1 || message.get() != 1) {144throw tc.fatal(Alert.UNEXPECTED_MESSAGE,145"Malformed or unexpected ChangeCipherSpec message");146}147if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {148SSLLogger.fine("Consuming ChangeCipherSpec message");149}150151// validate152if (tc.handshakeContext == null) {153throw tc.fatal(Alert.HANDSHAKE_FAILURE,154"Unexpected ChangeCipherSpec message");155}156157158HandshakeContext hc = tc.handshakeContext;159160if (hc.handshakeKeyDerivation == null) {161throw tc.fatal(Alert.UNEXPECTED_MESSAGE,162"Unexpected ChangeCipherSpec message");163}164165SSLKeyDerivation kd = hc.handshakeKeyDerivation;166if (kd instanceof LegacyTrafficKeyDerivation) {167LegacyTrafficKeyDerivation tkd = (LegacyTrafficKeyDerivation)kd;168CipherSuite ncs = hc.negotiatedCipherSuite;169Authenticator readAuthenticator;170if (ncs.bulkCipher.cipherType == CipherType.AEAD_CIPHER) {171readAuthenticator =172Authenticator.valueOf(hc.negotiatedProtocol);173} else {174try {175readAuthenticator = Authenticator.valueOf(176hc.negotiatedProtocol, ncs.macAlg,177tkd.getTrafficKey(hc.sslConfig.isClientMode ?178"serverMacKey" : "clientMacKey"));179} catch (NoSuchAlgorithmException | InvalidKeyException e) {180// unlikely181throw new SSLException("Algorithm missing: ", e);182}183}184185SecretKey readKey =186tkd.getTrafficKey(hc.sslConfig.isClientMode ?187"serverWriteKey" : "clientWriteKey");188SecretKey readIv =189tkd.getTrafficKey(hc.sslConfig.isClientMode ?190"serverWriteIv" : "clientWriteIv");191IvParameterSpec iv = (readIv == null) ? null :192new IvParameterSpec(readIv.getEncoded());193SSLReadCipher readCipher;194try {195readCipher = ncs.bulkCipher.createReadCipher(196readAuthenticator,197hc.negotiatedProtocol, readKey, iv,198hc.sslContext.getSecureRandom());199} catch (GeneralSecurityException gse) {200// unlikely201throw new SSLException("Algorithm missing: ", gse);202}203204if (readCipher == null) {205throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER,206"Illegal cipher suite (" + hc.negotiatedCipherSuite +207") and protocol version (" + hc.negotiatedProtocol +208")");209}210211tc.inputRecord.changeReadCiphers(readCipher);212} else {213throw new UnsupportedOperationException("Not supported.");214}215}216}217218private static final219class T13ChangeCipherSpecConsumer implements SSLConsumer {220// Prevent instantiation of this class.221private T13ChangeCipherSpecConsumer() {222// blank223}224225// An implementation may receive an unencrypted record of type226// change_cipher_spec consisting of the single byte value 0x01227// at any time after the first ClientHello message has been228// sent or received and before the peer's Finished message has229// been received and MUST simply drop it without further230// processing.231@Override232public void consume(ConnectionContext context,233ByteBuffer message) throws IOException {234TransportContext tc = (TransportContext)context;235236// This consumer can be used only once.237tc.consumers.remove(ContentType.CHANGE_CIPHER_SPEC.id);238239// parse240if (message.remaining() != 1 || message.get() != 1) {241throw tc.fatal(Alert.UNEXPECTED_MESSAGE,242"Malformed or unexpected ChangeCipherSpec message");243}244if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {245SSLLogger.fine("Consuming ChangeCipherSpec message");246}247248// no further processing249}250}251}252253254