|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.ssl; |
|
|
|
import java.io.IOException; |
|
import java.nio.ByteBuffer; |
|
import java.text.MessageFormat; |
|
import java.util.Locale; |
|
import javax.net.ssl.SSLProtocolException; |
|
|
|
import sun.security.ssl.ClientHello.ClientHelloMessage; |
|
import sun.security.ssl.SSLExtension.ExtensionConsumer; |
|
import sun.security.ssl.SSLHandshake.HandshakeMessage; |
|
import sun.security.ssl.SSLExtension.SSLExtensionSpec; |
|
import sun.security.ssl.ServerHello.ServerHelloMessage; |
|
import sun.misc.HexDumpEncoder; |
|
|
|
public class CookieExtension { |
|
static final HandshakeProducer chNetworkProducer = |
|
new CHCookieProducer(); |
|
static final ExtensionConsumer chOnLoadConsumer = |
|
new CHCookieConsumer(); |
|
static final HandshakeConsumer chOnTradeConsumer = |
|
new CHCookieUpdate(); |
|
|
|
static final HandshakeProducer hrrNetworkProducer = |
|
new HRRCookieProducer(); |
|
static final ExtensionConsumer hrrOnLoadConsumer = |
|
new HRRCookieConsumer(); |
|
|
|
static final HandshakeProducer hrrNetworkReproducer = |
|
new HRRCookieReproducer(); |
|
|
|
static final CookieStringizer cookieStringizer = |
|
new CookieStringizer(); |
|
|
|
|
|
|
|
*/ |
|
static class CookieSpec implements SSLExtensionSpec { |
|
final byte[] cookie; |
|
|
|
private CookieSpec(ByteBuffer m) throws IOException { |
|
|
|
if (m.remaining() < 3) { |
|
throw new SSLProtocolException( |
|
"Invalid cookie extension: insufficient data"); |
|
} |
|
|
|
this.cookie = Record.getBytes16(m); |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
MessageFormat messageFormat = new MessageFormat( |
|
"\"cookie\": '{'\n" + |
|
"{0}\n" + |
|
"'}',", Locale.ENGLISH); |
|
HexDumpEncoder hexEncoder = new HexDumpEncoder(); |
|
Object[] messageFields = { |
|
Utilities.indent(hexEncoder.encode(cookie)) |
|
}; |
|
|
|
return messageFormat.format(messageFields); |
|
} |
|
} |
|
|
|
private static final class CookieStringizer implements SSLStringizer { |
|
@Override |
|
public String toString(ByteBuffer buffer) { |
|
try { |
|
return (new CookieSpec(buffer)).toString(); |
|
} catch (IOException ioe) { |
|
|
|
return ioe.getMessage(); |
|
} |
|
} |
|
} |
|
|
|
private static final |
|
class CHCookieProducer implements HandshakeProducer { |
|
|
|
private CHCookieProducer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public byte[] produce(ConnectionContext context, |
|
HandshakeMessage message) throws IOException { |
|
ClientHandshakeContext chc = (ClientHandshakeContext) context; |
|
|
|
|
|
if (!chc.sslConfig.isAvailable(SSLExtension.CH_COOKIE)) { |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine( |
|
"Ignore unavailable cookie extension"); |
|
} |
|
return null; |
|
} |
|
|
|
|
|
CookieSpec spec = (CookieSpec)chc.handshakeExtensions.get( |
|
SSLExtension.HRR_COOKIE); |
|
|
|
if (spec != null && |
|
spec.cookie != null && spec.cookie.length != 0) { |
|
byte[] extData = new byte[spec.cookie.length + 2]; |
|
ByteBuffer m = ByteBuffer.wrap(extData); |
|
Record.putBytes16(m, spec.cookie); |
|
return extData; |
|
} |
|
|
|
return null; |
|
} |
|
} |
|
|
|
private static final |
|
class CHCookieConsumer implements ExtensionConsumer { |
|
|
|
private CHCookieConsumer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public void consume(ConnectionContext context, |
|
HandshakeMessage message, ByteBuffer buffer) throws IOException { |
|
|
|
ServerHandshakeContext shc = (ServerHandshakeContext)context; |
|
|
|
|
|
if (!shc.sslConfig.isAvailable(SSLExtension.CH_COOKIE)) { |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine( |
|
"Ignore unavailable cookie extension"); |
|
} |
|
return; |
|
} |
|
|
|
CookieSpec spec; |
|
try { |
|
spec = new CookieSpec(buffer); |
|
} catch (IOException ioe) { |
|
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); |
|
} |
|
|
|
shc.handshakeExtensions.put(SSLExtension.CH_COOKIE, spec); |
|
|
|
// No impact on session resumption. |
|
// |
|
// Note that the protocol version negotiation happens before the |
|
// session resumption negotiation. And the session resumption |
|
// negotiation depends on the negotiated protocol version. |
|
} |
|
} |
|
|
|
private static final |
|
class CHCookieUpdate implements HandshakeConsumer { |
|
|
|
private CHCookieUpdate() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public void consume(ConnectionContext context, |
|
HandshakeMessage message) throws IOException { |
|
|
|
ServerHandshakeContext shc = (ServerHandshakeContext)context; |
|
ClientHelloMessage clientHello = (ClientHelloMessage)message; |
|
|
|
CookieSpec spec = (CookieSpec) |
|
shc.handshakeExtensions.get(SSLExtension.CH_COOKIE); |
|
if (spec == null) { |
|
|
|
return; |
|
} |
|
|
|
HelloCookieManager hcm = |
|
shc.sslContext.getHelloCookieManager(shc.negotiatedProtocol); |
|
if (!hcm.isCookieValid(shc, clientHello, spec.cookie)) { |
|
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, |
|
"unrecognized cookie"); |
|
} |
|
} |
|
} |
|
|
|
private static final |
|
class HRRCookieProducer implements HandshakeProducer { |
|
|
|
private HRRCookieProducer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public byte[] produce(ConnectionContext context, |
|
HandshakeMessage message) throws IOException { |
|
|
|
ServerHandshakeContext shc = (ServerHandshakeContext)context; |
|
ServerHelloMessage hrrm = (ServerHelloMessage)message; |
|
|
|
|
|
if (!shc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) { |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine( |
|
"Ignore unavailable cookie extension"); |
|
} |
|
return null; |
|
} |
|
|
|
HelloCookieManager hcm = |
|
shc.sslContext.getHelloCookieManager(shc.negotiatedProtocol); |
|
|
|
byte[] cookie = hcm.createCookie(shc, hrrm.clientHello); |
|
|
|
byte[] extData = new byte[cookie.length + 2]; |
|
ByteBuffer m = ByteBuffer.wrap(extData); |
|
Record.putBytes16(m, cookie); |
|
|
|
return extData; |
|
} |
|
} |
|
|
|
private static final |
|
class HRRCookieConsumer implements ExtensionConsumer { |
|
|
|
private HRRCookieConsumer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public void consume(ConnectionContext context, |
|
HandshakeMessage message, ByteBuffer buffer) throws IOException { |
|
|
|
ClientHandshakeContext chc = (ClientHandshakeContext)context; |
|
|
|
|
|
if (!chc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) { |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine( |
|
"Ignore unavailable cookie extension"); |
|
} |
|
return; |
|
} |
|
|
|
CookieSpec spec; |
|
try { |
|
spec = new CookieSpec(buffer); |
|
} catch (IOException ioe) { |
|
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe); |
|
} |
|
|
|
chc.handshakeExtensions.put(SSLExtension.HRR_COOKIE, spec); |
|
} |
|
} |
|
|
|
private static final |
|
class HRRCookieReproducer implements HandshakeProducer { |
|
|
|
private HRRCookieReproducer() { |
|
// blank |
|
} |
|
|
|
@Override |
|
public byte[] produce(ConnectionContext context, |
|
HandshakeMessage message) throws IOException { |
|
|
|
ServerHandshakeContext shc = (ServerHandshakeContext) context; |
|
|
|
|
|
if (!shc.sslConfig.isAvailable(SSLExtension.HRR_COOKIE)) { |
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { |
|
SSLLogger.fine( |
|
"Ignore unavailable cookie extension"); |
|
} |
|
return null; |
|
} |
|
|
|
|
|
CookieSpec spec = (CookieSpec)shc.handshakeExtensions.get( |
|
SSLExtension.CH_COOKIE); |
|
|
|
if (spec != null && |
|
spec.cookie != null && spec.cookie.length != 0) { |
|
byte[] extData = new byte[spec.cookie.length + 2]; |
|
ByteBuffer m = ByteBuffer.wrap(extData); |
|
Record.putBytes16(m, spec.cookie); |
|
return extData; |
|
} |
|
|
|
return null; |
|
} |
|
} |
|
} |