org.openjsse.sun.security.ssl.ExtendedMasterSecretExtension Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openjsse Show documentation
Show all versions of openjsse Show documentation
OpenJSSE delivers a TLS 1.3 JSSE provider for Java SE 8
/*
* Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjsse.sun.security.ssl;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.net.ssl.SSLProtocolException;
import static org.openjsse.sun.security.ssl.SSLExtension.CH_EXTENDED_MASTER_SECRET;
import org.openjsse.sun.security.ssl.SSLExtension.ExtensionConsumer;
import static org.openjsse.sun.security.ssl.SSLExtension.SH_EXTENDED_MASTER_SECRET;
import org.openjsse.sun.security.ssl.SSLExtension.SSLExtensionSpec;
import org.openjsse.sun.security.ssl.SSLHandshake.HandshakeMessage;
/**
* Pack of the "extended_master_secret" extensions [RFC 7627].
*/
final class ExtendedMasterSecretExtension {
static final HandshakeProducer chNetworkProducer =
new CHExtendedMasterSecretProducer();
static final ExtensionConsumer chOnLoadConsumer =
new CHExtendedMasterSecretConsumer();
static final HandshakeAbsence chOnLoadAbsence =
new CHExtendedMasterSecretAbsence();
static final HandshakeProducer shNetworkProducer =
new SHExtendedMasterSecretProducer();
static final ExtensionConsumer shOnLoadConsumer =
new SHExtendedMasterSecretConsumer();
static final HandshakeAbsence shOnLoadAbsence =
new SHExtendedMasterSecretAbsence();
static final SSLStringizer emsStringizer =
new ExtendedMasterSecretStringizer();
/**
* The "extended_master_secret" extension.
*/
static final class ExtendedMasterSecretSpec implements SSLExtensionSpec {
// A nominal object that does not holding any real renegotiation info.
static final ExtendedMasterSecretSpec NOMINAL =
new ExtendedMasterSecretSpec();
private ExtendedMasterSecretSpec() {
// blank
}
private ExtendedMasterSecretSpec(ByteBuffer m) throws IOException {
// Parse the extension.
if (m.hasRemaining()) {
throw new SSLProtocolException(
"Invalid extended_master_secret extension data: " +
"not empty");
}
}
@Override
public String toString() {
return "";
}
}
private static final
class ExtendedMasterSecretStringizer implements SSLStringizer {
@Override
public String toString(ByteBuffer buffer) {
try {
return (new ExtendedMasterSecretSpec(buffer)).toString();
} catch (IOException ioe) {
// For debug logging only, so please swallow exceptions.
return ioe.getMessage();
}
}
}
/**
* Network data producer of a "extended_master_secret" extension in
* the ClientHello handshake message.
*/
private static final
class CHExtendedMasterSecretProducer implements HandshakeProducer {
// Prevent instantiation of this class.
private CHExtendedMasterSecretProducer() {
// blank
}
@Override
public byte[] produce(ConnectionContext context,
HandshakeMessage message) throws IOException {
// The producing happens in client side only.
ClientHandshakeContext chc = (ClientHandshakeContext)context;
// Is it a supported and enabled extension?
if (!chc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET) ||
!SSLConfiguration.useExtendedMasterSecret ||
!chc.conContext.protocolVersion.useTLS10PlusSpec()) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"Ignore unavailable extended_master_secret extension");
}
return null;
}
if (chc.handshakeSession == null ||
chc.handshakeSession.useExtendedMasterSecret) {
byte[] extData = new byte[0];
chc.handshakeExtensions.put(CH_EXTENDED_MASTER_SECRET,
ExtendedMasterSecretSpec.NOMINAL);
return extData;
}
return null;
}
}
/**
* Network data producer of a "extended_master_secret" extension in
* the ServerHello handshake message.
*/
private static final
class CHExtendedMasterSecretConsumer implements ExtensionConsumer {
// Prevent instantiation of this class.
private CHExtendedMasterSecretConsumer() {
// blank
}
@Override
public void consume(ConnectionContext context,
HandshakeMessage message, ByteBuffer buffer) throws IOException {
// The consuming happens in server side only.
ServerHandshakeContext shc = (ServerHandshakeContext)context;
// Is it a supported and enabled extension?
if (!shc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET) ||
!SSLConfiguration.useExtendedMasterSecret ||
!shc.negotiatedProtocol.useTLS10PlusSpec()) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine("Ignore unavailable extension: " +
CH_EXTENDED_MASTER_SECRET.name);
}
return; // ignore the extension
}
// Parse the extension.
ExtendedMasterSecretSpec spec;
try {
spec = new ExtendedMasterSecretSpec(buffer);
} catch (IOException ioe) {
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
}
if (shc.isResumption && shc.resumingSession != null &&
!shc.resumingSession.useExtendedMasterSecret) {
// For abbreviated handshake request, If the original
// session did not use the "extended_master_secret"
// extension but the new ClientHello contains the
// extension, then the server MUST NOT perform the
// abbreviated handshake. Instead, it SHOULD continue
// with a full handshake.
shc.isResumption = false;
shc.resumingSession = null;
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"abort session resumption which did not use " +
"Extended Master Secret extension");
}
}
// Update the context.
//
shc.handshakeExtensions.put(
CH_EXTENDED_MASTER_SECRET, ExtendedMasterSecretSpec.NOMINAL);
// No impact on session resumption.
}
}
/**
* The absence processing if a "extended_master_secret" extension is
* not present in the ClientHello handshake message.
*/
private static final
class CHExtendedMasterSecretAbsence implements HandshakeAbsence {
@Override
public void absent(ConnectionContext context,
HandshakeMessage message) throws IOException {
// The producing happens in server side only.
ServerHandshakeContext shc = (ServerHandshakeContext)context;
// Is it a supported and enabled extension?
if (!shc.sslConfig.isAvailable(CH_EXTENDED_MASTER_SECRET) ||
!SSLConfiguration.useExtendedMasterSecret) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine("Ignore unavailable extension: " +
CH_EXTENDED_MASTER_SECRET.name);
}
return; // ignore the extension
}
if (shc.negotiatedProtocol.useTLS10PlusSpec() &&
!SSLConfiguration.allowLegacyMasterSecret) {
// For full handshake, if the server receives a ClientHello
// without the extension, it SHOULD abort the handshake if
// it does not wish to interoperate with legacy clients.
//
// As if extended master extension is required for full
// handshake, it MUST be used in abbreviated handshake too.
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
"Extended Master Secret extension is required");
}
if (shc.isResumption && shc.resumingSession != null) {
if (shc.resumingSession.useExtendedMasterSecret) {
// For abbreviated handshake request, if the original
// session used the "extended_master_secret" extension
// but the new ClientHello does not contain it, the
// server MUST abort the abbreviated handshake.
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
"Missing Extended Master Secret extension " +
"on session resumption");
} else {
// For abbreviated handshake request, if neither the
// original session nor the new ClientHello uses the
// extension, the server SHOULD abort the handshake.
if (!SSLConfiguration.allowLegacyResumption) {
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
"Missing Extended Master Secret extension " +
"on session resumption");
} else { // Otherwise, continue with a full handshake.
shc.isResumption = false;
shc.resumingSession = null;
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"abort session resumption, " +
"missing Extended Master Secret extension");
}
}
}
}
}
}
/**
* Network data producer of a "extended_master_secret" extension in
* the ServerHello handshake message.
*/
private static final
class SHExtendedMasterSecretProducer implements HandshakeProducer {
// Prevent instantiation of this class.
private SHExtendedMasterSecretProducer() {
// blank
}
@Override
public byte[] produce(ConnectionContext context,
HandshakeMessage message) throws IOException {
// The producing happens in server side only.
ServerHandshakeContext shc = (ServerHandshakeContext)context;
if (shc.handshakeSession.useExtendedMasterSecret) {
byte[] extData = new byte[0];
shc.handshakeExtensions.put(SH_EXTENDED_MASTER_SECRET,
ExtendedMasterSecretSpec.NOMINAL);
return extData;
}
return null;
}
}
/**
* Network data consumer of a "extended_master_secret" extension in
* the ServerHello handshake message.
*/
private static final
class SHExtendedMasterSecretConsumer implements ExtensionConsumer {
// Prevent instantiation of this class.
private SHExtendedMasterSecretConsumer() {
// blank
}
@Override
public void consume(ConnectionContext context,
HandshakeMessage message, ByteBuffer buffer) throws IOException {
// The producing happens in client side only.
ClientHandshakeContext chc = (ClientHandshakeContext)context;
// In response to the client extended_master_secret extension
// request, which is mandatory for ClientHello message.
ExtendedMasterSecretSpec requstedSpec = (ExtendedMasterSecretSpec)
chc.handshakeExtensions.get(CH_EXTENDED_MASTER_SECRET);
if (requstedSpec == null) {
throw chc.conContext.fatal(Alert.UNSUPPORTED_EXTENSION,
"Server sent the extended_master_secret " +
"extension improperly");
}
// Parse the extension.
ExtendedMasterSecretSpec spec;
try {
spec = new ExtendedMasterSecretSpec(buffer);
} catch (IOException ioe) {
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
}
if (chc.isResumption && chc.resumingSession != null &&
!chc.resumingSession.useExtendedMasterSecret) {
throw chc.conContext.fatal(Alert.UNSUPPORTED_EXTENSION,
"Server sent an unexpected extended_master_secret " +
"extension on session resumption");
}
// Update the context.
chc.handshakeExtensions.put(
SH_EXTENDED_MASTER_SECRET, ExtendedMasterSecretSpec.NOMINAL);
// No impact on session resumption.
}
}
/**
* The absence processing if a "extended_master_secret" extension is
* not present in the ServerHello handshake message.
*/
private static final
class SHExtendedMasterSecretAbsence implements HandshakeAbsence {
@Override
public void absent(ConnectionContext context,
HandshakeMessage message) throws IOException {
// The producing happens in client side only.
ClientHandshakeContext chc = (ClientHandshakeContext)context;
if (SSLConfiguration.useExtendedMasterSecret &&
!SSLConfiguration.allowLegacyMasterSecret) {
// For full handshake, if a client receives a ServerHello
// without the extension, it SHOULD abort the handshake if
// it does not wish to interoperate with legacy servers.
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
"Extended Master Secret extension is required");
}
if (chc.isResumption && chc.resumingSession != null) {
if (chc.resumingSession.useExtendedMasterSecret) {
// For abbreviated handshake, if the original session used
// the "extended_master_secret" extension but the new
// ServerHello does not contain the extension, the client
// MUST abort the handshake.
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
"Missing Extended Master Secret extension " +
"on session resumption");
} else if (SSLConfiguration.useExtendedMasterSecret &&
!SSLConfiguration.allowLegacyResumption &&
chc.negotiatedProtocol.useTLS10PlusSpec()) {
// Unlikely, abbreviated handshake should be discarded.
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
"Extended Master Secret extension is required");
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy