This commit is contained in:
Henry Jen 2020-04-14 23:11:49 +00:00
commit 0278846eaa
91 changed files with 1073 additions and 416 deletions

View file

@ -81,6 +81,12 @@ public final class JceKeyStore extends KeyStoreSpi {
private static final class SecretKeyEntry {
Date date; // the creation date of this entry
SealedObject sealedKey;
// Maximum possible length of sealedKey. Used to detect malicious
// input data. This field is set to the file length of the keystore
// at loading. It is useless when creating a new SecretKeyEntry
// to be store in a keystore.
int maxLength;
}
// Trusted certificate
@ -136,8 +142,8 @@ public final class JceKeyStore extends KeyStoreSpi {
}
key = keyProtector.recover(encrInfo);
} else {
key =
keyProtector.unseal(((SecretKeyEntry)entry).sealedKey);
SecretKeyEntry ske = ((SecretKeyEntry)entry);
key = keyProtector.unseal(ske.sealedKey, ske.maxLength);
}
return key;
@ -282,6 +288,7 @@ public final class JceKeyStore extends KeyStoreSpi {
// seal and store the key
entry.sealedKey = keyProtector.seal(key);
entry.maxLength = Integer.MAX_VALUE;
entries.put(alias.toLowerCase(Locale.ENGLISH), entry);
}
@ -691,6 +698,10 @@ public final class JceKeyStore extends KeyStoreSpi {
if (stream == null)
return;
byte[] allData = stream.readAllBytes();
int fullLength = allData.length;
stream = new ByteArrayInputStream(allData);
if (password != null) {
md = getPreKeyedHash(password);
dis = new DataInputStream(new DigestInputStream(stream, md));
@ -829,10 +840,11 @@ public final class JceKeyStore extends KeyStoreSpi {
AccessController.doPrivileged(
(PrivilegedAction<Void>)() -> {
ois2.setObjectInputFilter(
new DeserializationChecker());
new DeserializationChecker(fullLength));
return null;
});
entry.sealedKey = (SealedObject)ois.readObject();
entry.maxLength = fullLength;
// NOTE: don't close ois here since we are still
// using dis!!!
} catch (ClassNotFoundException cnfe) {
@ -926,8 +938,17 @@ public final class JceKeyStore extends KeyStoreSpi {
* deserialized.
*/
private static class DeserializationChecker implements ObjectInputFilter {
private static final int MAX_NESTED_DEPTH = 2;
// Full length of keystore, anything inside a SecretKeyEntry should not
// be bigger. Otherwise, must be illegal.
private final int fullLength;
public DeserializationChecker(int fullLength) {
this.fullLength = fullLength;
}
@Override
public ObjectInputFilter.Status
checkInput(ObjectInputFilter.FilterInfo info) {
@ -936,6 +957,7 @@ public final class JceKeyStore extends KeyStoreSpi {
long nestedDepth = info.depth();
if ((nestedDepth == 1 &&
info.serialClass() != SealedObjectForKeyProtector.class) ||
info.arrayLength() > fullLength ||
(nestedDepth > MAX_NESTED_DEPTH &&
info.serialClass() != null &&
info.serialClass() != Object.class)) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2019, 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
@ -352,8 +352,11 @@ final class KeyProtector {
/**
* Unseals the sealed key.
*
* @param maxLength Maximum possible length of so.
* If bigger, must be illegal.
*/
Key unseal(SealedObject so)
Key unseal(SealedObject so, int maxLength)
throws NoSuchAlgorithmException, UnrecoverableKeyException {
SecretKey sKey = null;
try {
@ -389,7 +392,7 @@ final class KeyProtector {
SunJCE.getInstance(),
"PBEWithMD5AndTripleDES");
cipher.init(Cipher.DECRYPT_MODE, sKey, params);
return soForKeyProtector.getKey(cipher);
return soForKeyProtector.getKey(cipher, maxLength);
} catch (NoSuchAlgorithmException ex) {
// Note: this catch needed to be here because of the
// later catch of GeneralSecurityException

View file

@ -73,7 +73,7 @@ final class SealedObjectForKeyProtector extends SealedObject {
return params;
}
final Key getKey(Cipher c)
final Key getKey(Cipher c, int maxLength)
throws IOException, ClassNotFoundException, IllegalBlockSizeException,
BadPaddingException {
@ -81,7 +81,7 @@ final class SealedObjectForKeyProtector extends SealedObject {
.getExtObjectInputStream(this, c)) {
AccessController.doPrivileged(
(PrivilegedAction<Void>) () -> {
ois.setObjectInputFilter(DeserializationChecker.ONE_FILTER);
ois.setObjectInputFilter(new DeserializationChecker(maxLength));
return null;
});
try {
@ -109,7 +109,7 @@ final class SealedObjectForKeyProtector extends SealedObject {
*/
private static class DeserializationChecker implements ObjectInputFilter {
private static final ObjectInputFilter ONE_FILTER;
private static final ObjectInputFilter OWN_FILTER;
static {
String prop = AccessController.doPrivileged(
@ -121,26 +121,32 @@ final class SealedObjectForKeyProtector extends SealedObject {
return Security.getProperty(KEY_SERIAL_FILTER);
}
});
ONE_FILTER = new DeserializationChecker(prop == null ? null
: ObjectInputFilter.Config.createFilter(prop));
OWN_FILTER = prop == null
? null
: ObjectInputFilter.Config.createFilter(prop);
}
private final ObjectInputFilter base;
// Maximum possible length of anything inside
private final int maxLength;
private DeserializationChecker(ObjectInputFilter base) {
this.base = base;
private DeserializationChecker(int maxLength) {
this.maxLength = maxLength;
}
@Override
public ObjectInputFilter.Status checkInput(
ObjectInputFilter.FilterInfo info) {
if (info.arrayLength() > maxLength) {
return Status.REJECTED;
}
if (info.serialClass() == Object.class) {
return Status.UNDECIDED;
}
if (base != null) {
Status result = base.checkInput(info);
if (OWN_FILTER != null) {
Status result = OWN_FILTER.checkInput(info);
if (result != Status.UNDECIDED) {
return result;
}

View file

@ -1858,6 +1858,8 @@ public class ObjectInputStream
break;
case TC_REFERENCE:
descriptor = (ObjectStreamClass) readHandle(unshared);
// Should only reference initialized class descriptors
descriptor.checkInitialized();
break;
case TC_PROXYCLASSDESC:
descriptor = readProxyDesc(unshared);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1996, 2020, 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
@ -885,6 +885,17 @@ public class ObjectStreamClass implements Serializable {
throw new InternalError("Unexpected call when not initialized");
}
/**
* Throws InvalidClassException if not initialized.
* To be called in cases where an uninitialized class descriptor indicates
* a problem in the serialization stream.
*/
final void checkInitialized() throws InvalidClassException {
if (!initialized) {
throw new InvalidClassException("Class descriptor should be initialized");
}
}
/**
* Throws an InvalidClassException if object instances referencing this
* class descriptor should not be allowed to deserialize. This method does
@ -1150,6 +1161,10 @@ public class ObjectStreamClass implements Serializable {
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
} catch (InstantiationError err) {
var ex = new InstantiationException();
ex.initCause(err);
throw ex;
}
} else {
throw new UnsupportedOperationException();

View file

@ -116,7 +116,8 @@ class MethodType
// The remaining fields are caches of various sorts:
private @Stable MethodTypeForm form; // erased form, plus cached data about primitives
private @Stable MethodType wrapAlt; // alternative wrapped/unwrapped version
private @Stable Object wrapAlt; // alternative wrapped/unwrapped version and
// private communication for readObject and readResolve
private @Stable Invokers invokers; // cache of handy higher-order adapters
private @Stable String methodDescriptor; // cache for toMethodDescriptorString
@ -711,7 +712,7 @@ class MethodType
private static MethodType wrapWithPrims(MethodType pt) {
assert(pt.hasPrimitives());
MethodType wt = pt.wrapAlt;
MethodType wt = (MethodType)pt.wrapAlt;
if (wt == null) {
// fill in lazily
wt = MethodTypeForm.canonicalize(pt, MethodTypeForm.WRAP, MethodTypeForm.WRAP);
@ -723,7 +724,7 @@ class MethodType
private static MethodType unwrapWithNoPrims(MethodType wt) {
assert(!wt.hasPrimitives());
MethodType uwt = wt.wrapAlt;
MethodType uwt = (MethodType)wt.wrapAlt;
if (uwt == null) {
// fill in lazily
uwt = MethodTypeForm.canonicalize(wt, MethodTypeForm.UNWRAP, MethodTypeForm.UNWRAP);
@ -1248,27 +1249,18 @@ s.writeObject(this.parameterArray());
*/
@java.io.Serial
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
// Assign temporary defaults in case this object escapes
MethodType_init(void.class, NO_PTYPES);
// Assign defaults in case this object escapes
UNSAFE.putReference(this, OffsetHolder.rtypeOffset, void.class);
UNSAFE.putReference(this, OffsetHolder.ptypesOffset, NO_PTYPES);
s.defaultReadObject(); // requires serialPersistentFields to be an empty array
Class<?> returnType = (Class<?>) s.readObject();
Class<?>[] parameterArray = (Class<?>[]) s.readObject();
parameterArray = parameterArray.clone(); // make sure it is unshared
// Assign deserialized values
MethodType_init(returnType, parameterArray);
}
// Initialization of state for deserialization only
private void MethodType_init(Class<?> rtype, Class<?>[] ptypes) {
// In order to communicate these values to readResolve, we must
// store them into the implementation-specific final fields.
checkRtype(rtype);
checkPtypes(ptypes);
UNSAFE.putReference(this, OffsetHolder.rtypeOffset, rtype);
UNSAFE.putReference(this, OffsetHolder.ptypesOffset, ptypes);
// Verify all operands, and make sure ptypes is unshared
// Cache the new MethodType for readResolve
wrapAlt = new MethodType[]{MethodType.methodType(returnType, parameterArray)};
}
// Support for resetting final fields while deserializing. Implement Holder
@ -1291,12 +1283,10 @@ s.writeObject(this.parameterArray());
// Do not use a trusted path for deserialization:
// return makeImpl(rtype, ptypes, true);
// Verify all operands, and make sure ptypes is unshared:
try {
return methodType(rtype, ptypes);
} finally {
// Re-assign defaults in case this object escapes
MethodType_init(void.class, NO_PTYPES);
}
// Return a new validated MethodType for the rtype and ptypes passed from readObject.
MethodType mt = ((MethodType[])wrapAlt)[0];
wrapAlt = null;
return mt;
}
/**

View file

@ -2178,8 +2178,8 @@ class MutableBigInteger {
}
/**
* Calculate the multiplicative inverse of this mod mod, where mod is odd.
* This and mod are not changed by the calculation.
* Calculate the multiplicative inverse of this modulo mod, where the mod
* argument is odd. This and mod are not changed by the calculation.
*
* This method implements an algorithm due to Richard Schroeppel, that uses
* the same intermediate representation as Montgomery Reduction
@ -2233,8 +2233,18 @@ class MutableBigInteger {
k += trailingZeros;
}
while (c.sign < 0)
c.signedAdd(p);
if (c.compare(p) >= 0) { // c has a larger magnitude than p
MutableBigInteger remainder = c.divide(p,
new MutableBigInteger());
// The previous line ignores the sign so we copy the data back
// into c which will restore the sign as needed (and converts
// it back to a SignedMutableBigInteger)
c.copyValue(remainder);
}
if (c.sign < 0) {
c.signedAdd(p);
}
return fixup(c, p, k);
}
@ -2272,8 +2282,8 @@ class MutableBigInteger {
}
// In theory, c may be greater than p at this point (Very rare!)
while (c.compare(p) >= 0)
c.subtract(p);
if (c.compare(p) >= 0)
c = c.divide(p, new MutableBigInteger());
return c;
}

View file

@ -37,12 +37,12 @@ import java.security.PermissionCollection;
import java.security.PrivilegedAction;
import java.security.Security;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Map;
import java.util.StringJoiner;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import sun.net.util.IPAddressUtil;
import sun.net.PortConfig;
import sun.security.util.RegisteredDomain;
@ -1349,16 +1349,13 @@ final class SocketPermissionCollection extends PermissionCollection
implements Serializable
{
// Not serialized; see serialization section at end of class
// A ConcurrentSkipListMap is used to preserve order, so that most
// recently added permissions are checked first (see JDK-4301064).
private transient ConcurrentSkipListMap<String, SocketPermission> perms;
private transient Map<String, SocketPermission> perms;
/**
* Create an empty SocketPermissions object.
*
* Create an empty SocketPermissionCollection object.
*/
public SocketPermissionCollection() {
perms = new ConcurrentSkipListMap<>(new SPCComparator());
perms = new ConcurrentHashMap<>();
}
/**
@ -1431,6 +1428,18 @@ final class SocketPermissionCollection extends PermissionCollection
int effective = 0;
int needed = desired;
var hit = perms.get(np.getName());
if (hit != null) {
// fastpath, if the host was explicitly listed
if (((needed & hit.getMask()) != 0) && hit.impliesIgnoreMask(np)) {
effective |= hit.getMask();
if ((effective & desired) == desired) {
return true;
}
needed = (desired & ~effective);
}
}
//System.out.println("implies "+np);
for (SocketPermission x : perms.values()) {
//System.out.println(" trying "+x);
@ -1512,22 +1521,9 @@ final class SocketPermissionCollection extends PermissionCollection
// Get the one we want
@SuppressWarnings("unchecked")
Vector<SocketPermission> permissions = (Vector<SocketPermission>)gfields.get("permissions", null);
perms = new ConcurrentSkipListMap<>(new SPCComparator());
perms = new ConcurrentHashMap<>(permissions.size());
for (SocketPermission sp : permissions) {
perms.put(sp.getName(), sp);
}
}
/**
* A simple comparator that orders new non-equal entries at the beginning.
*/
private static class SPCComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
if (s1.equals(s2)) {
return 0;
}
return -1;
}
}
}

View file

@ -80,7 +80,6 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
public $Type$Buffer slice() {
int pos = this.position();
int lim = this.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
long addr = byteOffset(pos);
return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr, segment);

View file

@ -213,7 +213,6 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer slice() {
int pos = this.position();
int lim = this.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
int off = (pos << $LG_BYTES_PER_VALUE$);
assert (off >= 0);

View file

@ -105,13 +105,15 @@ class Heap$Type$Buffer$RW$
}
public $Type$Buffer slice() {
int rem = this.remaining();
int pos = this.position();
int lim = this.limit();
int rem = (pos <= lim ? lim - pos : 0);
return new Heap$Type$Buffer$RW$(hb,
-1,
0,
rem,
rem,
this.position() + offset, segment);
pos + offset, segment);
}
@Override

View file

@ -43,12 +43,15 @@ class StringCharBuffer // package-private
}
public CharBuffer slice() {
int pos = this.position();
int lim = this.limit();
int rem = (pos <= lim ? lim - pos : 0);
return new StringCharBuffer(str,
-1,
0,
this.remaining(),
this.remaining(),
offset + this.position());
rem,
rem,
offset + pos);
}
@Override

View file

@ -428,7 +428,7 @@ public final class Scanner implements Iterator<String>, Closeable {
// here but what can we do? The final authority will be
// whatever parse method is invoked, so ultimately the
// Scanner will do the right thing
String digit = "((?i)["+radixDigits+"]|\\p{javaDigit})";
String digit = "((?i)["+radixDigits+"\\p{javaDigit}])";
String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
groupSeparator+digit+digit+digit+")+)";
// digit++ is the possessive form which is necessary for reducing
@ -478,7 +478,7 @@ public final class Scanner implements Iterator<String>, Closeable {
private Pattern decimalPattern;
private void buildFloatAndDecimalPattern() {
// \\p{javaDigit} may not be perfect, see above
String digit = "([0-9]|(\\p{javaDigit}))";
String digit = "(([0-9\\p{javaDigit}]))";
String exponent = "([eE][+-]?"+digit+"+)?";
String groupedNumeral = "("+non0Digit+digit+"?"+digit+"?("+
groupSeparator+digit+digit+digit+")+)";
@ -1289,25 +1289,25 @@ public final class Scanner implements Iterator<String>, Closeable {
// These must be literalized to avoid collision with regex
// metacharacters such as dot or parenthesis
groupSeparator = "\\" + dfs.getGroupingSeparator();
decimalSeparator = "\\" + dfs.getDecimalSeparator();
groupSeparator = "\\x{" + Integer.toHexString(dfs.getGroupingSeparator()) + "}";
decimalSeparator = "\\x{" + Integer.toHexString(dfs.getDecimalSeparator()) + "}";
// Quoting the nonzero length locale-specific things
// to avoid potential conflict with metacharacters
nanString = "\\Q" + dfs.getNaN() + "\\E";
infinityString = "\\Q" + dfs.getInfinity() + "\\E";
nanString = Pattern.quote(dfs.getNaN());
infinityString = Pattern.quote(dfs.getInfinity());
positivePrefix = df.getPositivePrefix();
if (!positivePrefix.isEmpty())
positivePrefix = "\\Q" + positivePrefix + "\\E";
positivePrefix = Pattern.quote(positivePrefix);
negativePrefix = df.getNegativePrefix();
if (!negativePrefix.isEmpty())
negativePrefix = "\\Q" + negativePrefix + "\\E";
negativePrefix = Pattern.quote(negativePrefix);
positiveSuffix = df.getPositiveSuffix();
if (!positiveSuffix.isEmpty())
positiveSuffix = "\\Q" + positiveSuffix + "\\E";
positiveSuffix = Pattern.quote(positiveSuffix);
negativeSuffix = df.getNegativeSuffix();
if (!negativeSuffix.isEmpty())
negativeSuffix = "\\Q" + negativeSuffix + "\\E";
negativeSuffix = Pattern.quote(negativeSuffix);
// Force rebuilding and recompilation of locale dependent
// primitive patterns

View file

@ -166,13 +166,23 @@ public class DatagramSocketAdaptor
@Override
public SocketAddress getLocalSocketAddress() {
try {
return dc.getLocalAddress();
} catch (ClosedChannelException e) {
InetSocketAddress local = dc.localAddress();
if (local == null || isClosed())
return null;
} catch (Exception x) {
throw new Error(x);
InetAddress addr = local.getAddress();
if (addr.isAnyLocalAddress())
return local;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
try {
sm.checkConnect(addr.getHostAddress(), -1);
} catch (SecurityException x) {
return new InetSocketAddress(local.getPort());
}
}
return local;
}
@Override

View file

@ -265,7 +265,7 @@ enum Alert {
// It's OK to get a no_certificate alert from a client of
// which we requested client authentication. However,
// if we required it, then this is not acceptable.
if (tc.sslConfig.isClientMode ||
if (tc.sslConfig.isClientMode ||
alert != Alert.NO_CERTIFICATE ||
(tc.sslConfig.clientAuthType !=
ClientAuthType.CLIENT_AUTH_REQUESTED)) {
@ -273,8 +273,10 @@ enum Alert {
"received handshake warning: " + alert.description);
} else {
// Otherwise ignore the warning but remove the
// CertificateVerify handshake consumer so the state
// machine doesn't expect it.
// Certificate and CertificateVerify handshake
// consumer so the state machine doesn't expect it.
tc.handshakeContext.handshakeConsumers.remove(
SSLHandshake.CERTIFICATE.id);
tc.handshakeContext.handshakeConsumers.remove(
SSLHandshake.CERTIFICATE_VERIFY.id);
}

View file

@ -406,7 +406,7 @@ final class ClientHello {
ProtocolVersion maxProtocolVersion = chc.maximumActiveProtocol;
// session ID of the ClientHello message
SessionId sessionId = SSLSessionImpl.nullSession.getSessionId();
SessionId sessionId = new SessionId(new byte[0]);
// a list of cipher suites sent by the client
List<CipherSuite> cipherSuites = chc.activeCipherSuites;

View file

@ -90,6 +90,16 @@ final class ClientKeyExchange {
ServerHandshakeContext shc = (ServerHandshakeContext)context;
// clean up this consumer
shc.handshakeConsumers.remove(SSLHandshake.CLIENT_KEY_EXCHANGE.id);
// Check for an unprocessed client Certificate message. If that
// handshake consumer is still present then that expected message
// was not sent.
if (shc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE.id)) {
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected ClientKeyExchange handshake message.");
}
SSLKeyExchange ke = SSLKeyExchange.valueOf(
shc.negotiatedCipherSuite.keyExchange,
shc.negotiatedProtocol);

View file

@ -897,6 +897,8 @@ final class Finished {
// has been received and processed.
if (!chc.isResumption) {
if (chc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE.id) ||
chc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE_VERIFY.id)) {
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected Finished handshake message");
@ -1029,6 +1031,8 @@ final class Finished {
// has been received and processed.
if (!shc.isResumption) {
if (shc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE.id) ||
shc.handshakeConsumers.containsKey(
SSLHandshake.CERTIFICATE_VERIFY.id)) {
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected Finished handshake message");

View file

@ -164,8 +164,10 @@ abstract class HandshakeContext implements ConnectionContext {
this.conContext = conContext;
this.sslConfig = (SSLConfiguration)conContext.sslConfig.clone();
this.algorithmConstraints = new SSLAlgorithmConstraints(
sslConfig.userSpecifiedAlgorithmConstraints);
this.activeProtocols = getActiveProtocols(sslConfig.enabledProtocols,
sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints);
sslConfig.enabledCipherSuites, algorithmConstraints);
if (activeProtocols.isEmpty()) {
throw new SSLHandshakeException(
"No appropriate protocol (protocol is disabled or " +
@ -181,12 +183,10 @@ abstract class HandshakeContext implements ConnectionContext {
}
this.maximumActiveProtocol = maximumVersion;
this.activeCipherSuites = getActiveCipherSuites(this.activeProtocols,
sslConfig.enabledCipherSuites, sslConfig.algorithmConstraints);
sslConfig.enabledCipherSuites, algorithmConstraints);
if (activeCipherSuites.isEmpty()) {
throw new SSLHandshakeException("No appropriate cipher suite");
}
this.algorithmConstraints =
new SSLAlgorithmConstraints(sslConfig.algorithmConstraints);
this.handshakeConsumers = new LinkedHashMap<>();
this.handshakeProducers = new HashMap<>();
@ -209,7 +209,7 @@ abstract class HandshakeContext implements ConnectionContext {
/**
* Constructor for PostHandshakeContext
*/
HandshakeContext(TransportContext conContext) {
protected HandshakeContext(TransportContext conContext) {
this.sslContext = conContext.sslContext;
this.conContext = conContext;
this.sslConfig = conContext.sslConfig;
@ -219,6 +219,7 @@ abstract class HandshakeContext implements ConnectionContext {
this.handshakeOutput = new HandshakeOutStream(conContext.outputRecord);
this.delegatedActions = new LinkedList<>();
this.handshakeConsumers = new LinkedHashMap<>();
this.handshakeProducers = null;
this.handshakeHash = null;
this.activeProtocols = null;

View file

@ -336,7 +336,7 @@ final class KeyShareExtension {
for (KeyShareEntry entry : spec.clientShares) {
NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId);
if (ng == null || !SupportedGroups.isActivatable(
shc.sslConfig.algorithmConstraints, ng)) {
shc.algorithmConstraints, ng)) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"Ignore unsupported named group: " +
@ -620,7 +620,7 @@ final class KeyShareExtension {
KeyShareEntry keyShare = spec.serverShare;
NamedGroup ng = NamedGroup.valueOf(keyShare.namedGroupId);
if (ng == null || !SupportedGroups.isActivatable(
chc.sslConfig.algorithmConstraints, ng)) {
chc.algorithmConstraints, ng)) {
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
"Unsupported named group: " +
NamedGroup.nameOf(keyShare.namedGroupId));
@ -762,7 +762,7 @@ final class KeyShareExtension {
NamedGroup selectedGroup = null;
for (NamedGroup ng : shc.clientRequestedNamedGroups) {
if (SupportedGroups.isActivatable(
shc.sslConfig.algorithmConstraints, ng)) {
shc.algorithmConstraints, ng)) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"HelloRetryRequest selected named group: " +

View file

@ -30,17 +30,11 @@ import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* A compact implementation of HandshakeContext for post-handshake messages
*/
final class PostHandshakeContext extends HandshakeContext {
private final static Map<Byte, SSLConsumer> consumers = Map.of(
SSLHandshake.KEY_UPDATE.id, SSLHandshake.KEY_UPDATE,
SSLHandshake.NEW_SESSION_TICKET.id, SSLHandshake.NEW_SESSION_TICKET);
PostHandshakeContext(TransportContext context) throws IOException {
super(context);
@ -49,10 +43,23 @@ final class PostHandshakeContext extends HandshakeContext {
"Post-handshake not supported in " + negotiatedProtocol.name);
}
this.localSupportedSignAlgs = new ArrayList<SignatureScheme>(
this.localSupportedSignAlgs = new ArrayList<>(
context.conSession.getLocalSupportedSignatureSchemes());
handshakeConsumers = new LinkedHashMap<>(consumers);
// Add the potential post-handshake consumers.
if (context.sslConfig.isClientMode) {
handshakeConsumers.putIfAbsent(
SSLHandshake.KEY_UPDATE.id,
SSLHandshake.KEY_UPDATE);
handshakeConsumers.putIfAbsent(
SSLHandshake.NEW_SESSION_TICKET.id,
SSLHandshake.NEW_SESSION_TICKET);
} else {
handshakeConsumers.putIfAbsent(
SSLHandshake.KEY_UPDATE.id,
SSLHandshake.KEY_UPDATE);
}
handshakeFinished = true;
handshakeSession = context.conSession;
}
@ -83,4 +90,21 @@ final class PostHandshakeContext extends HandshakeContext {
SSLHandshake.nameOf(handshakeType), be);
}
}
static boolean isConsumable(TransportContext context, byte handshakeType) {
if (handshakeType == SSLHandshake.KEY_UPDATE.id) {
// The KeyUpdate handshake message does not apply to TLS 1.2 and
// previous protocols.
return context.protocolVersion.useTLS13PlusSpec();
}
if (handshakeType == SSLHandshake.NEW_SESSION_TICKET.id) {
// The new session ticket handshake message could be consumer in
// client side only.
return context.sslConfig.isClientMode;
}
// No more post-handshake message supported currently.
return false;
}
}

View file

@ -71,21 +71,21 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
SSLAlgorithmConstraints(SSLSocket socket,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(socket);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(socket);
this.peerSpecifiedConstraints = null;
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
}
SSLAlgorithmConstraints(SSLEngine engine,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(engine);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(engine);
this.peerSpecifiedConstraints = null;
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
}
SSLAlgorithmConstraints(SSLSocket socket, String[] supportedAlgorithms,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(socket);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(socket);
this.peerSpecifiedConstraints =
new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
@ -93,13 +93,14 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
SSLAlgorithmConstraints(SSLEngine engine, String[] supportedAlgorithms,
boolean withDefaultCertPathConstraints) {
this.userSpecifiedConstraints = getConstraints(engine);
this.userSpecifiedConstraints = getUserSpecifiedConstraints(engine);
this.peerSpecifiedConstraints =
new SupportedSignatureAlgorithmConstraints(supportedAlgorithms);
this.enabledX509DisabledAlgConstraints = withDefaultCertPathConstraints;
}
private static AlgorithmConstraints getConstraints(SSLEngine engine) {
private static AlgorithmConstraints getUserSpecifiedConstraints(
SSLEngine engine) {
if (engine != null) {
// Note that the KeyManager or TrustManager implementation may be
// not implemented in the same provider as SSLSocket/SSLEngine.
@ -108,17 +109,18 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
HandshakeContext hc =
((SSLEngineImpl)engine).conContext.handshakeContext;
if (hc != null) {
return hc.sslConfig.algorithmConstraints;
return hc.sslConfig.userSpecifiedAlgorithmConstraints;
}
} else {
return engine.getSSLParameters().getAlgorithmConstraints();
}
return engine.getSSLParameters().getAlgorithmConstraints();
}
return null;
}
private static AlgorithmConstraints getConstraints(SSLSocket socket) {
private static AlgorithmConstraints getUserSpecifiedConstraints(
SSLSocket socket) {
if (socket != null) {
// Note that the KeyManager or TrustManager implementation may be
// not implemented in the same provider as SSLSocket/SSLEngine.
@ -127,11 +129,11 @@ final class SSLAlgorithmConstraints implements AlgorithmConstraints {
HandshakeContext hc =
((SSLSocketImpl)socket).conContext.handshakeContext;
if (hc != null) {
return hc.sslConfig.algorithmConstraints;
return hc.sslConfig.userSpecifiedAlgorithmConstraints;
}
} else {
return socket.getSSLParameters().getAlgorithmConstraints();
}
return socket.getSSLParameters().getAlgorithmConstraints();
}
return null;

View file

@ -51,7 +51,7 @@ import sun.security.ssl.SSLExtension.ServerExtensions;
*/
final class SSLConfiguration implements Cloneable {
// configurations with SSLParameters
AlgorithmConstraints algorithmConstraints;
AlgorithmConstraints userSpecifiedAlgorithmConstraints;
List<ProtocolVersion> enabledProtocols;
List<CipherSuite> enabledCipherSuites;
ClientAuthType clientAuthType;
@ -116,7 +116,8 @@ final class SSLConfiguration implements Cloneable {
SSLConfiguration(SSLContextImpl sslContext, boolean isClientMode) {
// Configurations with SSLParameters, default values.
this.algorithmConstraints = SSLAlgorithmConstraints.DEFAULT;
this.userSpecifiedAlgorithmConstraints =
SSLAlgorithmConstraints.DEFAULT;
this.enabledProtocols =
sslContext.getDefaultProtocolVersions(!isClientMode);
this.enabledCipherSuites =
@ -153,7 +154,7 @@ final class SSLConfiguration implements Cloneable {
SSLParameters getSSLParameters() {
SSLParameters params = new SSLParameters();
params.setAlgorithmConstraints(this.algorithmConstraints);
params.setAlgorithmConstraints(this.userSpecifiedAlgorithmConstraints);
params.setProtocols(ProtocolVersion.toStringArray(enabledProtocols));
params.setCipherSuites(CipherSuite.namesOf(enabledCipherSuites));
switch (this.clientAuthType) {
@ -193,7 +194,7 @@ final class SSLConfiguration implements Cloneable {
void setSSLParameters(SSLParameters params) {
AlgorithmConstraints ac = params.getAlgorithmConstraints();
if (ac != null) {
this.algorithmConstraints = ac;
this.userSpecifiedAlgorithmConstraints = ac;
} // otherwise, use the default value
String[] sa = params.getCipherSuites();

View file

@ -77,11 +77,6 @@ import javax.net.ssl.SSLSessionContext;
*/
final class SSLSessionImpl extends ExtendedSSLSession {
/*
* we only really need a single null session
*/
static final SSLSessionImpl nullSession = new SSLSessionImpl();
/*
* The state of a single session, as described in section 7.1
* of the SSLv3 spec.
@ -153,7 +148,7 @@ final class SSLSessionImpl extends ExtendedSSLSession {
* be used either by a client or by a server, as a connection is
* first opened and before handshaking begins.
*/
private SSLSessionImpl() {
SSLSessionImpl() {
this.protocolVersion = ProtocolVersion.NONE;
this.cipherSuite = CipherSuite.C_NULL;
this.sessionId = new SessionId(false, null);
@ -1222,15 +1217,6 @@ final class SSLSessionImpl extends ExtendedSSLSession {
public void invalidate() {
sessionLock.lock();
try {
//
// Can't invalidate the NULL session -- this would be
// attempted when we get a handshaking error on a brand
// new connection, with no "real" session yet.
//
if (this == nullSession) {
return;
}
if (context != null) {
context.remove(sessionId);
context = null;

View file

@ -360,7 +360,7 @@ public final class SSLSocketImpl
SSLLogger.severe("handshake failed", ioe);
}
return SSLSessionImpl.nullSession;
return new SSLSessionImpl();
}
return conContext.conSession;

View file

@ -173,12 +173,24 @@ interface SSLTransport {
if (plainText == null) {
plainText = Plaintext.PLAINTEXT_NULL;
} else {
// Fill the destination buffers.
if ((dsts != null) && (dstsLength > 0) &&
(plainText.contentType ==
ContentType.APPLICATION_DATA.id)) {
} else if (plainText.contentType ==
ContentType.APPLICATION_DATA.id) {
// check handshake status
//
// Note that JDK does not support 0-RTT yet. Otherwise, it is
// needed to check early_data.
if (!context.isNegotiated) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,verbose")) {
SSLLogger.warning("unexpected application data " +
"before handshake completion");
}
throw context.fatal(Alert.UNEXPECTED_MESSAGE,
"Receiving application data before handshake complete");
}
// Fill the destination buffers.
if ((dsts != null) && (dstsLength > 0)) {
ByteBuffer fragment = plainText.fragment;
int remains = fragment.remaining();

View file

@ -130,7 +130,7 @@ final class TransportContext implements ConnectionContext {
this.isUnsureMode = isUnsureMode;
// initial security parameters
this.conSession = SSLSessionImpl.nullSession;
this.conSession = new SSLSessionImpl();
this.protocolVersion = this.sslConfig.maximumProtocolVersion;
this.clientVerifyData = emptyByteArray;
this.serverVerifyData = emptyByteArray;
@ -164,12 +164,13 @@ final class TransportContext implements ConnectionContext {
" message: " +
SSLHandshake.nameOf(type));
}
if (type == SSLHandshake.KEY_UPDATE.id &&
!protocolVersion.useTLS13PlusSpec()) {
if (!PostHandshakeContext.isConsumable(this, type)) {
throw fatal(Alert.UNEXPECTED_MESSAGE,
"Unexpected post-handshake message: " +
SSLHandshake.nameOf(type));
}
handshakeContext = new PostHandshakeContext(this);
} else {
handshakeContext = sslConfig.isClientMode ?