--- a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java Wed Jul 17 13:41:12 2019 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java Wed Jul 17 14:37:50 2019 -0700
@@ -45,7 +45,6 @@
*/
final class NewSessionTicket {
static final int MAX_TICKET_LIFETIME = 604800; // seconds, 7 days
-
static final SSLConsumer handshakeConsumer =
new T13NewSessionTicketConsumer();
static final SSLConsumer handshake12Consumer =
@@ -60,7 +59,7 @@
*/
abstract static class NewSessionTicketMessage extends HandshakeMessage {
int ticketLifetime;
- byte[] ticket;
+ byte[] ticket = new byte[0];
NewSessionTicketMessage(HandshakeContext context) {
super(context);
@@ -83,6 +82,9 @@
"TicketNonce not part of RFC 5077.");
}
+ boolean isValid() {
+ return (ticket.length > 0);
+ }
}
/**
* NewSessionTicket for TLS 1.2 and below (RFC 5077)
@@ -102,13 +104,13 @@
// RFC5077 struct {
// uint32 ticket_lifetime;
- // opaque ticket<1..2^16-1>;
+ // opaque ticket<0..2^16-1>;
// } NewSessionTicket;
super(context);
- if (m.remaining() < 14) {
+ if (m.remaining() < 6) {
throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Invalid NewSessionTicket message: no sufficient data");
+ "Invalid NewSessionTicket message: insufficient data");
}
this.ticketLifetime = Record.getInt32(m);
@@ -186,7 +188,7 @@
if (m.remaining() < 14) {
throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Invalid NewSessionTicket message: no sufficient data");
+ "Invalid NewSessionTicket message: insufficient data");
}
this.ticketLifetime = Record.getInt32(m);
@@ -195,18 +197,21 @@
if (m.remaining() < 5) {
throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Invalid NewSessionTicket message: no sufficient data");
+ "Invalid NewSessionTicket message: insufficient ticket" +
+ " data");
}
this.ticket = Record.getBytes16(m);
if (ticket.length == 0) {
- throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.fine(
"No ticket in the NewSessionTicket handshake message");
+ }
}
if (m.remaining() < 2) {
throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Invalid NewSessionTicket message: no sufficient data");
+ "Invalid NewSessionTicket message: extra data");
}
SSLExtension[] supportedExtensions =
@@ -310,36 +315,45 @@
@Override
public byte[] produce(ConnectionContext context) throws IOException {
- // The producing happens in server side only.
- ServerHandshakeContext shc = (ServerHandshakeContext)context;
+ HandshakeContext hc = (HandshakeContext)context;
- // Is this session resumable?
- if (!shc.handshakeSession.isRejoinable()) {
- return null;
- }
+ // The producing happens in server side only.
+ if (hc instanceof ServerHandshakeContext) {
+ // Is this session resumable?
+ if (!hc.handshakeSession.isRejoinable()) {
+ return null;
+ }
- // What's the requested PSK key exchange modes?
- //
- // Note that currently, the NewSessionTicket post-handshake is
- // produced and delivered only in the current handshake context
- // if required.
- PskKeyExchangeModesSpec pkemSpec =
- (PskKeyExchangeModesSpec)shc.handshakeExtensions.get(
- SSLExtension.PSK_KEY_EXCHANGE_MODES);
- if (pkemSpec == null || !pkemSpec.contains(
- PskKeyExchangeModesExtension.PskKeyExchangeMode.PSK_DHE_KE)) {
- // Client doesn't support PSK with (EC)DHE key establishment.
- return null;
+ // What's the requested PSK key exchange modes?
+ //
+ // Note that currently, the NewSessionTicket post-handshake is
+ // produced and delivered only in the current handshake context
+ // if required.
+ PskKeyExchangeModesSpec pkemSpec =
+ (PskKeyExchangeModesSpec) hc.handshakeExtensions.get(
+ SSLExtension.PSK_KEY_EXCHANGE_MODES);
+ if (pkemSpec == null || !pkemSpec.contains(
+ PskKeyExchangeModesExtension.PskKeyExchangeMode.PSK_DHE_KE)) {
+ // Client doesn't support PSK with (EC)DHE key establishment.
+ return null;
+ }
+ } else { // PostHandshakeContext
+
+ // Check if we have sent a PSK already, then we know it is using a
+ // allowable PSK exchange key mode
+ if (!hc.handshakeSession.isPSKable()) {
+ return null;
+ }
}
// get a new session ID
SSLSessionContextImpl sessionCache = (SSLSessionContextImpl)
- shc.sslContext.engineGetServerSessionContext();
+ hc.sslContext.engineGetServerSessionContext();
SessionId newId = new SessionId(true,
- shc.sslContext.getSecureRandom());
+ hc.sslContext.getSecureRandom());
SecretKey resumptionMasterSecret =
- shc.handshakeSession.getResumptionMasterSecret();
+ hc.handshakeSession.getResumptionMasterSecret();
if (resumptionMasterSecret == null) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
@@ -349,10 +363,10 @@
}
// construct the PSK and handshake message
- BigInteger nonce = shc.handshakeSession.incrTicketNonceCounter();
+ BigInteger nonce = hc.handshakeSession.incrTicketNonceCounter();
byte[] nonceArr = nonce.toByteArray();
SecretKey psk = derivePreSharedKey(
- shc.negotiatedCipherSuite.hashAlg,
+ hc.negotiatedCipherSuite.hashAlg,
resumptionMasterSecret, nonceArr);
int sessionTimeoutSeconds = sessionCache.getSessionTimeout();
@@ -364,31 +378,35 @@
return null;
}
- NewSessionTicketMessage nstm;
+ NewSessionTicketMessage nstm = null;
SSLSessionImpl sessionCopy =
- new SSLSessionImpl(shc.handshakeSession, newId);
+ new SSLSessionImpl(hc.handshakeSession, newId);
sessionCopy.setPreSharedKey(psk);
sessionCopy.setPskIdentity(newId.getId());
- if (shc.statelessResumption) {
- try {
- nstm = new T13NewSessionTicketMessage(shc,
- sessionTimeoutSeconds, shc.sslContext.getSecureRandom(),
- nonceArr, new SessionTicketSpec().encrypt(shc, sessionCopy));
+ // If a stateless ticket is allowed, attempt to make one
+ if (hc.handshakeSession.isStatelessable(hc)) {
+ nstm = new T13NewSessionTicketMessage(hc,
+ sessionTimeoutSeconds,
+ hc.sslContext.getSecureRandom(),
+ nonceArr,
+ new SessionTicketSpec().encrypt(hc, sessionCopy));
+ // If ticket construction failed, switch to session cache
+ if (!nstm.isValid()) {
+ hc.statelessResumption = false;
+ } else {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"Produced NewSessionTicket stateless " +
"handshake message", nstm);
}
- } catch (Exception e) {
- // Error with NST ticket, abort NST
- shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, e);
- return null;
}
- } else {
- nstm = new T13NewSessionTicketMessage(shc, sessionTimeoutSeconds,
- shc.sslContext.getSecureRandom(), nonceArr,
+ }
+ // If a session cache ticket is being used, make one
+ if (!hc.handshakeSession.isStatelessable(hc)) {
+ nstm = new T13NewSessionTicketMessage(hc, sessionTimeoutSeconds,
+ hc.sslContext.getSecureRandom(), nonceArr,
newId.getId());
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
@@ -399,13 +417,21 @@
// create and cache the new session
// The new session must be a child of the existing session so
// they will be invalidated together, etc.
- shc.handshakeSession.addChild(sessionCopy);
+ hc.handshakeSession.addChild(sessionCopy);
sessionCopy.setTicketAgeAdd(nstm.getTicketAgeAdd());
sessionCache.put(sessionCopy);
}
+
// Output the handshake message.
- nstm.write(shc.handshakeOutput);
- shc.handshakeOutput.flush();
+ if (nstm != null) {
+ // should never be null
+ nstm.write(hc.handshakeOutput);
+ hc.handshakeOutput.flush();
+ }
+
+ if (hc instanceof PostHandshakeContext) {
+ ((PostHandshakeContext) hc).finish();
+ }
// The message has been delivered.
return null;
@@ -448,23 +474,16 @@
return null;
}
- NewSessionTicketMessage nstm;
-
SSLSessionImpl sessionCopy =
new SSLSessionImpl(shc.handshakeSession, newId);
sessionCopy.setPskIdentity(newId.getId());
- try {
- nstm = new T12NewSessionTicketMessage(shc, sessionTimeoutSeconds,
- new SessionTicketSpec().encrypt(shc, sessionCopy));
- if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
- SSLLogger.fine(
- "Produced NewSessionTicket stateless handshake message", nstm);
- }
- } catch (Exception e) {
- // Abort on error with NST ticket
- shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, e);
- return null;
+ NewSessionTicketMessage nstm = new T12NewSessionTicketMessage(shc,
+ sessionTimeoutSeconds,
+ new SessionTicketSpec().encrypt(shc, sessionCopy));
+ if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+ SSLLogger.fine(
+ "Produced NewSessionTicket stateless handshake message", nstm);
}
// Output the handshake message.
@@ -505,6 +524,9 @@
"Consuming NewSessionTicket message", nstm);
}
+ SSLSessionContextImpl sessionCache = (SSLSessionContextImpl)
+ hc.sslContext.engineGetClientSessionContext();
+
// discard tickets with timeout 0
if (nstm.ticketLifetime <= 0 ||
nstm.ticketLifetime > MAX_TICKET_LIFETIME) {
@@ -513,12 +535,10 @@
"Discarding NewSessionTicket with lifetime "
+ nstm.ticketLifetime, nstm);
}
+ sessionCache.remove(hc.handshakeSession.getSessionId());
return;
}
- SSLSessionContextImpl sessionCache = (SSLSessionContextImpl)
- hc.sslContext.engineGetClientSessionContext();
-
if (sessionCache.getSessionTimeout() > MAX_TICKET_LIFETIME) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(