Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/KeyUpdate.java
38830 views
/*1* Copyright (c) 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.text.MessageFormat;31import java.util.Locale;3233import sun.security.ssl.SSLHandshake.HandshakeMessage;34import sun.security.ssl.SSLCipher.SSLReadCipher;35import sun.security.ssl.SSLCipher.SSLWriteCipher;3637import javax.crypto.SecretKey;38import javax.crypto.spec.IvParameterSpec;3940/**41* Pack of the KeyUpdate handshake message.42*/43final class KeyUpdate {44static final SSLProducer kickstartProducer =45new KeyUpdateKickstartProducer();4647static final SSLConsumer handshakeConsumer =48new KeyUpdateConsumer();49static final HandshakeProducer handshakeProducer =50new KeyUpdateProducer();5152/**53* The KeyUpdate handshake message.54*55* The KeyUpdate handshake message is used to indicate that the sender is56* updating its sending cryptographic keys.57*58* enum {59* update_not_requested(0), update_requested(1), (255)60* } KeyUpdateRequest;61*62* struct {63* KeyUpdateRequest request_update;64* } KeyUpdate;65*/66static final class KeyUpdateMessage extends HandshakeMessage {67private final KeyUpdateRequest status;6869KeyUpdateMessage(PostHandshakeContext context,70KeyUpdateRequest status) {71super(context);72this.status = status;73}7475KeyUpdateMessage(PostHandshakeContext context,76ByteBuffer m) throws IOException {77super(context);7879if (m.remaining() != 1) {80throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,81"KeyUpdate has an unexpected length of "+82m.remaining());83}8485byte request = m.get();86this.status = KeyUpdateRequest.valueOf(request);87if (status == null) {88throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,89"Invalid KeyUpdate message value: " +90KeyUpdateRequest.nameOf(request));91}92}9394@Override95public SSLHandshake handshakeType() {96return SSLHandshake.KEY_UPDATE;97}9899@Override100public int messageLength() {101// one byte enum102return 1;103}104105@Override106public void send(HandshakeOutStream s) throws IOException {107s.putInt8(status.id);108}109110@Override111public String toString() {112MessageFormat messageFormat = new MessageFormat(113"\"KeyUpdate\": '{'\n" +114" \"request_update\": {0}\n" +115"'}'",116Locale.ENGLISH);117118Object[] messageFields = {119status.name120};121122return messageFormat.format(messageFields);123}124}125126enum KeyUpdateRequest {127NOTREQUESTED ((byte)0, "update_not_requested"),128REQUESTED ((byte)1, "update_requested");129130final byte id;131final String name;132133private KeyUpdateRequest(byte id, String name) {134this.id = id;135this.name = name;136}137138static KeyUpdateRequest valueOf(byte id) {139for (KeyUpdateRequest kur : KeyUpdateRequest.values()) {140if (kur.id == id) {141return kur;142}143}144145return null;146}147148static String nameOf(byte id) {149for (KeyUpdateRequest kur : KeyUpdateRequest.values()) {150if (kur.id == id) {151return kur.name;152}153}154155return "<UNKNOWN KeyUpdateRequest TYPE: " + (id & 0x0FF) + ">";156}157}158159private static final160class KeyUpdateKickstartProducer implements SSLProducer {161// Prevent instantiation of this class.162private KeyUpdateKickstartProducer() {163// blank164}165166// Produce kickstart handshake message.167@Override168public byte[] produce(ConnectionContext context) throws IOException {169PostHandshakeContext hc = (PostHandshakeContext)context;170return handshakeProducer.produce(context,171new KeyUpdateMessage(hc, KeyUpdateRequest.REQUESTED));172}173}174175/**176* The "KeyUpdate" handshake message consumer.177*/178private static final class KeyUpdateConsumer implements SSLConsumer {179// Prevent instantiation of this class.180private KeyUpdateConsumer() {181// blank182}183184@Override185public void consume(ConnectionContext context,186ByteBuffer message) throws IOException {187// The consuming happens in client side only.188PostHandshakeContext hc = (PostHandshakeContext)context;189KeyUpdateMessage km = new KeyUpdateMessage(hc, message);190if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {191SSLLogger.fine(192"Consuming KeyUpdate post-handshake message", km);193}194195// Update read key and IV.196SSLTrafficKeyDerivation kdg =197SSLTrafficKeyDerivation.valueOf(hc.conContext.protocolVersion);198if (kdg == null) {199// unlikely200throw hc.conContext.fatal(Alert.INTERNAL_ERROR,201"Not supported key derivation: " +202hc.conContext.protocolVersion);203}204205SSLKeyDerivation skd = kdg.createKeyDerivation(hc,206hc.conContext.inputRecord.readCipher.baseSecret);207if (skd == null) {208// unlikely209throw hc.conContext.fatal(210Alert.INTERNAL_ERROR, "no key derivation");211}212213SecretKey nplus1 = skd.deriveKey("TlsUpdateNplus1", null);214SSLKeyDerivation kd = kdg.createKeyDerivation(hc, nplus1);215SecretKey key = kd.deriveKey("TlsKey", null);216IvParameterSpec ivSpec = new IvParameterSpec(217kd.deriveKey("TlsIv", null).getEncoded());218try {219SSLReadCipher rc =220hc.negotiatedCipherSuite.bulkCipher.createReadCipher(221Authenticator.valueOf(hc.conContext.protocolVersion),222hc.conContext.protocolVersion, key, ivSpec,223hc.sslContext.getSecureRandom());224225if (rc == null) {226throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER,227"Illegal cipher suite (" + hc.negotiatedCipherSuite +228") and protocol version (" + hc.negotiatedProtocol +229")");230}231232rc.baseSecret = nplus1;233hc.conContext.inputRecord.changeReadCiphers(rc);234if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {235SSLLogger.fine("KeyUpdate: read key updated");236}237} catch (GeneralSecurityException gse) {238throw hc.conContext.fatal(Alert.INTERNAL_ERROR,239"Failure to derive read secrets", gse);240}241242if (km.status == KeyUpdateRequest.REQUESTED) {243// Update the write key and IV.244handshakeProducer.produce(hc,245new KeyUpdateMessage(hc, KeyUpdateRequest.NOTREQUESTED));246return;247}248249// clean handshake context250hc.conContext.finishPostHandshake();251}252}253254/**255* The "KeyUpdate" handshake message producer.256*/257private static final class KeyUpdateProducer implements HandshakeProducer {258// Prevent instantiation of this class.259private KeyUpdateProducer() {260// blank261}262263@Override264public byte[] produce(ConnectionContext context,265HandshakeMessage message) throws IOException {266// The producing happens in server side only.267PostHandshakeContext hc = (PostHandshakeContext)context;268KeyUpdateMessage km = (KeyUpdateMessage)message;269if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {270SSLLogger.fine(271"Produced KeyUpdate post-handshake message", km);272}273274// Update the write key and IV.275SSLTrafficKeyDerivation kdg =276SSLTrafficKeyDerivation.valueOf(hc.conContext.protocolVersion);277if (kdg == null) {278// unlikely279throw hc.conContext.fatal(Alert.INTERNAL_ERROR,280"Not supported key derivation: " +281hc.conContext.protocolVersion);282}283284SSLKeyDerivation skd = kdg.createKeyDerivation(hc,285hc.conContext.outputRecord.writeCipher.baseSecret);286if (skd == null) {287// unlikely288throw hc.conContext.fatal(289Alert.INTERNAL_ERROR, "no key derivation");290}291292SecretKey nplus1 = skd.deriveKey("TlsUpdateNplus1", null);293SSLKeyDerivation kd = kdg.createKeyDerivation(hc, nplus1);294SecretKey key = kd.deriveKey("TlsKey", null);295IvParameterSpec ivSpec = new IvParameterSpec(296kd.deriveKey("TlsIv", null).getEncoded());297298SSLWriteCipher wc;299try {300wc = hc.negotiatedCipherSuite.bulkCipher.createWriteCipher(301Authenticator.valueOf(hc.conContext.protocolVersion),302hc.conContext.protocolVersion, key, ivSpec,303hc.sslContext.getSecureRandom());304} catch (GeneralSecurityException gse) {305throw hc.conContext.fatal(Alert.INTERNAL_ERROR,306"Failure to derive write secrets", gse);307}308309if (wc == null) {310throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER,311"Illegal cipher suite (" + hc.negotiatedCipherSuite +312") and protocol version (" + hc.negotiatedProtocol + ")");313}314315// Output the handshake message and change the write cipher.316//317// The KeyUpdate handshake message SHALL be delivered in the318// changeWriteCiphers() implementation.319wc.baseSecret = nplus1;320hc.conContext.outputRecord.changeWriteCiphers(wc, km.status.id);321if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {322SSLLogger.fine("KeyUpdate: write key updated");323}324325// clean handshake context326hc.conContext.finishPostHandshake();327328// The handshake message has been delivered.329return null;330}331}332}333334335