Path: blob/master/src/java.base/share/classes/sun/security/ssl/CookieExtension.java
41159 views
/*1* Copyright (c) 2018, 2020, 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.text.MessageFormat;30import java.util.Locale;31import javax.net.ssl.SSLProtocolException;3233import sun.security.ssl.ClientHello.ClientHelloMessage;34import sun.security.ssl.SSLExtension.ExtensionConsumer;35import sun.security.ssl.SSLHandshake.HandshakeMessage;36import sun.security.ssl.SSLExtension.SSLExtensionSpec;37import sun.security.ssl.ServerHello.ServerHelloMessage;38import sun.security.util.HexDumpEncoder;3940public class CookieExtension {41static final HandshakeProducer chNetworkProducer =42new CHCookieProducer();43static final ExtensionConsumer chOnLoadConsumer =44new CHCookieConsumer();45static final HandshakeConsumer chOnTradeConsumer =46new CHCookieUpdate();4748static final HandshakeProducer hrrNetworkProducer =49new HRRCookieProducer();50static final ExtensionConsumer hrrOnLoadConsumer =51new HRRCookieConsumer();5253static final HandshakeProducer hrrNetworkReproducer =54new HRRCookieReproducer();5556static final CookieStringizer cookieStringizer =57new CookieStringizer();5859/**60* The "cookie" extension.61*/62static class CookieSpec implements SSLExtensionSpec {63final byte[] cookie;6465private CookieSpec(HandshakeContext hc,66ByteBuffer m) throws IOException {67// opaque cookie<1..2^16-1>;68if (m.remaining() < 3) {69throw hc.conContext.fatal(Alert.DECODE_ERROR,70new SSLProtocolException(71"Invalid cookie extension: insufficient data"));72}7374this.cookie = Record.getBytes16(m);75}7677@Override78public String toString() {79MessageFormat messageFormat = new MessageFormat(80"\"cookie\": '{'\n" +81"{0}\n" +82"'}',", Locale.ENGLISH);83HexDumpEncoder hexEncoder = new HexDumpEncoder();84Object[] messageFields = {85Utilities.indent(hexEncoder.encode(cookie))86};8788return messageFormat.format(messageFields);89}90}9192private static final class CookieStringizer implements SSLStringizer {93@Override94public String toString(HandshakeContext hc, ByteBuffer buffer) {95try {96return (new CookieSpec(hc, buffer)).toString();97} catch (IOException ioe) {98// For debug logging only, so please swallow exceptions.99return ioe.getMessage();100}101}102}103104private static final105class CHCookieProducer implements HandshakeProducer {106// Prevent instantiation of this class.107private CHCookieProducer() {108// blank109}110111@Override112public byte[] produce(ConnectionContext context,113HandshakeMessage message) throws IOException {114ClientHandshakeContext chc = (ClientHandshakeContext) context;115116// Is it a supported and enabled extension?117if (!chc.sslConfig.isAvailable(SSLExtension.CH_COOKIE)) {118if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {119SSLLogger.fine(120"Ignore unavailable cookie extension");121}122return null;123}124125// response to an HelloRetryRequest cookie126CookieSpec spec = (CookieSpec)chc.handshakeExtensions.get(127SSLExtension.HRR_COOKIE);128129if (spec != null &&130spec.cookie != null && spec.cookie.length != 0) {131byte[] extData = new byte[spec.cookie.length + 2];132ByteBuffer m = ByteBuffer.wrap(extData);133Record.putBytes16(m, spec.cookie);134return extData;135}136137return null;138}139}140141private static final142class CHCookieConsumer implements ExtensionConsumer {143// Prevent instantiation of this class.144private CHCookieConsumer() {145// blank146}147148@Override149public void consume(ConnectionContext context,150HandshakeMessage message, ByteBuffer buffer) throws IOException {151// The consuming happens in server side only.152ServerHandshakeContext shc = (ServerHandshakeContext)context;153154// Is it a supported and enabled extension?155if (!shc.sslConfig.isAvailable(SSLExtension.CH_COOKIE)) {156if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {157SSLLogger.fine(158"Ignore unavailable cookie extension");159}160return; // ignore the extension161}162163CookieSpec spec = new CookieSpec(shc, buffer);164shc.handshakeExtensions.put(SSLExtension.CH_COOKIE, spec);165166// No impact on session resumption.167//168// Note that the protocol version negotiation happens before the169// session resumption negotiation. And the session resumption170// negotiation depends on the negotiated protocol version.171}172}173174private static final175class CHCookieUpdate implements HandshakeConsumer {176// Prevent instantiation of this class.177private CHCookieUpdate() {178// blank179}180181@Override182public void consume(ConnectionContext context,183HandshakeMessage message) throws IOException {184// The consuming happens in server side only.185ServerHandshakeContext shc = (ServerHandshakeContext)context;186ClientHelloMessage clientHello = (ClientHelloMessage)message;187188CookieSpec spec = (CookieSpec)189shc.handshakeExtensions.get(SSLExtension.CH_COOKIE);190if (spec == null) {191// Ignore, no "cookie" extension requested.192return;193}194195HelloCookieManager hcm =196shc.sslContext.getHelloCookieManager(shc.negotiatedProtocol);197if (!hcm.isCookieValid(shc, clientHello, spec.cookie)) {198throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,199"unrecognized cookie");200}201}202}203204private static final205class HRRCookieProducer implements HandshakeProducer {206// Prevent instantiation of this class.207private HRRCookieProducer() {208// blank209}210211@Override212public byte[] produce(ConnectionContext context,213HandshakeMessage message) throws IOException {214// The producing happens in server side only.215ServerHandshakeContext shc = (ServerHandshakeContext)context;216ServerHelloMessage hrrm = (ServerHelloMessage)message;217218// Is it a supported and enabled extension?219if (!shc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) {220if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {221SSLLogger.fine(222"Ignore unavailable cookie extension");223}224return null;225}226227HelloCookieManager hcm =228shc.sslContext.getHelloCookieManager(shc.negotiatedProtocol);229230byte[] cookie = hcm.createCookie(shc, hrrm.clientHello);231232byte[] extData = new byte[cookie.length + 2];233ByteBuffer m = ByteBuffer.wrap(extData);234Record.putBytes16(m, cookie);235236return extData;237}238}239240private static final241class HRRCookieConsumer implements ExtensionConsumer {242// Prevent instantiation of this class.243private HRRCookieConsumer() {244// blank245}246247@Override248public void consume(ConnectionContext context,249HandshakeMessage message, ByteBuffer buffer) throws IOException {250// The consuming happens in client side only.251ClientHandshakeContext chc = (ClientHandshakeContext)context;252253// Is it a supported and enabled extension?254if (!chc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) {255if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {256SSLLogger.fine(257"Ignore unavailable cookie extension");258}259return; // ignore the extension260}261262CookieSpec spec = new CookieSpec(chc, buffer);263chc.handshakeExtensions.put(SSLExtension.HRR_COOKIE, spec);264}265}266267private static final268class HRRCookieReproducer implements HandshakeProducer {269// Prevent instantiation of this class.270private HRRCookieReproducer() {271// blank272}273274@Override275public byte[] produce(ConnectionContext context,276HandshakeMessage message) throws IOException {277// The producing happens in server side only.278ServerHandshakeContext shc = (ServerHandshakeContext) context;279280// Is it a supported and enabled extension?281if (!shc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) {282if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {283SSLLogger.fine(284"Ignore unavailable cookie extension");285}286return null;287}288289// copy of the ClientHello cookie290CookieSpec spec = (CookieSpec)shc.handshakeExtensions.get(291SSLExtension.CH_COOKIE);292293if (spec != null &&294spec.cookie != null && spec.cookie.length != 0) {295byte[] extData = new byte[spec.cookie.length + 2];296ByteBuffer m = ByteBuffer.wrap(extData);297Record.putBytes16(m, spec.cookie);298return extData;299}300301return null;302}303}304}305306307