8221882: Use fiber-friendly java.util.concurrent.locks in JSSE
Reviewed-by: alanb, dfuchs
This commit is contained in:
parent
6d617481d4
commit
8263b618ba
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -26,8 +26,9 @@
|
|||||||
package javax.net.ssl;
|
package javax.net.ssl;
|
||||||
|
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.VarHandle;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import sun.security.jca.GetInstance;
|
import sun.security.jca.GetInstance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,6 +59,20 @@ public class SSLContext {
|
|||||||
|
|
||||||
private final String protocol;
|
private final String protocol;
|
||||||
|
|
||||||
|
private static volatile SSLContext defaultContext;
|
||||||
|
|
||||||
|
private static final VarHandle VH_DEFAULT_CONTEXT;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
VH_DEFAULT_CONTEXT = MethodHandles.lookup()
|
||||||
|
.findStaticVarHandle(
|
||||||
|
SSLContext.class, "defaultContext", SSLContext.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ExceptionInInitializerError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an SSLContext object.
|
* Creates an SSLContext object.
|
||||||
*
|
*
|
||||||
@ -72,8 +87,6 @@ public class SSLContext {
|
|||||||
this.protocol = protocol;
|
this.protocol = protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SSLContext defaultContext;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the default SSL context.
|
* Returns the default SSL context.
|
||||||
*
|
*
|
||||||
@ -91,12 +104,16 @@ public class SSLContext {
|
|||||||
* {@link SSLContext#getInstance SSLContext.getInstance()} call fails
|
* {@link SSLContext#getInstance SSLContext.getInstance()} call fails
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public static synchronized SSLContext getDefault()
|
public static SSLContext getDefault() throws NoSuchAlgorithmException {
|
||||||
throws NoSuchAlgorithmException {
|
SSLContext temporaryContext = defaultContext;
|
||||||
if (defaultContext == null) {
|
if (temporaryContext == null) {
|
||||||
defaultContext = SSLContext.getInstance("Default");
|
temporaryContext = SSLContext.getInstance("Default");
|
||||||
|
if (!VH_DEFAULT_CONTEXT.compareAndSet(null, temporaryContext)) {
|
||||||
|
temporaryContext = defaultContext;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return defaultContext;
|
|
||||||
|
return temporaryContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,7 +128,7 @@ public class SSLContext {
|
|||||||
* {@code SSLPermission("setDefaultSSLContext")}
|
* {@code SSLPermission("setDefaultSSLContext")}
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public static synchronized void setDefault(SSLContext context) {
|
public static void setDefault(SSLContext context) {
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
throw new NullPointerException();
|
throw new NullPointerException();
|
||||||
}
|
}
|
||||||
@ -119,6 +136,7 @@ public class SSLContext {
|
|||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
sm.checkPermission(new SSLPermission("setDefaultSSLContext"));
|
sm.checkPermission(new SSLPermission("setDefaultSSLContext"));
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultContext = context;
|
defaultContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -42,17 +42,7 @@ import java.security.*;
|
|||||||
* @see SSLServerSocket
|
* @see SSLServerSocket
|
||||||
* @author David Brownell
|
* @author David Brownell
|
||||||
*/
|
*/
|
||||||
public abstract class SSLServerSocketFactory extends ServerSocketFactory
|
public abstract class SSLServerSocketFactory extends ServerSocketFactory {
|
||||||
{
|
|
||||||
private static SSLServerSocketFactory theFactory;
|
|
||||||
|
|
||||||
private static boolean propertyChecked;
|
|
||||||
|
|
||||||
private static void log(String msg) {
|
|
||||||
if (SSLSocketFactory.DEBUG) {
|
|
||||||
System.out.println(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor is used only by subclasses.
|
* Constructor is used only by subclasses.
|
||||||
@ -75,39 +65,9 @@ public abstract class SSLServerSocketFactory extends ServerSocketFactory
|
|||||||
* @return the default <code>ServerSocketFactory</code>
|
* @return the default <code>ServerSocketFactory</code>
|
||||||
* @see SSLContext#getDefault
|
* @see SSLContext#getDefault
|
||||||
*/
|
*/
|
||||||
public static synchronized ServerSocketFactory getDefault() {
|
public static ServerSocketFactory getDefault() {
|
||||||
if (theFactory != null) {
|
if (DefaultFactoryHolder.defaultFactory != null) {
|
||||||
return theFactory;
|
return DefaultFactoryHolder.defaultFactory;
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyChecked == false) {
|
|
||||||
propertyChecked = true;
|
|
||||||
String clsName = SSLSocketFactory.getSecurityProperty
|
|
||||||
("ssl.ServerSocketFactory.provider");
|
|
||||||
if (clsName != null) {
|
|
||||||
log("setting up default SSLServerSocketFactory");
|
|
||||||
try {
|
|
||||||
Class<?> cls = null;
|
|
||||||
try {
|
|
||||||
cls = Class.forName(clsName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
|
||||||
if (cl != null) {
|
|
||||||
cls = cl.loadClass(clsName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log("class " + clsName + " is loaded");
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
SSLServerSocketFactory fac = (SSLServerSocketFactory)cls.newInstance();
|
|
||||||
log("instantiated an instance of class " + clsName);
|
|
||||||
theFactory = fac;
|
|
||||||
return fac;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log("SSLServerSocketFactory instantiation failed: " + e);
|
|
||||||
theFactory = new DefaultSSLServerSocketFactory(e);
|
|
||||||
return theFactory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -156,8 +116,50 @@ public abstract class SSLServerSocketFactory extends ServerSocketFactory
|
|||||||
* @see #getDefaultCipherSuites()
|
* @see #getDefaultCipherSuites()
|
||||||
*/
|
*/
|
||||||
public abstract String [] getSupportedCipherSuites();
|
public abstract String [] getSupportedCipherSuites();
|
||||||
}
|
|
||||||
|
|
||||||
|
// lazy initialization holder class idiom for static default factory
|
||||||
|
//
|
||||||
|
// See Effective Java Second Edition: Item 71.
|
||||||
|
private static final class DefaultFactoryHolder {
|
||||||
|
private static final SSLServerSocketFactory defaultFactory;
|
||||||
|
|
||||||
|
static {
|
||||||
|
SSLServerSocketFactory mediator = null;
|
||||||
|
String clsName = SSLSocketFactory.getSecurityProperty(
|
||||||
|
"ssl.ServerSocketFactory.provider");
|
||||||
|
if (clsName != null) {
|
||||||
|
log("setting up default SSLServerSocketFactory");
|
||||||
|
try {
|
||||||
|
Class<?> cls = null;
|
||||||
|
try {
|
||||||
|
cls = Class.forName(clsName);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||||
|
if (cl != null) {
|
||||||
|
cls = cl.loadClass(clsName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log("class " + clsName + " is loaded");
|
||||||
|
|
||||||
|
mediator = (SSLServerSocketFactory)cls
|
||||||
|
.getDeclaredConstructor().newInstance();
|
||||||
|
log("instantiated an instance of class " + clsName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log("SSLServerSocketFactory instantiation failed: " + e);
|
||||||
|
mediator = new DefaultSSLServerSocketFactory(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultFactory = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void log(String msg) {
|
||||||
|
if (SSLSocketFactory.DEBUG) {
|
||||||
|
System.out.println(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// The default factory does NOTHING.
|
// The default factory does NOTHING.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -42,31 +42,20 @@ import sun.security.action.GetPropertyAction;
|
|||||||
* @see SSLSocket
|
* @see SSLSocket
|
||||||
* @author David Brownell
|
* @author David Brownell
|
||||||
*/
|
*/
|
||||||
public abstract class SSLSocketFactory extends SocketFactory
|
public abstract class SSLSocketFactory extends SocketFactory {
|
||||||
{
|
|
||||||
private static SSLSocketFactory theFactory;
|
|
||||||
|
|
||||||
private static boolean propertyChecked;
|
|
||||||
|
|
||||||
static final boolean DEBUG;
|
static final boolean DEBUG;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
String s = GetPropertyAction.privilegedGetProperty("javax.net.debug", "")
|
String s = GetPropertyAction.privilegedGetProperty(
|
||||||
.toLowerCase(Locale.ENGLISH);
|
"javax.net.debug", "").toLowerCase(Locale.ENGLISH);
|
||||||
|
|
||||||
DEBUG = s.contains("all") || s.contains("ssl");
|
DEBUG = s.contains("all") || s.contains("ssl");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void log(String msg) {
|
|
||||||
if (DEBUG) {
|
|
||||||
System.out.println(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor is used only by subclasses.
|
* Constructor is used only by subclasses.
|
||||||
*/
|
*/
|
||||||
public SSLSocketFactory() {
|
public SSLSocketFactory() {
|
||||||
|
// blank
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,38 +74,9 @@ public abstract class SSLSocketFactory extends SocketFactory
|
|||||||
* @return the default <code>SocketFactory</code>
|
* @return the default <code>SocketFactory</code>
|
||||||
* @see SSLContext#getDefault
|
* @see SSLContext#getDefault
|
||||||
*/
|
*/
|
||||||
public static synchronized SocketFactory getDefault() {
|
public static SocketFactory getDefault() {
|
||||||
if (theFactory != null) {
|
if (DefaultFactoryHolder.defaultFactory != null) {
|
||||||
return theFactory;
|
return DefaultFactoryHolder.defaultFactory;
|
||||||
}
|
|
||||||
|
|
||||||
if (propertyChecked == false) {
|
|
||||||
propertyChecked = true;
|
|
||||||
String clsName = getSecurityProperty("ssl.SocketFactory.provider");
|
|
||||||
if (clsName != null) {
|
|
||||||
log("setting up default SSLSocketFactory");
|
|
||||||
try {
|
|
||||||
Class<?> cls = null;
|
|
||||||
try {
|
|
||||||
cls = Class.forName(clsName);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
|
||||||
if (cl != null) {
|
|
||||||
cls = cl.loadClass(clsName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log("class " + clsName + " is loaded");
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance();
|
|
||||||
log("instantiated an instance of class " + clsName);
|
|
||||||
theFactory = fac;
|
|
||||||
return fac;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log("SSLSocketFactory instantiation failed: " + e.toString());
|
|
||||||
theFactory = new DefaultSSLSocketFactory(e);
|
|
||||||
return theFactory;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -246,6 +206,49 @@ public abstract class SSLSocketFactory extends SocketFactory
|
|||||||
boolean autoClose) throws IOException {
|
boolean autoClose) throws IOException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lazy initialization holder class idiom for static default factory
|
||||||
|
//
|
||||||
|
// See Effective Java Second Edition: Item 71.
|
||||||
|
private static final class DefaultFactoryHolder {
|
||||||
|
private static final SSLSocketFactory defaultFactory;
|
||||||
|
|
||||||
|
static {
|
||||||
|
SSLSocketFactory mediator = null;
|
||||||
|
String clsName = getSecurityProperty("ssl.SocketFactory.provider");
|
||||||
|
if (clsName != null) {
|
||||||
|
log("setting up default SSLSocketFactory");
|
||||||
|
try {
|
||||||
|
Class<?> cls = null;
|
||||||
|
try {
|
||||||
|
cls = Class.forName(clsName);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
ClassLoader cl = ClassLoader.getSystemClassLoader();
|
||||||
|
if (cl != null) {
|
||||||
|
cls = cl.loadClass(clsName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log("class " + clsName + " is loaded");
|
||||||
|
|
||||||
|
mediator = (SSLSocketFactory)cls
|
||||||
|
.getDeclaredConstructor().newInstance();
|
||||||
|
|
||||||
|
log("instantiated an instance of class " + clsName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log("SSLSocketFactory instantiation failed: " + e);
|
||||||
|
mediator = new DefaultSSLSocketFactory(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultFactory = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void log(String msg) {
|
||||||
|
if (DEBUG) {
|
||||||
|
System.out.println(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -57,8 +57,7 @@ import sun.net.www.http.HttpClient;
|
|||||||
public class HttpsURLConnectionImpl
|
public class HttpsURLConnectionImpl
|
||||||
extends javax.net.ssl.HttpsURLConnection {
|
extends javax.net.ssl.HttpsURLConnection {
|
||||||
|
|
||||||
// NOTE: made protected for plugin so that subclass can set it.
|
private final DelegateHttpsURLConnection delegate;
|
||||||
protected DelegateHttpsURLConnection delegate;
|
|
||||||
|
|
||||||
HttpsURLConnectionImpl(URL u, Handler handler) throws IOException {
|
HttpsURLConnectionImpl(URL u, Handler handler) throws IOException {
|
||||||
this(u, null, handler);
|
this(u, null, handler);
|
||||||
@ -78,13 +77,6 @@ public class HttpsURLConnectionImpl
|
|||||||
delegate = new DelegateHttpsURLConnection(url, p, handler, this);
|
delegate = new DelegateHttpsURLConnection(url, p, handler, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: introduced for plugin
|
|
||||||
// subclass needs to overwrite this to set delegate to
|
|
||||||
// the appropriate delegatee
|
|
||||||
protected HttpsURLConnectionImpl(URL u) throws IOException {
|
|
||||||
super(u);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new HttpClient object, bypassing the cache of
|
* Create a new HttpClient object, bypassing the cache of
|
||||||
* HTTP client objects/connections.
|
* HTTP client objects/connections.
|
||||||
@ -219,11 +211,11 @@ public class HttpsURLConnectionImpl
|
|||||||
* - get input, [read input,] get output, [write output]
|
* - get input, [read input,] get output, [write output]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public synchronized OutputStream getOutputStream() throws IOException {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
return delegate.getOutputStream();
|
return delegate.getOutputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized InputStream getInputStream() throws IOException {
|
public InputStream getInputStream() throws IOException {
|
||||||
return delegate.getInputStream();
|
return delegate.getInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -632,7 +632,7 @@ abstract class BaseSSLSocketImpl extends SSLSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setSoTimeout(int timeout) throws SocketException {
|
public void setSoTimeout(int timeout) throws SocketException {
|
||||||
if (self == this) {
|
if (self == this) {
|
||||||
super.setSoTimeout(timeout);
|
super.setSoTimeout(timeout);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -58,7 +58,7 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (!isClosed) {
|
if (!isClosed) {
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -58,13 +58,18 @@ final class DTLSOutputRecord extends OutputRecord implements DTLSRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (!isClosed) {
|
recordLock.lock();
|
||||||
if (fragmenter != null && fragmenter.hasAlert()) {
|
try {
|
||||||
isCloseWaiting = true;
|
if (!isClosed) {
|
||||||
} else {
|
if (fragmenter != null && fragmenter.hasAlert()) {
|
||||||
super.close();
|
isCloseWaiting = true;
|
||||||
|
} else {
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
package sun.security.ssl;
|
package sun.security.ssl;
|
||||||
|
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The "KeyManager" for ephemeral RSA keys. Ephemeral DH and ECDH keys
|
* The "KeyManager" for ephemeral RSA keys. Ephemeral DH and ECDH keys
|
||||||
@ -48,6 +49,8 @@ final class EphemeralKeyManager {
|
|||||||
new EphemeralKeyPair(null),
|
new EphemeralKeyPair(null),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final ReentrantLock cachedKeysLock = new ReentrantLock();
|
||||||
|
|
||||||
EphemeralKeyManager() {
|
EphemeralKeyManager() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
@ -65,20 +68,32 @@ final class EphemeralKeyManager {
|
|||||||
index = INDEX_RSA1024;
|
index = INDEX_RSA1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (keys) {
|
KeyPair kp = keys[index].getKeyPair();
|
||||||
KeyPair kp = keys[index].getKeyPair();
|
if (kp != null) {
|
||||||
if (kp == null) {
|
|
||||||
try {
|
|
||||||
KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA");
|
|
||||||
kgen.initialize(length, random);
|
|
||||||
keys[index] = new EphemeralKeyPair(kgen.genKeyPair());
|
|
||||||
kp = keys[index].getKeyPair();
|
|
||||||
} catch (Exception e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return kp;
|
return kp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cachedKeysLock.lock();
|
||||||
|
try {
|
||||||
|
// double check
|
||||||
|
kp = keys[index].getKeyPair();
|
||||||
|
if (kp != null) {
|
||||||
|
return kp;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA");
|
||||||
|
kgen.initialize(length, random);
|
||||||
|
keys[index] = new EphemeralKeyPair(kgen.genKeyPair());
|
||||||
|
kp = keys[index].getKeyPair();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cachedKeysLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return kp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,6 +30,7 @@ import java.security.MessageDigest;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import static sun.security.ssl.ClientHello.ClientHelloMessage;
|
import static sun.security.ssl.ClientHello.ClientHelloMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,6 +46,8 @@ abstract class HelloCookieManager {
|
|||||||
private volatile D13HelloCookieManager d13HelloCookieManager;
|
private volatile D13HelloCookieManager d13HelloCookieManager;
|
||||||
private volatile T13HelloCookieManager t13HelloCookieManager;
|
private volatile T13HelloCookieManager t13HelloCookieManager;
|
||||||
|
|
||||||
|
private final ReentrantLock managerLock = new ReentrantLock();
|
||||||
|
|
||||||
Builder(SecureRandom secureRandom) {
|
Builder(SecureRandom secureRandom) {
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
}
|
}
|
||||||
@ -56,11 +59,14 @@ abstract class HelloCookieManager {
|
|||||||
return d13HelloCookieManager;
|
return d13HelloCookieManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
managerLock.lock();
|
||||||
|
try {
|
||||||
if (d13HelloCookieManager == null) {
|
if (d13HelloCookieManager == null) {
|
||||||
d13HelloCookieManager =
|
d13HelloCookieManager =
|
||||||
new D13HelloCookieManager(secureRandom);
|
new D13HelloCookieManager(secureRandom);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
managerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return d13HelloCookieManager;
|
return d13HelloCookieManager;
|
||||||
@ -69,11 +75,14 @@ abstract class HelloCookieManager {
|
|||||||
return d10HelloCookieManager;
|
return d10HelloCookieManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
managerLock.lock();
|
||||||
|
try {
|
||||||
if (d10HelloCookieManager == null) {
|
if (d10HelloCookieManager == null) {
|
||||||
d10HelloCookieManager =
|
d10HelloCookieManager =
|
||||||
new D10HelloCookieManager(secureRandom);
|
new D10HelloCookieManager(secureRandom);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
managerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return d10HelloCookieManager;
|
return d10HelloCookieManager;
|
||||||
@ -84,11 +93,14 @@ abstract class HelloCookieManager {
|
|||||||
return t13HelloCookieManager;
|
return t13HelloCookieManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
managerLock.lock();
|
||||||
|
try {
|
||||||
if (t13HelloCookieManager == null) {
|
if (t13HelloCookieManager == null) {
|
||||||
t13HelloCookieManager =
|
t13HelloCookieManager =
|
||||||
new T13HelloCookieManager(secureRandom);
|
new T13HelloCookieManager(secureRandom);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
managerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return t13HelloCookieManager;
|
return t13HelloCookieManager;
|
||||||
@ -114,6 +126,8 @@ abstract class HelloCookieManager {
|
|||||||
private byte[] cookieSecret;
|
private byte[] cookieSecret;
|
||||||
private byte[] legacySecret;
|
private byte[] legacySecret;
|
||||||
|
|
||||||
|
private final ReentrantLock d10ManagerLock = new ReentrantLock();
|
||||||
|
|
||||||
D10HelloCookieManager(SecureRandom secureRandom) {
|
D10HelloCookieManager(SecureRandom secureRandom) {
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
|
|
||||||
@ -131,7 +145,8 @@ abstract class HelloCookieManager {
|
|||||||
int version;
|
int version;
|
||||||
byte[] secret;
|
byte[] secret;
|
||||||
|
|
||||||
synchronized (this) {
|
d10ManagerLock.lock();
|
||||||
|
try {
|
||||||
version = cookieVersion;
|
version = cookieVersion;
|
||||||
secret = cookieSecret;
|
secret = cookieSecret;
|
||||||
|
|
||||||
@ -142,6 +157,8 @@ abstract class HelloCookieManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cookieVersion++;
|
cookieVersion++;
|
||||||
|
} finally {
|
||||||
|
d10ManagerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageDigest md;
|
MessageDigest md;
|
||||||
@ -168,12 +185,15 @@ abstract class HelloCookieManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
byte[] secret;
|
byte[] secret;
|
||||||
synchronized (this) {
|
d10ManagerLock.lock();
|
||||||
|
try {
|
||||||
if (((cookieVersion >> 24) & 0xFF) == cookie[0]) {
|
if (((cookieVersion >> 24) & 0xFF) == cookie[0]) {
|
||||||
secret = cookieSecret;
|
secret = cookieSecret;
|
||||||
} else {
|
} else {
|
||||||
secret = legacySecret; // including out of window cookies
|
secret = legacySecret; // including out of window cookies
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
d10ManagerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageDigest md;
|
MessageDigest md;
|
||||||
@ -218,6 +238,8 @@ abstract class HelloCookieManager {
|
|||||||
private final byte[] cookieSecret;
|
private final byte[] cookieSecret;
|
||||||
private final byte[] legacySecret;
|
private final byte[] legacySecret;
|
||||||
|
|
||||||
|
private final ReentrantLock t13ManagerLock = new ReentrantLock();
|
||||||
|
|
||||||
T13HelloCookieManager(SecureRandom secureRandom) {
|
T13HelloCookieManager(SecureRandom secureRandom) {
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
this.cookieVersion = secureRandom.nextInt();
|
this.cookieVersion = secureRandom.nextInt();
|
||||||
@ -234,7 +256,8 @@ abstract class HelloCookieManager {
|
|||||||
int version;
|
int version;
|
||||||
byte[] secret;
|
byte[] secret;
|
||||||
|
|
||||||
synchronized (this) {
|
t13ManagerLock.lock();
|
||||||
|
try {
|
||||||
version = cookieVersion;
|
version = cookieVersion;
|
||||||
secret = cookieSecret;
|
secret = cookieSecret;
|
||||||
|
|
||||||
@ -245,6 +268,8 @@ abstract class HelloCookieManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cookieVersion++; // allow wrapped version number
|
cookieVersion++; // allow wrapped version number
|
||||||
|
} finally {
|
||||||
|
t13ManagerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageDigest md;
|
MessageDigest md;
|
||||||
@ -313,12 +338,15 @@ abstract class HelloCookieManager {
|
|||||||
Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length);
|
Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length);
|
||||||
|
|
||||||
byte[] secret;
|
byte[] secret;
|
||||||
synchronized (this) {
|
t13ManagerLock.lock();
|
||||||
|
try {
|
||||||
if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) {
|
if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) {
|
||||||
secret = cookieSecret;
|
secret = cookieSecret;
|
||||||
} else {
|
} else {
|
||||||
secret = legacySecret; // including out of window cookies
|
secret = legacySecret; // including out of window cookies
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
t13ManagerLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageDigest md;
|
MessageDigest md;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -31,6 +31,7 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.BufferUnderflowException;
|
import java.nio.BufferUnderflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import sun.security.ssl.SSLCipher.SSLReadCipher;
|
import sun.security.ssl.SSLCipher.SSLReadCipher;
|
||||||
|
|
||||||
@ -43,10 +44,10 @@ import sun.security.ssl.SSLCipher.SSLReadCipher;
|
|||||||
abstract class InputRecord implements Record, Closeable {
|
abstract class InputRecord implements Record, Closeable {
|
||||||
SSLReadCipher readCipher;
|
SSLReadCipher readCipher;
|
||||||
// Needed for KeyUpdate, used after Handshake.Finished
|
// Needed for KeyUpdate, used after Handshake.Finished
|
||||||
TransportContext tc;
|
TransportContext tc;
|
||||||
|
|
||||||
final HandshakeHash handshakeHash;
|
final HandshakeHash handshakeHash;
|
||||||
boolean isClosed;
|
volatile boolean isClosed;
|
||||||
|
|
||||||
// The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
|
// The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
|
||||||
// and the first message we read is a ClientHello in V2 format, we convert
|
// and the first message we read is a ClientHello in V2 format, we convert
|
||||||
@ -56,6 +57,8 @@ abstract class InputRecord implements Record, Closeable {
|
|||||||
// fragment size
|
// fragment size
|
||||||
int fragmentSize;
|
int fragmentSize;
|
||||||
|
|
||||||
|
final ReentrantLock recordLock = new ReentrantLock();
|
||||||
|
|
||||||
InputRecord(HandshakeHash handshakeHash, SSLReadCipher readCipher) {
|
InputRecord(HandshakeHash handshakeHash, SSLReadCipher readCipher) {
|
||||||
this.readCipher = readCipher;
|
this.readCipher = readCipher;
|
||||||
this.helloVersion = ProtocolVersion.TLS10;
|
this.helloVersion = ProtocolVersion.TLS10;
|
||||||
@ -92,14 +95,19 @@ abstract class InputRecord implements Record, Closeable {
|
|||||||
* and flag the record as holding no data.
|
* and flag the record as holding no data.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (!isClosed) {
|
recordLock.lock();
|
||||||
isClosed = true;
|
try {
|
||||||
readCipher.dispose();
|
if (!isClosed) {
|
||||||
|
isClosed = true;
|
||||||
|
readCipher.dispose();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized boolean isClosed() {
|
boolean isClosed() {
|
||||||
return isClosed;
|
return isClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,6 +30,7 @@ import java.io.Closeable;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import sun.security.ssl.SSLCipher.SSLWriteCipher;
|
import sun.security.ssl.SSLCipher.SSLWriteCipher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,6 +69,8 @@ abstract class OutputRecord
|
|||||||
// closed or not?
|
// closed or not?
|
||||||
volatile boolean isClosed;
|
volatile boolean isClosed;
|
||||||
|
|
||||||
|
final ReentrantLock recordLock = new ReentrantLock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mappings from V3 cipher suite encodings to their pure V2 equivalents.
|
* Mappings from V3 cipher suite encodings to their pure V2 equivalents.
|
||||||
* This is taken from the SSL V3 specification, Appendix E.
|
* This is taken from the SSL V3 specification, Appendix E.
|
||||||
@ -89,15 +92,25 @@ abstract class OutputRecord
|
|||||||
// Please set packetSize and protocolVersion in the implementation.
|
// Please set packetSize and protocolVersion in the implementation.
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setVersion(ProtocolVersion protocolVersion) {
|
void setVersion(ProtocolVersion protocolVersion) {
|
||||||
this.protocolVersion = protocolVersion;
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates helloVersion of this record.
|
* Updates helloVersion of this record.
|
||||||
*/
|
*/
|
||||||
synchronized void setHelloVersion(ProtocolVersion helloVersion) {
|
void setHelloVersion(ProtocolVersion helloVersion) {
|
||||||
this.helloVersion = helloVersion;
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
this.helloVersion = helloVersion;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -108,9 +121,14 @@ abstract class OutputRecord
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized boolean seqNumIsHuge() {
|
boolean seqNumIsHuge() {
|
||||||
return (writeCipher.authenticator != null) &&
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
return (writeCipher.authenticator != null) &&
|
||||||
writeCipher.authenticator.seqNumIsHuge();
|
writeCipher.authenticator.seqNumIsHuge();
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SSLEngine and SSLSocket
|
// SSLEngine and SSLSocket
|
||||||
@ -148,68 +166,93 @@ abstract class OutputRecord
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change write ciphers, may use change_cipher_spec record.
|
// Change write ciphers, may use change_cipher_spec record.
|
||||||
synchronized void changeWriteCiphers(SSLWriteCipher writeCipher,
|
void changeWriteCiphers(SSLWriteCipher writeCipher,
|
||||||
boolean useChangeCipherSpec) throws IOException {
|
boolean useChangeCipherSpec) throws IOException {
|
||||||
if (isClosed()) {
|
recordLock.lock();
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
try {
|
||||||
SSLLogger.warning("outbound has closed, ignore outbound " +
|
if (isClosed()) {
|
||||||
"change_cipher_spec message");
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
|
SSLLogger.warning("outbound has closed, ignore outbound " +
|
||||||
|
"change_cipher_spec message");
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
if (useChangeCipherSpec) {
|
||||||
|
encodeChangeCipherSpec();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dispose of any intermediate state in the underlying cipher.
|
||||||
|
* For PKCS11 ciphers, this will release any attached sessions,
|
||||||
|
* and thus make finalization faster.
|
||||||
|
*
|
||||||
|
* Since MAC's doFinal() is called for every SSL/TLS packet, it's
|
||||||
|
* not necessary to do the same with MAC's.
|
||||||
|
*/
|
||||||
|
writeCipher.dispose();
|
||||||
|
|
||||||
|
this.writeCipher = writeCipher;
|
||||||
|
this.isFirstAppOutputRecord = true;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useChangeCipherSpec) {
|
|
||||||
encodeChangeCipherSpec();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dispose of any intermediate state in the underlying cipher.
|
|
||||||
* For PKCS11 ciphers, this will release any attached sessions,
|
|
||||||
* and thus make finalization faster.
|
|
||||||
*
|
|
||||||
* Since MAC's doFinal() is called for every SSL/TLS packet, it's
|
|
||||||
* not necessary to do the same with MAC's.
|
|
||||||
*/
|
|
||||||
writeCipher.dispose();
|
|
||||||
|
|
||||||
this.writeCipher = writeCipher;
|
|
||||||
this.isFirstAppOutputRecord = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change write ciphers using key_update handshake message.
|
// Change write ciphers using key_update handshake message.
|
||||||
synchronized void changeWriteCiphers(SSLWriteCipher writeCipher,
|
void changeWriteCiphers(SSLWriteCipher writeCipher,
|
||||||
byte keyUpdateRequest) throws IOException {
|
byte keyUpdateRequest) throws IOException {
|
||||||
if (isClosed()) {
|
recordLock.lock();
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
try {
|
||||||
SSLLogger.warning("outbound has closed, ignore outbound " +
|
if (isClosed()) {
|
||||||
"key_update handshake message");
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
|
SSLLogger.warning("outbound has closed, ignore outbound " +
|
||||||
|
"key_update handshake message");
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
// encode the handshake message, KeyUpdate
|
||||||
|
byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone();
|
||||||
|
hm[hm.length - 1] = keyUpdateRequest;
|
||||||
|
encodeHandshake(hm, 0, hm.length);
|
||||||
|
flush();
|
||||||
|
|
||||||
|
// Dispose of any intermediate state in the underlying cipher.
|
||||||
|
writeCipher.dispose();
|
||||||
|
|
||||||
|
this.writeCipher = writeCipher;
|
||||||
|
this.isFirstAppOutputRecord = true;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode the handshake message, KeyUpdate
|
|
||||||
byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone();
|
|
||||||
hm[hm.length - 1] = keyUpdateRequest;
|
|
||||||
encodeHandshake(hm, 0, hm.length);
|
|
||||||
flush();
|
|
||||||
|
|
||||||
// Dispose of any intermediate state in the underlying cipher.
|
|
||||||
writeCipher.dispose();
|
|
||||||
|
|
||||||
this.writeCipher = writeCipher;
|
|
||||||
this.isFirstAppOutputRecord = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void changePacketSize(int packetSize) {
|
void changePacketSize(int packetSize) {
|
||||||
this.packetSize = packetSize;
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
this.packetSize = packetSize;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void changeFragmentSize(int fragmentSize) {
|
void changeFragmentSize(int fragmentSize) {
|
||||||
this.fragmentSize = fragmentSize;
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
this.fragmentSize = fragmentSize;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int getMaxPacketSize() {
|
int getMaxPacketSize() {
|
||||||
return packetSize;
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
return packetSize;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply to DTLS SSLEngine
|
// apply to DTLS SSLEngine
|
||||||
@ -228,13 +271,18 @@ abstract class OutputRecord
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (isClosed) {
|
recordLock.lock();
|
||||||
return;
|
try {
|
||||||
}
|
if (isClosed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isClosed = true;
|
isClosed = true;
|
||||||
writeCipher.dispose();
|
writeCipher.dispose();
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isClosed() {
|
boolean isClosed() {
|
||||||
|
@ -30,6 +30,7 @@ import java.net.Socket;
|
|||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
import sun.security.action.GetPropertyAction;
|
import sun.security.action.GetPropertyAction;
|
||||||
import sun.security.provider.certpath.AlgorithmChecker;
|
import sun.security.provider.certpath.AlgorithmChecker;
|
||||||
@ -69,6 +70,8 @@ public abstract class SSLContextImpl extends SSLContextSpi {
|
|||||||
|
|
||||||
private volatile StatusResponseManager statusResponseManager;
|
private volatile StatusResponseManager statusResponseManager;
|
||||||
|
|
||||||
|
private final ReentrantLock contextLock = new ReentrantLock();
|
||||||
|
|
||||||
SSLContextImpl() {
|
SSLContextImpl() {
|
||||||
ephemeralKeyManager = new EphemeralKeyManager();
|
ephemeralKeyManager = new EphemeralKeyManager();
|
||||||
clientCache = new SSLSessionContextImpl();
|
clientCache = new SSLSessionContextImpl();
|
||||||
@ -230,11 +233,14 @@ public abstract class SSLContextImpl extends SSLContextSpi {
|
|||||||
// Used for DTLS in server mode only.
|
// Used for DTLS in server mode only.
|
||||||
HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) {
|
HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) {
|
||||||
if (helloCookieManagerBuilder == null) {
|
if (helloCookieManagerBuilder == null) {
|
||||||
synchronized (this) {
|
contextLock.lock();
|
||||||
|
try {
|
||||||
if (helloCookieManagerBuilder == null) {
|
if (helloCookieManagerBuilder == null) {
|
||||||
helloCookieManagerBuilder =
|
helloCookieManagerBuilder =
|
||||||
new HelloCookieManager.Builder(secureRandom);
|
new HelloCookieManager.Builder(secureRandom);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
contextLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +249,8 @@ public abstract class SSLContextImpl extends SSLContextSpi {
|
|||||||
|
|
||||||
StatusResponseManager getStatusResponseManager() {
|
StatusResponseManager getStatusResponseManager() {
|
||||||
if (serverEnableStapling && statusResponseManager == null) {
|
if (serverEnableStapling && statusResponseManager == null) {
|
||||||
synchronized (this) {
|
contextLock.lock();
|
||||||
|
try {
|
||||||
if (statusResponseManager == null) {
|
if (statusResponseManager == null) {
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
|
||||||
SSLLogger.finest(
|
SSLLogger.finest(
|
||||||
@ -251,6 +258,8 @@ public abstract class SSLContextImpl extends SSLContextSpi {
|
|||||||
}
|
}
|
||||||
statusResponseManager = new StatusResponseManager();
|
statusResponseManager = new StatusResponseManager();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
contextLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -33,6 +33,7 @@ import java.security.PrivilegedActionException;
|
|||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLEngineResult;
|
import javax.net.ssl.SSLEngineResult;
|
||||||
@ -54,6 +55,7 @@ import javax.net.ssl.SSLSession;
|
|||||||
final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
||||||
private final SSLContextImpl sslContext;
|
private final SSLContextImpl sslContext;
|
||||||
final TransportContext conContext;
|
final TransportContext conContext;
|
||||||
|
private final ReentrantLock engineLock = new ReentrantLock();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for an SSLEngine from SSLContext, without
|
* Constructor for an SSLEngine from SSLContext, without
|
||||||
@ -93,57 +95,68 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void beginHandshake() throws SSLException {
|
public void beginHandshake() throws SSLException {
|
||||||
if (conContext.isUnsureMode) {
|
engineLock.lock();
|
||||||
throw new IllegalStateException(
|
|
||||||
"Client/Server mode has not yet been set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conContext.kickstart();
|
if (conContext.isUnsureMode) {
|
||||||
} catch (IOException ioe) {
|
throw new IllegalStateException(
|
||||||
throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
|
"Client/Server mode has not yet been set.");
|
||||||
"Couldn't kickstart handshaking", ioe);
|
}
|
||||||
} catch (Exception ex) { // including RuntimeException
|
|
||||||
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
try {
|
||||||
"Fail to begin handshake", ex);
|
conContext.kickstart();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
|
||||||
|
"Couldn't kickstart handshaking", ioe);
|
||||||
|
} catch (Exception ex) { // including RuntimeException
|
||||||
|
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
||||||
|
"Fail to begin handshake", ex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized SSLEngineResult wrap(ByteBuffer[] appData,
|
public SSLEngineResult wrap(ByteBuffer[] appData,
|
||||||
int offset, int length, ByteBuffer netData) throws SSLException {
|
int offset, int length, ByteBuffer netData) throws SSLException {
|
||||||
return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1);
|
return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
public synchronized SSLEngineResult wrap(
|
public SSLEngineResult wrap(
|
||||||
ByteBuffer[] srcs, int srcsOffset, int srcsLength,
|
ByteBuffer[] srcs, int srcsOffset, int srcsLength,
|
||||||
ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
|
ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
|
||||||
|
|
||||||
if (conContext.isUnsureMode) {
|
engineLock.lock();
|
||||||
throw new IllegalStateException(
|
|
||||||
"Client/Server mode has not yet been set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if the handshaker needs to report back some SSLException.
|
|
||||||
checkTaskThrown();
|
|
||||||
|
|
||||||
// check parameters
|
|
||||||
checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return writeRecord(
|
if (conContext.isUnsureMode) {
|
||||||
srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
|
throw new IllegalStateException(
|
||||||
} catch (SSLProtocolException spe) {
|
"Client/Server mode has not yet been set.");
|
||||||
// may be an unexpected handshake message
|
}
|
||||||
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
|
|
||||||
} catch (IOException ioe) {
|
// See if the handshaker needs to report back some SSLException.
|
||||||
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
checkTaskThrown();
|
||||||
"problem wrapping app data", ioe);
|
|
||||||
} catch (Exception ex) { // including RuntimeException
|
// check parameters
|
||||||
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
checkParams(srcs, srcsOffset, srcsLength,
|
||||||
"Fail to wrap application data", ex);
|
dsts, dstsOffset, dstsLength);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return writeRecord(
|
||||||
|
srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
|
||||||
|
} catch (SSLProtocolException spe) {
|
||||||
|
// may be an unexpected handshake message
|
||||||
|
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
||||||
|
"problem wrapping app data", ioe);
|
||||||
|
} catch (Exception ex) { // including RuntimeException
|
||||||
|
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
||||||
|
"Fail to wrap application data", ex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,47 +441,53 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized SSLEngineResult unwrap(ByteBuffer src,
|
public SSLEngineResult unwrap(ByteBuffer src,
|
||||||
ByteBuffer[] dsts, int offset, int length) throws SSLException {
|
ByteBuffer[] dsts, int offset, int length) throws SSLException {
|
||||||
return unwrap(
|
return unwrap(
|
||||||
new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
|
new ByteBuffer[]{src}, 0, 1, dsts, offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
public synchronized SSLEngineResult unwrap(
|
public SSLEngineResult unwrap(
|
||||||
ByteBuffer[] srcs, int srcsOffset, int srcsLength,
|
ByteBuffer[] srcs, int srcsOffset, int srcsLength,
|
||||||
ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
|
ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException {
|
||||||
|
|
||||||
if (conContext.isUnsureMode) {
|
engineLock.lock();
|
||||||
throw new IllegalStateException(
|
|
||||||
"Client/Server mode has not yet been set.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if the handshaker needs to report back some SSLException.
|
|
||||||
checkTaskThrown();
|
|
||||||
|
|
||||||
// check parameters
|
|
||||||
checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return readRecord(
|
if (conContext.isUnsureMode) {
|
||||||
srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
|
throw new IllegalStateException(
|
||||||
} catch (SSLProtocolException spe) {
|
"Client/Server mode has not yet been set.");
|
||||||
// may be an unexpected handshake message
|
}
|
||||||
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
|
|
||||||
spe.getMessage(), spe);
|
// See if the handshaker needs to report back some SSLException.
|
||||||
} catch (IOException ioe) {
|
checkTaskThrown();
|
||||||
/*
|
|
||||||
* Don't reset position so it looks like we didn't
|
// check parameters
|
||||||
* consume anything. We did consume something, and it
|
checkParams(srcs, srcsOffset, srcsLength,
|
||||||
* got us into this situation, so report that much back.
|
dsts, dstsOffset, dstsLength);
|
||||||
* Our days of consuming are now over anyway.
|
|
||||||
*/
|
try {
|
||||||
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
return readRecord(
|
||||||
"problem unwrapping net record", ioe);
|
srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength);
|
||||||
} catch (Exception ex) { // including RuntimeException
|
} catch (SSLProtocolException spe) {
|
||||||
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
// may be an unexpected handshake message
|
||||||
"Fail to unwrap network record", ex);
|
throw conContext.fatal(Alert.UNEXPECTED_MESSAGE,
|
||||||
|
spe.getMessage(), spe);
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
/*
|
||||||
|
* Don't reset position so it looks like we didn't
|
||||||
|
* consume anything. We did consume something, and it
|
||||||
|
* got us into this situation, so report that much back.
|
||||||
|
* Our days of consuming are now over anyway.
|
||||||
|
*/
|
||||||
|
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
||||||
|
"problem unwrapping net record", ioe);
|
||||||
|
} catch (Exception ex) { // including RuntimeException
|
||||||
|
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
||||||
|
"Fail to unwrap network record", ex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -703,61 +722,87 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized Runnable getDelegatedTask() {
|
public Runnable getDelegatedTask() {
|
||||||
if (conContext.handshakeContext != null && // PRE or POST handshake
|
engineLock.lock();
|
||||||
!conContext.handshakeContext.taskDelegated &&
|
try {
|
||||||
!conContext.handshakeContext.delegatedActions.isEmpty()) {
|
if (conContext.handshakeContext != null && // PRE or POST handshake
|
||||||
conContext.handshakeContext.taskDelegated = true;
|
!conContext.handshakeContext.taskDelegated &&
|
||||||
return new DelegatedTask(this);
|
!conContext.handshakeContext.delegatedActions.isEmpty()) {
|
||||||
|
conContext.handshakeContext.taskDelegated = true;
|
||||||
|
return new DelegatedTask(this);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void closeInbound() throws SSLException {
|
public void closeInbound() throws SSLException {
|
||||||
if (isInboundDone()) {
|
engineLock.lock();
|
||||||
return;
|
try {
|
||||||
|
if (isInboundDone()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
|
SSLLogger.finest("Closing inbound of SSLEngine");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it ready to close inbound?
|
||||||
|
//
|
||||||
|
// No exception if the initial handshake is not started.
|
||||||
|
if (!conContext.isInputCloseNotified &&
|
||||||
|
(conContext.isNegotiated ||
|
||||||
|
conContext.handshakeContext != null)) {
|
||||||
|
|
||||||
|
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
||||||
|
"closing inbound before receiving peer's close_notify");
|
||||||
|
}
|
||||||
|
|
||||||
|
conContext.closeInbound();
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
|
||||||
SSLLogger.finest("Closing inbound of SSLEngine");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it ready to close inbound?
|
|
||||||
//
|
|
||||||
// No need to throw exception if the initial handshake is not started.
|
|
||||||
if (!conContext.isInputCloseNotified &&
|
|
||||||
(conContext.isNegotiated || conContext.handshakeContext != null)) {
|
|
||||||
|
|
||||||
throw conContext.fatal(Alert.INTERNAL_ERROR,
|
|
||||||
"closing inbound before receiving peer's close_notify");
|
|
||||||
}
|
|
||||||
|
|
||||||
conContext.closeInbound();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isInboundDone() {
|
public boolean isInboundDone() {
|
||||||
return conContext.isInboundClosed();
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.isInboundClosed();
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void closeOutbound() {
|
public void closeOutbound() {
|
||||||
if (conContext.isOutboundClosed()) {
|
engineLock.lock();
|
||||||
return;
|
try {
|
||||||
}
|
if (conContext.isOutboundClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
SSLLogger.finest("Closing outbound of SSLEngine");
|
SSLLogger.finest("Closing outbound of SSLEngine");
|
||||||
}
|
}
|
||||||
|
|
||||||
conContext.closeOutbound();
|
conContext.closeOutbound();
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isOutboundDone() {
|
public boolean isOutboundDone() {
|
||||||
return conContext.isOutboundDone();
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.isOutboundDone();
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -766,14 +811,24 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String[] getEnabledCipherSuites() {
|
public String[] getEnabledCipherSuites() {
|
||||||
return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setEnabledCipherSuites(String[] suites) {
|
public void setEnabledCipherSuites(String[] suites) {
|
||||||
conContext.sslConfig.enabledCipherSuites =
|
engineLock.lock();
|
||||||
CipherSuite.validValuesOf(suites);
|
try {
|
||||||
|
conContext.sslConfig.enabledCipherSuites =
|
||||||
|
CipherSuite.validValuesOf(suites);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -783,119 +838,214 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String[] getEnabledProtocols() {
|
public String[] getEnabledProtocols() {
|
||||||
return ProtocolVersion.toStringArray(
|
engineLock.lock();
|
||||||
conContext.sslConfig.enabledProtocols);
|
try {
|
||||||
}
|
return ProtocolVersion.toStringArray(
|
||||||
|
conContext.sslConfig.enabledProtocols);
|
||||||
@Override
|
} finally {
|
||||||
public synchronized void setEnabledProtocols(String[] protocols) {
|
engineLock.unlock();
|
||||||
if (protocols == null) {
|
|
||||||
throw new IllegalArgumentException("Protocols cannot be null");
|
|
||||||
}
|
|
||||||
|
|
||||||
conContext.sslConfig.enabledProtocols =
|
|
||||||
ProtocolVersion.namesOf(protocols);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized SSLSession getSession() {
|
|
||||||
return conContext.conSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized SSLSession getHandshakeSession() {
|
|
||||||
return conContext.handshakeContext == null ?
|
|
||||||
null : conContext.handshakeContext.handshakeSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
|
|
||||||
return conContext.getHandshakeStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setUseClientMode(boolean mode) {
|
|
||||||
conContext.setUseClientMode(mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean getUseClientMode() {
|
|
||||||
return conContext.sslConfig.isClientMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setNeedClientAuth(boolean need) {
|
|
||||||
conContext.sslConfig.clientAuthType =
|
|
||||||
(need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
|
|
||||||
ClientAuthType.CLIENT_AUTH_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean getNeedClientAuth() {
|
|
||||||
return (conContext.sslConfig.clientAuthType ==
|
|
||||||
ClientAuthType.CLIENT_AUTH_REQUIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setWantClientAuth(boolean want) {
|
|
||||||
conContext.sslConfig.clientAuthType =
|
|
||||||
(want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
|
|
||||||
ClientAuthType.CLIENT_AUTH_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean getWantClientAuth() {
|
|
||||||
return (conContext.sslConfig.clientAuthType ==
|
|
||||||
ClientAuthType.CLIENT_AUTH_REQUESTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setEnableSessionCreation(boolean flag) {
|
|
||||||
conContext.sslConfig.enableSessionCreation = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean getEnableSessionCreation() {
|
|
||||||
return conContext.sslConfig.enableSessionCreation;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized SSLParameters getSSLParameters() {
|
|
||||||
return conContext.sslConfig.getSSLParameters();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setSSLParameters(SSLParameters params) {
|
|
||||||
conContext.sslConfig.setSSLParameters(params);
|
|
||||||
|
|
||||||
if (conContext.sslConfig.maximumPacketSize != 0) {
|
|
||||||
conContext.outputRecord.changePacketSize(
|
|
||||||
conContext.sslConfig.maximumPacketSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String getApplicationProtocol() {
|
public void setEnabledProtocols(String[] protocols) {
|
||||||
return conContext.applicationProtocol;
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
if (protocols == null) {
|
||||||
|
throw new IllegalArgumentException("Protocols cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
conContext.sslConfig.enabledProtocols =
|
||||||
|
ProtocolVersion.namesOf(protocols);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String getHandshakeApplicationProtocol() {
|
public SSLSession getSession() {
|
||||||
return conContext.handshakeContext == null ?
|
engineLock.lock();
|
||||||
null : conContext.handshakeContext.applicationProtocol;
|
try {
|
||||||
|
return conContext.conSession;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setHandshakeApplicationProtocolSelector(
|
public SSLSession getHandshakeSession() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.handshakeContext == null ?
|
||||||
|
null : conContext.handshakeContext.handshakeSession;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.getHandshakeStatus();
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUseClientMode(boolean mode) {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.setUseClientMode(mode);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getUseClientMode() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.sslConfig.isClientMode;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNeedClientAuth(boolean need) {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.clientAuthType =
|
||||||
|
(need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
|
||||||
|
ClientAuthType.CLIENT_AUTH_NONE);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getNeedClientAuth() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return (conContext.sslConfig.clientAuthType ==
|
||||||
|
ClientAuthType.CLIENT_AUTH_REQUIRED);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWantClientAuth(boolean want) {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.clientAuthType =
|
||||||
|
(want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
|
||||||
|
ClientAuthType.CLIENT_AUTH_NONE);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getWantClientAuth() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return (conContext.sslConfig.clientAuthType ==
|
||||||
|
ClientAuthType.CLIENT_AUTH_REQUESTED);
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnableSessionCreation(boolean flag) {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.enableSessionCreation = flag;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getEnableSessionCreation() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.sslConfig.enableSessionCreation;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSLParameters getSSLParameters() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.sslConfig.getSSLParameters();
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSSLParameters(SSLParameters params) {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.setSSLParameters(params);
|
||||||
|
|
||||||
|
if (conContext.sslConfig.maximumPacketSize != 0) {
|
||||||
|
conContext.outputRecord.changePacketSize(
|
||||||
|
conContext.sslConfig.maximumPacketSize);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getApplicationProtocol() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.applicationProtocol;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHandshakeApplicationProtocol() {
|
||||||
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.handshakeContext == null ?
|
||||||
|
null : conContext.handshakeContext.applicationProtocol;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHandshakeApplicationProtocolSelector(
|
||||||
BiFunction<SSLEngine, List<String>, String> selector) {
|
BiFunction<SSLEngine, List<String>, String> selector) {
|
||||||
conContext.sslConfig.engineAPSelector = selector;
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.engineAPSelector = selector;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized BiFunction<SSLEngine, List<String>, String>
|
public BiFunction<SSLEngine, List<String>, String>
|
||||||
getHandshakeApplicationProtocolSelector() {
|
getHandshakeApplicationProtocolSelector() {
|
||||||
return conContext.sslConfig.engineAPSelector;
|
engineLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.sslConfig.engineAPSelector;
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -909,38 +1059,42 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
* null, report back the Exception that happened in the delegated
|
* null, report back the Exception that happened in the delegated
|
||||||
* task(s).
|
* task(s).
|
||||||
*/
|
*/
|
||||||
private synchronized void checkTaskThrown() throws SSLException {
|
private void checkTaskThrown() throws SSLException {
|
||||||
|
|
||||||
Exception exc = null;
|
Exception exc = null;
|
||||||
|
engineLock.lock();
|
||||||
// First check the handshake context.
|
try {
|
||||||
HandshakeContext hc = conContext.handshakeContext;
|
// First check the handshake context.
|
||||||
if ((hc != null) && (hc.delegatedThrown != null)) {
|
HandshakeContext hc = conContext.handshakeContext;
|
||||||
exc = hc.delegatedThrown;
|
if ((hc != null) && (hc.delegatedThrown != null)) {
|
||||||
hc.delegatedThrown = null;
|
exc = hc.delegatedThrown;
|
||||||
}
|
hc.delegatedThrown = null;
|
||||||
|
|
||||||
/*
|
|
||||||
* hc.delegatedThrown and conContext.delegatedThrown are most likely
|
|
||||||
* the same, but it's possible we could have had a non-fatal
|
|
||||||
* exception and thus the new HandshakeContext is still valid
|
|
||||||
* (alert warning). If so, then we may have a secondary exception
|
|
||||||
* waiting to be reported from the TransportContext, so we will
|
|
||||||
* need to clear that on a successive call. Otherwise, clear it now.
|
|
||||||
*/
|
|
||||||
if (conContext.delegatedThrown != null) {
|
|
||||||
if (exc != null) {
|
|
||||||
// hc object comparison
|
|
||||||
if (conContext.delegatedThrown == exc) {
|
|
||||||
// clear if/only if both are the same
|
|
||||||
conContext.delegatedThrown = null;
|
|
||||||
} // otherwise report the hc delegatedThrown
|
|
||||||
} else {
|
|
||||||
// Nothing waiting in HandshakeContext, but one is in the
|
|
||||||
// TransportContext.
|
|
||||||
exc = conContext.delegatedThrown;
|
|
||||||
conContext.delegatedThrown = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hc.delegatedThrown and conContext.delegatedThrown are most
|
||||||
|
* likely the same, but it's possible we could have had a non-fatal
|
||||||
|
* exception and thus the new HandshakeContext is still valid
|
||||||
|
* (alert warning). If so, then we may have a secondary exception
|
||||||
|
* waiting to be reported from the TransportContext, so we will
|
||||||
|
* need to clear that on a successive call. Otherwise, clear it now.
|
||||||
|
*/
|
||||||
|
if (conContext.delegatedThrown != null) {
|
||||||
|
if (exc != null) {
|
||||||
|
// hc object comparison
|
||||||
|
if (conContext.delegatedThrown == exc) {
|
||||||
|
// clear if/only if both are the same
|
||||||
|
conContext.delegatedThrown = null;
|
||||||
|
} // otherwise report the hc delegatedThrown
|
||||||
|
} else {
|
||||||
|
// Nothing waiting in HandshakeContext, but one is in the
|
||||||
|
// TransportContext.
|
||||||
|
exc = conContext.delegatedThrown;
|
||||||
|
conContext.delegatedThrown = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
engineLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anything to report?
|
// Anything to report?
|
||||||
@ -998,7 +1152,8 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (engine) {
|
engine.engineLock.lock();
|
||||||
|
try {
|
||||||
HandshakeContext hc = engine.conContext.handshakeContext;
|
HandshakeContext hc = engine.conContext.handshakeContext;
|
||||||
if (hc == null || hc.delegatedActions.isEmpty()) {
|
if (hc == null || hc.delegatedActions.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -1055,6 +1210,8 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport {
|
|||||||
if (hc != null) {
|
if (hc != null) {
|
||||||
hc.taskDelegated = false;
|
hc.taskDelegated = false;
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
engine.engineLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -51,13 +51,18 @@ final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (!isClosed) {
|
recordLock.lock();
|
||||||
if (fragmenter != null && fragmenter.hasAlert()) {
|
try {
|
||||||
isCloseWaiting = true;
|
if (!isClosed) {
|
||||||
} else {
|
if (fragmenter != null && fragmenter.hasAlert()) {
|
||||||
super.close();
|
isCloseWaiting = true;
|
||||||
|
} else {
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -28,6 +28,7 @@ package sun.security.ssl;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import javax.net.ssl.SSLParameters;
|
import javax.net.ssl.SSLParameters;
|
||||||
import javax.net.ssl.SSLServerSocket;
|
import javax.net.ssl.SSLServerSocket;
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ import javax.net.ssl.SSLServerSocket;
|
|||||||
final class SSLServerSocketImpl extends SSLServerSocket {
|
final class SSLServerSocketImpl extends SSLServerSocket {
|
||||||
private final SSLContextImpl sslContext;
|
private final SSLContextImpl sslContext;
|
||||||
private final SSLConfiguration sslConfig;
|
private final SSLConfiguration sslConfig;
|
||||||
|
private final ReentrantLock serverSocketLock = new ReentrantLock();
|
||||||
|
|
||||||
SSLServerSocketImpl(SSLContextImpl sslContext) throws IOException {
|
SSLServerSocketImpl(SSLContextImpl sslContext) throws IOException {
|
||||||
|
|
||||||
@ -84,14 +86,24 @@ final class SSLServerSocketImpl extends SSLServerSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String[] getEnabledCipherSuites() {
|
public String[] getEnabledCipherSuites() {
|
||||||
return CipherSuite.namesOf(sslConfig.enabledCipherSuites);
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
return CipherSuite.namesOf(sslConfig.enabledCipherSuites);
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setEnabledCipherSuites(String[] suites) {
|
public void setEnabledCipherSuites(String[] suites) {
|
||||||
sslConfig.enabledCipherSuites =
|
serverSocketLock.lock();
|
||||||
CipherSuite.validValuesOf(suites);
|
try {
|
||||||
|
sslConfig.enabledCipherSuites =
|
||||||
|
CipherSuite.validValuesOf(suites);
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -106,93 +118,153 @@ final class SSLServerSocketImpl extends SSLServerSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String[] getEnabledProtocols() {
|
public String[] getEnabledProtocols() {
|
||||||
return ProtocolVersion.toStringArray(sslConfig.enabledProtocols);
|
serverSocketLock.lock();
|
||||||
}
|
try {
|
||||||
|
return ProtocolVersion.toStringArray(sslConfig.enabledProtocols);
|
||||||
@Override
|
} finally {
|
||||||
public synchronized void setEnabledProtocols(String[] protocols) {
|
serverSocketLock.unlock();
|
||||||
if (protocols == null) {
|
|
||||||
throw new IllegalArgumentException("Protocols cannot be null");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setNeedClientAuth(boolean need) {
|
public void setEnabledProtocols(String[] protocols) {
|
||||||
sslConfig.clientAuthType =
|
serverSocketLock.lock();
|
||||||
(need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
|
try {
|
||||||
ClientAuthType.CLIENT_AUTH_NONE);
|
if (protocols == null) {
|
||||||
|
throw new IllegalArgumentException("Protocols cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols);
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean getNeedClientAuth() {
|
public void setNeedClientAuth(boolean need) {
|
||||||
return (sslConfig.clientAuthType ==
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
sslConfig.clientAuthType =
|
||||||
|
(need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
|
||||||
|
ClientAuthType.CLIENT_AUTH_NONE);
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getNeedClientAuth() {
|
||||||
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
return (sslConfig.clientAuthType ==
|
||||||
ClientAuthType.CLIENT_AUTH_REQUIRED);
|
ClientAuthType.CLIENT_AUTH_REQUIRED);
|
||||||
}
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
@Override
|
|
||||||
public synchronized void setWantClientAuth(boolean want) {
|
|
||||||
sslConfig.clientAuthType =
|
|
||||||
(want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
|
|
||||||
ClientAuthType.CLIENT_AUTH_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized boolean getWantClientAuth() {
|
|
||||||
return (sslConfig.clientAuthType ==
|
|
||||||
ClientAuthType.CLIENT_AUTH_REQUESTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void setUseClientMode(boolean useClientMode) {
|
|
||||||
/*
|
|
||||||
* If we need to change the client mode and the enabled
|
|
||||||
* protocols and cipher suites haven't specifically been
|
|
||||||
* set by the user, change them to the corresponding
|
|
||||||
* default ones.
|
|
||||||
*/
|
|
||||||
if (sslConfig.isClientMode != useClientMode) {
|
|
||||||
if (sslContext.isDefaultProtocolVesions(
|
|
||||||
sslConfig.enabledProtocols)) {
|
|
||||||
sslConfig.enabledProtocols =
|
|
||||||
sslContext.getDefaultProtocolVersions(!useClientMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sslContext.isDefaultCipherSuiteList(
|
|
||||||
sslConfig.enabledCipherSuites)) {
|
|
||||||
sslConfig.enabledCipherSuites =
|
|
||||||
sslContext.getDefaultCipherSuites(!useClientMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
sslConfig.isClientMode = useClientMode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean getUseClientMode() {
|
public void setWantClientAuth(boolean want) {
|
||||||
return sslConfig.isClientMode;
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
sslConfig.clientAuthType =
|
||||||
|
(want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
|
||||||
|
ClientAuthType.CLIENT_AUTH_NONE);
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setEnableSessionCreation(boolean flag) {
|
public boolean getWantClientAuth() {
|
||||||
sslConfig.enableSessionCreation = flag;
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
return (sslConfig.clientAuthType ==
|
||||||
|
ClientAuthType.CLIENT_AUTH_REQUESTED);
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean getEnableSessionCreation() {
|
public void setUseClientMode(boolean useClientMode) {
|
||||||
return sslConfig.enableSessionCreation;
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
/*
|
||||||
|
* If we need to change the client mode and the enabled
|
||||||
|
* protocols and cipher suites haven't specifically been
|
||||||
|
* set by the user, change them to the corresponding
|
||||||
|
* default ones.
|
||||||
|
*/
|
||||||
|
if (sslConfig.isClientMode != useClientMode) {
|
||||||
|
if (sslContext.isDefaultProtocolVesions(
|
||||||
|
sslConfig.enabledProtocols)) {
|
||||||
|
sslConfig.enabledProtocols =
|
||||||
|
sslContext.getDefaultProtocolVersions(!useClientMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sslContext.isDefaultCipherSuiteList(
|
||||||
|
sslConfig.enabledCipherSuites)) {
|
||||||
|
sslConfig.enabledCipherSuites =
|
||||||
|
sslContext.getDefaultCipherSuites(!useClientMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
sslConfig.isClientMode = useClientMode;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized SSLParameters getSSLParameters() {
|
public boolean getUseClientMode() {
|
||||||
return sslConfig.getSSLParameters();
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
return sslConfig.isClientMode;
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setSSLParameters(SSLParameters params) {
|
public void setEnableSessionCreation(boolean flag) {
|
||||||
sslConfig.setSSLParameters(params);
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
sslConfig.enableSessionCreation = flag;
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getEnableSessionCreation() {
|
||||||
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
return sslConfig.enableSessionCreation;
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSLParameters getSSLParameters() {
|
||||||
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
return sslConfig.getSSLParameters();
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSSLParameters(SSLParameters params) {
|
||||||
|
serverSocketLock.lock();
|
||||||
|
try {
|
||||||
|
sslConfig.setSSLParameters(params);
|
||||||
|
} finally {
|
||||||
|
serverSocketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -38,6 +38,7 @@ import java.util.Enumeration;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
import javax.net.ssl.ExtendedSSLSession;
|
import javax.net.ssl.ExtendedSSLSession;
|
||||||
import javax.net.ssl.SNIServerName;
|
import javax.net.ssl.SNIServerName;
|
||||||
@ -133,7 +134,9 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
|
|
||||||
// The endpoint identification algorithm used to check certificates
|
// The endpoint identification algorithm used to check certificates
|
||||||
// in this session.
|
// in this session.
|
||||||
private final String identificationProtocol;
|
private final String identificationProtocol;
|
||||||
|
|
||||||
|
private final ReentrantLock sessionLock = new ReentrantLock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new non-rejoinable session, using the default (null)
|
* Create a new non-rejoinable session, using the default (null)
|
||||||
@ -289,15 +292,22 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
return resumptionMasterSecret;
|
return resumptionMasterSecret;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized SecretKey getPreSharedKey() {
|
SecretKey getPreSharedKey() {
|
||||||
return preSharedKey;
|
sessionLock.lock();
|
||||||
|
try {
|
||||||
|
return preSharedKey;
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized SecretKey consumePreSharedKey() {
|
SecretKey consumePreSharedKey() {
|
||||||
|
sessionLock.lock();
|
||||||
try {
|
try {
|
||||||
return preSharedKey;
|
return preSharedKey;
|
||||||
} finally {
|
} finally {
|
||||||
preSharedKey = null;
|
preSharedKey = null;
|
||||||
|
sessionLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,11 +323,13 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
* be used once. This method will return the identity and then clear it
|
* be used once. This method will return the identity and then clear it
|
||||||
* so it cannot be used again.
|
* so it cannot be used again.
|
||||||
*/
|
*/
|
||||||
synchronized byte[] consumePskIdentity() {
|
byte[] consumePskIdentity() {
|
||||||
|
sessionLock.lock();
|
||||||
try {
|
try {
|
||||||
return pskIdentity;
|
return pskIdentity;
|
||||||
} finally {
|
} finally {
|
||||||
pskIdentity = null;
|
pskIdentity = null;
|
||||||
|
sessionLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,8 +405,13 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isValid() {
|
public boolean isValid() {
|
||||||
return isRejoinable();
|
sessionLock.lock();
|
||||||
|
try {
|
||||||
|
return isRejoinable();
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -777,29 +794,35 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
* no connections will be able to rejoin this session.
|
* no connections will be able to rejoin this session.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized void invalidate() {
|
public void invalidate() {
|
||||||
//
|
sessionLock.lock();
|
||||||
// Can't invalidate the NULL session -- this would be
|
try {
|
||||||
// attempted when we get a handshaking error on a brand
|
//
|
||||||
// new connection, with no "real" session yet.
|
// Can't invalidate the NULL session -- this would be
|
||||||
//
|
// attempted when we get a handshaking error on a brand
|
||||||
if (this == nullSession) {
|
// new connection, with no "real" session yet.
|
||||||
return;
|
//
|
||||||
}
|
if (this == nullSession) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
context.remove(sessionId);
|
context.remove(sessionId);
|
||||||
context = null;
|
context = null;
|
||||||
}
|
}
|
||||||
if (invalidated) {
|
|
||||||
return;
|
if (invalidated) {
|
||||||
}
|
return;
|
||||||
invalidated = true;
|
}
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("session")) {
|
invalidated = true;
|
||||||
SSLLogger.finest("Invalidated session: " + this);
|
if (SSLLogger.isOn && SSLLogger.isOn("session")) {
|
||||||
}
|
SSLLogger.finest("Invalidated session: " + this);
|
||||||
for (SSLSessionImpl child : childSessions) {
|
}
|
||||||
child.invalidate();
|
for (SSLSessionImpl child : childSessions) {
|
||||||
|
child.invalidate();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -912,8 +935,13 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
* Expand the buffer size of both SSL/TLS network packet and
|
* Expand the buffer size of both SSL/TLS network packet and
|
||||||
* application data.
|
* application data.
|
||||||
*/
|
*/
|
||||||
protected synchronized void expandBufferSizes() {
|
protected void expandBufferSizes() {
|
||||||
acceptLargeFragments = true;
|
sessionLock.lock();
|
||||||
|
try {
|
||||||
|
acceptLargeFragments = true;
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -921,30 +949,35 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
* when using this session.
|
* when using this session.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized int getPacketBufferSize() {
|
public int getPacketBufferSize() {
|
||||||
// Use the bigger packet size calculated from maximumPacketSize
|
sessionLock.lock();
|
||||||
// and negotiatedMaxFragLen.
|
try {
|
||||||
int packetSize = 0;
|
// Use the bigger packet size calculated from maximumPacketSize
|
||||||
if (negotiatedMaxFragLen > 0) {
|
// and negotiatedMaxFragLen.
|
||||||
packetSize = cipherSuite.calculatePacketSize(
|
int packetSize = 0;
|
||||||
negotiatedMaxFragLen, protocolVersion,
|
if (negotiatedMaxFragLen > 0) {
|
||||||
protocolVersion.isDTLS);
|
packetSize = cipherSuite.calculatePacketSize(
|
||||||
}
|
negotiatedMaxFragLen, protocolVersion,
|
||||||
|
protocolVersion.isDTLS);
|
||||||
|
}
|
||||||
|
|
||||||
if (maximumPacketSize > 0) {
|
if (maximumPacketSize > 0) {
|
||||||
return (maximumPacketSize > packetSize) ?
|
return (maximumPacketSize > packetSize) ?
|
||||||
maximumPacketSize : packetSize;
|
maximumPacketSize : packetSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packetSize != 0) {
|
if (packetSize != 0) {
|
||||||
return packetSize;
|
return packetSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocolVersion.isDTLS) {
|
if (protocolVersion.isDTLS) {
|
||||||
return DTLSRecord.maxRecordSize;
|
return DTLSRecord.maxRecordSize;
|
||||||
} else {
|
} else {
|
||||||
return acceptLargeFragments ?
|
return acceptLargeFragments ?
|
||||||
SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
|
SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,31 +986,36 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
* expected when using this session.
|
* expected when using this session.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized int getApplicationBufferSize() {
|
public int getApplicationBufferSize() {
|
||||||
// Use the bigger fragment size calculated from maximumPacketSize
|
sessionLock.lock();
|
||||||
// and negotiatedMaxFragLen.
|
try {
|
||||||
int fragmentSize = 0;
|
// Use the bigger fragment size calculated from maximumPacketSize
|
||||||
if (maximumPacketSize > 0) {
|
// and negotiatedMaxFragLen.
|
||||||
fragmentSize = cipherSuite.calculateFragSize(
|
int fragmentSize = 0;
|
||||||
maximumPacketSize, protocolVersion,
|
if (maximumPacketSize > 0) {
|
||||||
protocolVersion.isDTLS);
|
fragmentSize = cipherSuite.calculateFragSize(
|
||||||
}
|
maximumPacketSize, protocolVersion,
|
||||||
|
protocolVersion.isDTLS);
|
||||||
|
}
|
||||||
|
|
||||||
if (negotiatedMaxFragLen > 0) {
|
if (negotiatedMaxFragLen > 0) {
|
||||||
return (negotiatedMaxFragLen > fragmentSize) ?
|
return (negotiatedMaxFragLen > fragmentSize) ?
|
||||||
negotiatedMaxFragLen : fragmentSize;
|
negotiatedMaxFragLen : fragmentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fragmentSize != 0) {
|
if (fragmentSize != 0) {
|
||||||
return fragmentSize;
|
return fragmentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocolVersion.isDTLS) {
|
if (protocolVersion.isDTLS) {
|
||||||
return Record.maxDataSize;
|
return Record.maxDataSize;
|
||||||
} else {
|
} else {
|
||||||
int maxPacketSize = acceptLargeFragments ?
|
int maxPacketSize = acceptLargeFragments ?
|
||||||
SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
|
SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
|
||||||
return (maxPacketSize - SSLRecord.headerSize);
|
return (maxPacketSize - SSLRecord.headerSize);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,10 +1027,14 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
* the negotiated maximum fragment length, or {@code -1} if
|
* the negotiated maximum fragment length, or {@code -1} if
|
||||||
* no such length has been negotiated.
|
* no such length has been negotiated.
|
||||||
*/
|
*/
|
||||||
synchronized void setNegotiatedMaxFragSize(
|
void setNegotiatedMaxFragSize(
|
||||||
int negotiatedMaxFragLen) {
|
int negotiatedMaxFragLen) {
|
||||||
|
sessionLock.lock();
|
||||||
this.negotiatedMaxFragLen = negotiatedMaxFragLen;
|
try {
|
||||||
|
this.negotiatedMaxFragLen = negotiatedMaxFragLen;
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1002,16 +1044,31 @@ final class SSLSessionImpl extends ExtendedSSLSession {
|
|||||||
* @return the negotiated maximum fragment length, or {@code -1} if
|
* @return the negotiated maximum fragment length, or {@code -1} if
|
||||||
* no such length has been negotiated.
|
* no such length has been negotiated.
|
||||||
*/
|
*/
|
||||||
synchronized int getNegotiatedMaxFragSize() {
|
int getNegotiatedMaxFragSize() {
|
||||||
return negotiatedMaxFragLen;
|
sessionLock.lock();
|
||||||
|
try {
|
||||||
|
return negotiatedMaxFragLen;
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void setMaximumPacketSize(int maximumPacketSize) {
|
void setMaximumPacketSize(int maximumPacketSize) {
|
||||||
this.maximumPacketSize = maximumPacketSize;
|
sessionLock.lock();
|
||||||
|
try {
|
||||||
|
this.maximumPacketSize = maximumPacketSize;
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int getMaximumPacketSize() {
|
int getMaximumPacketSize() {
|
||||||
return maximumPacketSize;
|
sessionLock.lock();
|
||||||
|
try {
|
||||||
|
return maximumPacketSize;
|
||||||
|
} finally {
|
||||||
|
sessionLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,6 +38,7 @@ import java.net.SocketException;
|
|||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import javax.net.ssl.HandshakeCompletedListener;
|
import javax.net.ssl.HandshakeCompletedListener;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
@ -84,6 +85,9 @@ public final class SSLSocketImpl
|
|||||||
private boolean isConnected = false;
|
private boolean isConnected = false;
|
||||||
private volatile boolean tlsIsClosed = false;
|
private volatile boolean tlsIsClosed = false;
|
||||||
|
|
||||||
|
private final ReentrantLock socketLock = new ReentrantLock();
|
||||||
|
private final ReentrantLock handshakeLock = new ReentrantLock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is the local name service trustworthy?
|
* Is the local name service trustworthy?
|
||||||
*
|
*
|
||||||
@ -292,14 +296,25 @@ public final class SSLSocketImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String[] getEnabledCipherSuites() {
|
public String[] getEnabledCipherSuites() {
|
||||||
return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites);
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
return CipherSuite.namesOf(
|
||||||
|
conContext.sslConfig.enabledCipherSuites);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setEnabledCipherSuites(String[] suites) {
|
public void setEnabledCipherSuites(String[] suites) {
|
||||||
conContext.sslConfig.enabledCipherSuites =
|
socketLock.lock();
|
||||||
CipherSuite.validValuesOf(suites);
|
try {
|
||||||
|
conContext.sslConfig.enabledCipherSuites =
|
||||||
|
CipherSuite.validValuesOf(suites);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -309,19 +324,29 @@ public final class SSLSocketImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String[] getEnabledProtocols() {
|
public String[] getEnabledProtocols() {
|
||||||
return ProtocolVersion.toStringArray(
|
socketLock.lock();
|
||||||
conContext.sslConfig.enabledProtocols);
|
try {
|
||||||
|
return ProtocolVersion.toStringArray(
|
||||||
|
conContext.sslConfig.enabledProtocols);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setEnabledProtocols(String[] protocols) {
|
public void setEnabledProtocols(String[] protocols) {
|
||||||
if (protocols == null) {
|
if (protocols == null) {
|
||||||
throw new IllegalArgumentException("Protocols cannot be null");
|
throw new IllegalArgumentException("Protocols cannot be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
conContext.sslConfig.enabledProtocols =
|
socketLock.lock();
|
||||||
ProtocolVersion.namesOf(protocols);
|
try {
|
||||||
|
conContext.sslConfig.enabledProtocols =
|
||||||
|
ProtocolVersion.namesOf(protocols);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -341,29 +366,44 @@ public final class SSLSocketImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized SSLSession getHandshakeSession() {
|
public SSLSession getHandshakeSession() {
|
||||||
return conContext.handshakeContext == null ?
|
socketLock.lock();
|
||||||
null : conContext.handshakeContext.handshakeSession;
|
try {
|
||||||
|
return conContext.handshakeContext == null ?
|
||||||
|
null : conContext.handshakeContext.handshakeSession;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void addHandshakeCompletedListener(
|
public void addHandshakeCompletedListener(
|
||||||
HandshakeCompletedListener listener) {
|
HandshakeCompletedListener listener) {
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
throw new IllegalArgumentException("listener is null");
|
throw new IllegalArgumentException("listener is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
conContext.sslConfig.addHandshakeCompletedListener(listener);
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.addHandshakeCompletedListener(listener);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void removeHandshakeCompletedListener(
|
public void removeHandshakeCompletedListener(
|
||||||
HandshakeCompletedListener listener) {
|
HandshakeCompletedListener listener) {
|
||||||
if (listener == null) {
|
if (listener == null) {
|
||||||
throw new IllegalArgumentException("listener is null");
|
throw new IllegalArgumentException("listener is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
conContext.sslConfig.removeHandshakeCompletedListener(listener);
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.removeHandshakeCompletedListener(listener);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -377,7 +417,8 @@ public final class SSLSocketImpl
|
|||||||
throw new SocketException("Socket has been closed or broken");
|
throw new SocketException("Socket has been closed or broken");
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (conContext) { // handshake lock
|
handshakeLock.lock();
|
||||||
|
try {
|
||||||
// double check the context status
|
// double check the context status
|
||||||
if (conContext.isBroken || conContext.isInboundClosed() ||
|
if (conContext.isBroken || conContext.isInboundClosed() ||
|
||||||
conContext.isOutboundClosed()) {
|
conContext.isOutboundClosed()) {
|
||||||
@ -400,53 +441,95 @@ public final class SSLSocketImpl
|
|||||||
} catch (Exception oe) { // including RuntimeException
|
} catch (Exception oe) { // including RuntimeException
|
||||||
handleException(oe);
|
handleException(oe);
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
handshakeLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setUseClientMode(boolean mode) {
|
public void setUseClientMode(boolean mode) {
|
||||||
conContext.setUseClientMode(mode);
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.setUseClientMode(mode);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean getUseClientMode() {
|
public boolean getUseClientMode() {
|
||||||
return conContext.sslConfig.isClientMode;
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.sslConfig.isClientMode;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setNeedClientAuth(boolean need) {
|
public void setNeedClientAuth(boolean need) {
|
||||||
conContext.sslConfig.clientAuthType =
|
socketLock.lock();
|
||||||
(need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
|
try {
|
||||||
ClientAuthType.CLIENT_AUTH_NONE);
|
conContext.sslConfig.clientAuthType =
|
||||||
|
(need ? ClientAuthType.CLIENT_AUTH_REQUIRED :
|
||||||
|
ClientAuthType.CLIENT_AUTH_NONE);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean getNeedClientAuth() {
|
public boolean getNeedClientAuth() {
|
||||||
return (conContext.sslConfig.clientAuthType ==
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
return (conContext.sslConfig.clientAuthType ==
|
||||||
ClientAuthType.CLIENT_AUTH_REQUIRED);
|
ClientAuthType.CLIENT_AUTH_REQUIRED);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setWantClientAuth(boolean want) {
|
public void setWantClientAuth(boolean want) {
|
||||||
conContext.sslConfig.clientAuthType =
|
socketLock.lock();
|
||||||
(want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
|
try {
|
||||||
ClientAuthType.CLIENT_AUTH_NONE);
|
conContext.sslConfig.clientAuthType =
|
||||||
|
(want ? ClientAuthType.CLIENT_AUTH_REQUESTED :
|
||||||
|
ClientAuthType.CLIENT_AUTH_NONE);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean getWantClientAuth() {
|
public boolean getWantClientAuth() {
|
||||||
return (conContext.sslConfig.clientAuthType ==
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
return (conContext.sslConfig.clientAuthType ==
|
||||||
ClientAuthType.CLIENT_AUTH_REQUESTED);
|
ClientAuthType.CLIENT_AUTH_REQUESTED);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setEnableSessionCreation(boolean flag) {
|
public void setEnableSessionCreation(boolean flag) {
|
||||||
conContext.sslConfig.enableSessionCreation = flag;
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.enableSessionCreation = flag;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean getEnableSessionCreation() {
|
public boolean getEnableSessionCreation() {
|
||||||
return conContext.sslConfig.enableSessionCreation;
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.sslConfig.enableSessionCreation;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -535,8 +618,9 @@ public final class SSLSocketImpl
|
|||||||
|
|
||||||
// Need a lock here so that the user_canceled alert and the
|
// Need a lock here so that the user_canceled alert and the
|
||||||
// close_notify alert can be delivered together.
|
// close_notify alert can be delivered together.
|
||||||
|
conContext.outputRecord.recordLock.lock();
|
||||||
try {
|
try {
|
||||||
synchronized (conContext.outputRecord) {
|
try {
|
||||||
// send a user_canceled alert if needed.
|
// send a user_canceled alert if needed.
|
||||||
if (useUserCanceled) {
|
if (useUserCanceled) {
|
||||||
conContext.warning(Alert.USER_CANCELED);
|
conContext.warning(Alert.USER_CANCELED);
|
||||||
@ -544,15 +628,17 @@ public final class SSLSocketImpl
|
|||||||
|
|
||||||
// send a close_notify alert
|
// send a close_notify alert
|
||||||
conContext.warning(Alert.CLOSE_NOTIFY);
|
conContext.warning(Alert.CLOSE_NOTIFY);
|
||||||
|
} finally {
|
||||||
|
if (!conContext.isOutboundClosed()) {
|
||||||
|
conContext.outputRecord.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((autoClose || !isLayered()) && !super.isOutputShutdown()) {
|
||||||
|
super.shutdownOutput();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (!conContext.isOutboundClosed()) {
|
conContext.outputRecord.recordLock.unlock();
|
||||||
conContext.outputRecord.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((autoClose || !isLayered()) && !super.isOutputShutdown()) {
|
|
||||||
super.shutdownOutput();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isInputShutdown()) {
|
if (!isInputShutdown()) {
|
||||||
@ -681,20 +767,25 @@ public final class SSLSocketImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized InputStream getInputStream() throws IOException {
|
public InputStream getInputStream() throws IOException {
|
||||||
if (isClosed()) {
|
socketLock.lock();
|
||||||
throw new SocketException("Socket is closed");
|
try {
|
||||||
}
|
if (isClosed()) {
|
||||||
|
throw new SocketException("Socket is closed");
|
||||||
|
}
|
||||||
|
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
throw new SocketException("Socket is not connected");
|
throw new SocketException("Socket is not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conContext.isInboundClosed() || isInputShutdown()) {
|
if (conContext.isInboundClosed() || isInputShutdown()) {
|
||||||
throw new SocketException("Socket input is already shutdown");
|
throw new SocketException("Socket input is already shutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
return appInput;
|
return appInput;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureNegotiated() throws IOException {
|
private void ensureNegotiated() throws IOException {
|
||||||
@ -703,7 +794,8 @@ public final class SSLSocketImpl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (conContext) { // handshake lock
|
handshakeLock.lock();
|
||||||
|
try {
|
||||||
// double check the context status
|
// double check the context status
|
||||||
if (conContext.isNegotiated || conContext.isBroken ||
|
if (conContext.isNegotiated || conContext.isBroken ||
|
||||||
conContext.isInboundClosed() ||
|
conContext.isInboundClosed() ||
|
||||||
@ -712,6 +804,8 @@ public final class SSLSocketImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
startHandshake();
|
startHandshake();
|
||||||
|
} finally {
|
||||||
|
handshakeLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,6 +823,9 @@ public final class SSLSocketImpl
|
|||||||
// Is application data available in the stream?
|
// Is application data available in the stream?
|
||||||
private volatile boolean appDataIsAvailable;
|
private volatile boolean appDataIsAvailable;
|
||||||
|
|
||||||
|
// reading lock
|
||||||
|
private final ReentrantLock readLock = new ReentrantLock();
|
||||||
|
|
||||||
AppInputStream() {
|
AppInputStream() {
|
||||||
this.appDataIsAvailable = false;
|
this.appDataIsAvailable = false;
|
||||||
this.buffer = ByteBuffer.allocate(4096);
|
this.buffer = ByteBuffer.allocate(4096);
|
||||||
@ -807,7 +904,8 @@ public final class SSLSocketImpl
|
|||||||
//
|
//
|
||||||
// Note that the receiving and processing of post-handshake message
|
// Note that the receiving and processing of post-handshake message
|
||||||
// are also synchronized with the read lock.
|
// are also synchronized with the read lock.
|
||||||
synchronized (this) {
|
readLock.lock();
|
||||||
|
try {
|
||||||
int remains = available();
|
int remains = available();
|
||||||
if (remains > 0) {
|
if (remains > 0) {
|
||||||
int howmany = Math.min(remains, len);
|
int howmany = Math.min(remains, len);
|
||||||
@ -839,6 +937,8 @@ public final class SSLSocketImpl
|
|||||||
// dummy for compiler
|
// dummy for compiler
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -850,19 +950,24 @@ public final class SSLSocketImpl
|
|||||||
* things simpler.
|
* things simpler.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized long skip(long n) throws IOException {
|
public long skip(long n) throws IOException {
|
||||||
// dummy array used to implement skip()
|
// dummy array used to implement skip()
|
||||||
byte[] skipArray = new byte[256];
|
byte[] skipArray = new byte[256];
|
||||||
|
|
||||||
long skipped = 0;
|
long skipped = 0;
|
||||||
while (n > 0) {
|
|
||||||
int len = (int)Math.min(n, skipArray.length);
|
readLock.lock();
|
||||||
int r = read(skipArray, 0, len);
|
try {
|
||||||
if (r <= 0) {
|
while (n > 0) {
|
||||||
break;
|
int len = (int)Math.min(n, skipArray.length);
|
||||||
|
int r = read(skipArray, 0, len);
|
||||||
|
if (r <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n -= r;
|
||||||
|
skipped += r;
|
||||||
}
|
}
|
||||||
n -= r;
|
} finally {
|
||||||
skipped += r;
|
readLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return skipped;
|
return skipped;
|
||||||
@ -910,8 +1015,18 @@ public final class SSLSocketImpl
|
|||||||
* Try the best to use up the input records so as to close the
|
* Try the best to use up the input records so as to close the
|
||||||
* socket gracefully, without impact the performance too much.
|
* socket gracefully, without impact the performance too much.
|
||||||
*/
|
*/
|
||||||
private synchronized void deplete() {
|
private void deplete() {
|
||||||
if (!conContext.isInboundClosed()) {
|
if (conContext.isInboundClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
// double check
|
||||||
|
if (conContext.isInboundClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) {
|
if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -927,25 +1042,32 @@ public final class SSLSocketImpl
|
|||||||
"input stream close depletion failed", ioe);
|
"input stream close depletion failed", ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized OutputStream getOutputStream() throws IOException {
|
public OutputStream getOutputStream() throws IOException {
|
||||||
if (isClosed()) {
|
socketLock.lock();
|
||||||
throw new SocketException("Socket is closed");
|
try {
|
||||||
}
|
if (isClosed()) {
|
||||||
|
throw new SocketException("Socket is closed");
|
||||||
|
}
|
||||||
|
|
||||||
if (!isConnected) {
|
if (!isConnected) {
|
||||||
throw new SocketException("Socket is not connected");
|
throw new SocketException("Socket is not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (conContext.isOutboundDone() || isOutputShutdown()) {
|
if (conContext.isOutboundDone() || isOutputShutdown()) {
|
||||||
throw new SocketException("Socket output is already shutdown");
|
throw new SocketException("Socket output is already shutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
return appOutput;
|
return appOutput;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1035,44 +1157,74 @@ public final class SSLSocketImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized SSLParameters getSSLParameters() {
|
public SSLParameters getSSLParameters() {
|
||||||
return conContext.sslConfig.getSSLParameters();
|
socketLock.lock();
|
||||||
}
|
try {
|
||||||
|
return conContext.sslConfig.getSSLParameters();
|
||||||
@Override
|
} finally {
|
||||||
public synchronized void setSSLParameters(SSLParameters params) {
|
socketLock.unlock();
|
||||||
conContext.sslConfig.setSSLParameters(params);
|
|
||||||
|
|
||||||
if (conContext.sslConfig.maximumPacketSize != 0) {
|
|
||||||
conContext.outputRecord.changePacketSize(
|
|
||||||
conContext.sslConfig.maximumPacketSize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String getApplicationProtocol() {
|
public void setSSLParameters(SSLParameters params) {
|
||||||
return conContext.applicationProtocol;
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.setSSLParameters(params);
|
||||||
|
|
||||||
|
if (conContext.sslConfig.maximumPacketSize != 0) {
|
||||||
|
conContext.outputRecord.changePacketSize(
|
||||||
|
conContext.sslConfig.maximumPacketSize);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized String getHandshakeApplicationProtocol() {
|
public String getApplicationProtocol() {
|
||||||
if (conContext.handshakeContext != null) {
|
socketLock.lock();
|
||||||
return conContext.handshakeContext.applicationProtocol;
|
try {
|
||||||
|
return conContext.applicationProtocol;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHandshakeApplicationProtocol() {
|
||||||
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
if (conContext.handshakeContext != null) {
|
||||||
|
return conContext.handshakeContext.applicationProtocol;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void setHandshakeApplicationProtocolSelector(
|
public void setHandshakeApplicationProtocolSelector(
|
||||||
BiFunction<SSLSocket, List<String>, String> selector) {
|
BiFunction<SSLSocket, List<String>, String> selector) {
|
||||||
conContext.sslConfig.socketAPSelector = selector;
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
conContext.sslConfig.socketAPSelector = selector;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized BiFunction<SSLSocket, List<String>, String>
|
public BiFunction<SSLSocket, List<String>, String>
|
||||||
getHandshakeApplicationProtocolSelector() {
|
getHandshakeApplicationProtocolSelector() {
|
||||||
return conContext.sslConfig.socketAPSelector;
|
socketLock.lock();
|
||||||
|
try {
|
||||||
|
return conContext.sslConfig.socketAPSelector;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1142,8 +1294,11 @@ public final class SSLSocketImpl
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
Plaintext plainText;
|
Plaintext plainText;
|
||||||
synchronized (this) {
|
socketLock.lock();
|
||||||
|
try {
|
||||||
plainText = decode(buffer);
|
plainText = decode(buffer);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
}
|
}
|
||||||
if (plainText.contentType == ContentType.APPLICATION_DATA.id &&
|
if (plainText.contentType == ContentType.APPLICATION_DATA.id &&
|
||||||
buffer.position() > 0) {
|
buffer.position() > 0) {
|
||||||
@ -1222,27 +1377,33 @@ public final class SSLSocketImpl
|
|||||||
*
|
*
|
||||||
* Called by connect, the layered constructor, and SSLServerSocket.
|
* Called by connect, the layered constructor, and SSLServerSocket.
|
||||||
*/
|
*/
|
||||||
synchronized void doneConnect() throws IOException {
|
void doneConnect() throws IOException {
|
||||||
// In server mode, it is not necessary to set host and serverNames.
|
socketLock.lock();
|
||||||
// Otherwise, would require a reverse DNS lookup to get the hostname.
|
try {
|
||||||
if (peerHost == null || peerHost.isEmpty()) {
|
// In server mode, it is not necessary to set host and serverNames.
|
||||||
boolean useNameService =
|
// Otherwise, would require a reverse DNS lookup to get
|
||||||
trustNameService && conContext.sslConfig.isClientMode;
|
// the hostname.
|
||||||
useImplicitHost(useNameService);
|
if (peerHost == null || peerHost.isEmpty()) {
|
||||||
} else {
|
boolean useNameService =
|
||||||
conContext.sslConfig.serverNames =
|
trustNameService && conContext.sslConfig.isClientMode;
|
||||||
Utilities.addToSNIServerNameList(
|
useImplicitHost(useNameService);
|
||||||
conContext.sslConfig.serverNames, peerHost);
|
} else {
|
||||||
|
conContext.sslConfig.serverNames =
|
||||||
|
Utilities.addToSNIServerNameList(
|
||||||
|
conContext.sslConfig.serverNames, peerHost);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream sockInput = super.getInputStream();
|
||||||
|
conContext.inputRecord.setReceiverStream(sockInput);
|
||||||
|
|
||||||
|
OutputStream sockOutput = super.getOutputStream();
|
||||||
|
conContext.inputRecord.setDeliverStream(sockOutput);
|
||||||
|
conContext.outputRecord.setDeliverStream(sockOutput);
|
||||||
|
|
||||||
|
this.isConnected = true;
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
InputStream sockInput = super.getInputStream();
|
|
||||||
conContext.inputRecord.setReceiverStream(sockInput);
|
|
||||||
|
|
||||||
OutputStream sockOutput = super.getOutputStream();
|
|
||||||
conContext.inputRecord.setDeliverStream(sockOutput);
|
|
||||||
conContext.outputRecord.setDeliverStream(sockOutput);
|
|
||||||
|
|
||||||
this.isConnected = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void useImplicitHost(boolean useNameService) {
|
private void useImplicitHost(boolean useNameService) {
|
||||||
@ -1288,11 +1449,16 @@ public final class SSLSocketImpl
|
|||||||
// Please NOTE that this method MUST be called before calling to
|
// Please NOTE that this method MUST be called before calling to
|
||||||
// SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter
|
// SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter
|
||||||
// may override SNIHostName in the customized server name indication.
|
// may override SNIHostName in the customized server name indication.
|
||||||
public synchronized void setHost(String host) {
|
public void setHost(String host) {
|
||||||
this.peerHost = host;
|
socketLock.lock();
|
||||||
this.conContext.sslConfig.serverNames =
|
try {
|
||||||
Utilities.addToSNIServerNameList(
|
this.peerHost = host;
|
||||||
conContext.sslConfig.serverNames, host);
|
this.conContext.sslConfig.serverNames =
|
||||||
|
Utilities.addToSNIServerNameList(
|
||||||
|
conContext.sslConfig.serverNames, host);
|
||||||
|
} finally {
|
||||||
|
socketLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -51,123 +51,206 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
synchronized void encodeAlert(
|
void encodeAlert(byte level, byte description) throws IOException {
|
||||||
byte level, byte description) throws IOException {
|
recordLock.lock();
|
||||||
if (isClosed()) {
|
try {
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
if (isClosed()) {
|
||||||
SSLLogger.warning("outbound has closed, ignore outbound " +
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
"alert message: " + Alert.nameOf(description));
|
SSLLogger.warning("outbound has closed, ignore outbound " +
|
||||||
|
"alert message: " + Alert.nameOf(description));
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
|
// use the buf of ByteArrayOutputStream
|
||||||
|
int position = headerSize + writeCipher.getExplicitNonceSize();
|
||||||
|
count = position;
|
||||||
|
|
||||||
|
write(level);
|
||||||
|
write(description);
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
||||||
|
SSLLogger.fine("WRITE: " + protocolVersion +
|
||||||
|
" " + ContentType.ALERT.name +
|
||||||
|
"(" + Alert.nameOf(description) + ")" +
|
||||||
|
", length = " + (count - headerSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the fragment and wrap up a record.
|
||||||
|
encrypt(writeCipher, ContentType.ALERT.id, headerSize);
|
||||||
|
|
||||||
|
// deliver this message
|
||||||
|
deliverStream.write(buf, 0, count); // may throw IOException
|
||||||
|
deliverStream.flush(); // may throw IOException
|
||||||
|
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
||||||
|
SSLLogger.fine("Raw write",
|
||||||
|
(new ByteArrayInputStream(buf, 0, count)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the internal buffer
|
||||||
|
count = 0;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// use the buf of ByteArrayOutputStream
|
|
||||||
int position = headerSize + writeCipher.getExplicitNonceSize();
|
|
||||||
count = position;
|
|
||||||
|
|
||||||
write(level);
|
|
||||||
write(description);
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
|
||||||
SSLLogger.fine("WRITE: " + protocolVersion +
|
|
||||||
" " + ContentType.ALERT.name +
|
|
||||||
"(" + Alert.nameOf(description) + ")" +
|
|
||||||
", length = " + (count - headerSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt the fragment and wrap up a record.
|
|
||||||
encrypt(writeCipher, ContentType.ALERT.id, headerSize);
|
|
||||||
|
|
||||||
// deliver this message
|
|
||||||
deliverStream.write(buf, 0, count); // may throw IOException
|
|
||||||
deliverStream.flush(); // may throw IOException
|
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
|
||||||
SSLLogger.fine("Raw write",
|
|
||||||
(new ByteArrayInputStream(buf, 0, count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the internal buffer
|
|
||||||
count = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
synchronized void encodeHandshake(byte[] source,
|
void encodeHandshake(byte[] source,
|
||||||
int offset, int length) throws IOException {
|
int offset, int length) throws IOException {
|
||||||
if (isClosed()) {
|
recordLock.lock();
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
try {
|
||||||
SSLLogger.warning("outbound has closed, ignore outbound " +
|
if (isClosed()) {
|
||||||
"handshake message",
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
ByteBuffer.wrap(source, offset, length));
|
SSLLogger.warning("outbound has closed, ignore outbound " +
|
||||||
|
"handshake message",
|
||||||
|
ByteBuffer.wrap(source, offset, length));
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (firstMessage) {
|
if (firstMessage) {
|
||||||
firstMessage = false;
|
firstMessage = false;
|
||||||
|
|
||||||
if ((helloVersion == ProtocolVersion.SSL20Hello) &&
|
if ((helloVersion == ProtocolVersion.SSL20Hello) &&
|
||||||
(source[offset] == SSLHandshake.CLIENT_HELLO.id) &&
|
(source[offset] == SSLHandshake.CLIENT_HELLO.id) &&
|
||||||
// 5: recode header size
|
// 5: recode header size
|
||||||
(source[offset + 4 + 2 + 32] == 0)) {
|
(source[offset + 4 + 2 + 32] == 0)) {
|
||||||
// V3 session ID is empty
|
// V3 session ID is empty
|
||||||
// 4: handshake header size
|
// 4: handshake header size
|
||||||
// 2: client_version in ClientHello
|
// 2: client_version in ClientHello
|
||||||
// 32: random in ClientHello
|
// 32: random in ClientHello
|
||||||
|
|
||||||
ByteBuffer v2ClientHello = encodeV2ClientHello(
|
ByteBuffer v2ClientHello = encodeV2ClientHello(
|
||||||
source, (offset + 4), (length - 4));
|
source, (offset + 4), (length - 4));
|
||||||
|
|
||||||
byte[] record = v2ClientHello.array(); // array offset is zero
|
// array offset is zero
|
||||||
int limit = v2ClientHello.limit();
|
byte[] record = v2ClientHello.array();
|
||||||
handshakeHash.deliver(record, 2, (limit - 2));
|
int limit = v2ClientHello.limit();
|
||||||
|
handshakeHash.deliver(record, 2, (limit - 2));
|
||||||
|
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
||||||
|
SSLLogger.fine(
|
||||||
|
"WRITE: SSLv2 ClientHello message" +
|
||||||
|
", length = " + limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deliver this message
|
||||||
|
//
|
||||||
|
// Version 2 ClientHello message should be plaintext.
|
||||||
|
//
|
||||||
|
// No max fragment length negotiation.
|
||||||
|
deliverStream.write(record, 0, limit);
|
||||||
|
deliverStream.flush();
|
||||||
|
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
||||||
|
SSLLogger.fine("Raw write",
|
||||||
|
(new ByteArrayInputStream(record, 0, limit)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte handshakeType = source[0];
|
||||||
|
if (handshakeHash.isHashable(handshakeType)) {
|
||||||
|
handshakeHash.deliver(source, offset, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fragLimit = getFragLimit();
|
||||||
|
int position = headerSize + writeCipher.getExplicitNonceSize();
|
||||||
|
if (count == 0) {
|
||||||
|
count = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((count - position) < (fragLimit - length)) {
|
||||||
|
write(source, offset, length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int limit = (offset + length); offset < limit;) {
|
||||||
|
|
||||||
|
int remains = (limit - offset) + (count - position);
|
||||||
|
int fragLen = Math.min(fragLimit, remains);
|
||||||
|
|
||||||
|
// use the buf of ByteArrayOutputStream
|
||||||
|
write(source, offset, fragLen);
|
||||||
|
if (remains < fragLimit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
||||||
SSLLogger.fine(
|
SSLLogger.fine(
|
||||||
"WRITE: SSLv2 ClientHello message" +
|
"WRITE: " + protocolVersion +
|
||||||
", length = " + limit);
|
" " + ContentType.HANDSHAKE.name +
|
||||||
|
", length = " + (count - headerSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encrypt the fragment and wrap up a record.
|
||||||
|
encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
|
||||||
|
|
||||||
// deliver this message
|
// deliver this message
|
||||||
//
|
deliverStream.write(buf, 0, count); // may throw IOException
|
||||||
// Version 2 ClientHello message should be plaintext.
|
deliverStream.flush(); // may throw IOException
|
||||||
//
|
|
||||||
// No max fragment length negotiation.
|
|
||||||
deliverStream.write(record, 0, limit);
|
|
||||||
deliverStream.flush();
|
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
||||||
SSLLogger.fine("Raw write",
|
SSLLogger.fine("Raw write",
|
||||||
(new ByteArrayInputStream(record, 0, limit)));
|
(new ByteArrayInputStream(buf, 0, count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reset the offset
|
||||||
|
offset += fragLen;
|
||||||
|
|
||||||
|
// reset the internal buffer
|
||||||
|
count = position;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void encodeChangeCipherSpec() throws IOException {
|
||||||
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
if (isClosed()) {
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
|
SSLLogger.warning("outbound has closed, ignore outbound " +
|
||||||
|
"change_cipher_spec message");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
byte handshakeType = source[0];
|
|
||||||
if (handshakeHash.isHashable(handshakeType)) {
|
|
||||||
handshakeHash.deliver(source, offset, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fragLimit = getFragLimit();
|
|
||||||
int position = headerSize + writeCipher.getExplicitNonceSize();
|
|
||||||
if (count == 0) {
|
|
||||||
count = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((count - position) < (fragLimit - length)) {
|
|
||||||
write(source, offset, length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int limit = (offset + length); offset < limit;) {
|
|
||||||
|
|
||||||
int remains = (limit - offset) + (count - position);
|
|
||||||
int fragLen = Math.min(fragLimit, remains);
|
|
||||||
|
|
||||||
// use the buf of ByteArrayOutputStream
|
// use the buf of ByteArrayOutputStream
|
||||||
write(source, offset, fragLen);
|
int position = headerSize + writeCipher.getExplicitNonceSize();
|
||||||
if (remains < fragLimit) {
|
count = position;
|
||||||
|
|
||||||
|
write((byte)1); // byte 1: change_cipher_spec(
|
||||||
|
|
||||||
|
// Encrypt the fragment and wrap up a record.
|
||||||
|
encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize);
|
||||||
|
|
||||||
|
// deliver this message
|
||||||
|
deliverStream.write(buf, 0, count); // may throw IOException
|
||||||
|
// deliverStream.flush(); // flush in Finished
|
||||||
|
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
||||||
|
SSLLogger.fine("Raw write",
|
||||||
|
(new ByteArrayInputStream(buf, 0, count)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the internal buffer
|
||||||
|
count = 0;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
int position = headerSize + writeCipher.getExplicitNonceSize();
|
||||||
|
if (count <= position) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,155 +273,103 @@ final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord {
|
|||||||
(new ByteArrayInputStream(buf, 0, count)));
|
(new ByteArrayInputStream(buf, 0, count)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset the offset
|
|
||||||
offset += fragLen;
|
|
||||||
|
|
||||||
// reset the internal buffer
|
// reset the internal buffer
|
||||||
count = position;
|
count = 0; // DON'T use position
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
synchronized void encodeChangeCipherSpec() throws IOException {
|
void deliver(byte[] source, int offset, int length) throws IOException {
|
||||||
if (isClosed()) {
|
recordLock.lock();
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
try {
|
||||||
SSLLogger.warning("outbound has closed, ignore outbound " +
|
if (isClosed()) {
|
||||||
"change_cipher_spec message");
|
throw new SocketException(
|
||||||
}
|
"Connection or outbound has been closed");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the buf of ByteArrayOutputStream
|
|
||||||
int position = headerSize + writeCipher.getExplicitNonceSize();
|
|
||||||
count = position;
|
|
||||||
|
|
||||||
write((byte)1); // byte 1: change_cipher_spec(
|
|
||||||
|
|
||||||
// Encrypt the fragment and wrap up a record.
|
|
||||||
encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize);
|
|
||||||
|
|
||||||
// deliver this message
|
|
||||||
deliverStream.write(buf, 0, count); // may throw IOException
|
|
||||||
// deliverStream.flush(); // flush in Finished
|
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
|
||||||
SSLLogger.fine("Raw write",
|
|
||||||
(new ByteArrayInputStream(buf, 0, count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the internal buffer
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized void flush() throws IOException {
|
|
||||||
int position = headerSize + writeCipher.getExplicitNonceSize();
|
|
||||||
if (count <= position) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
|
||||||
SSLLogger.fine(
|
|
||||||
"WRITE: " + protocolVersion +
|
|
||||||
" " + ContentType.HANDSHAKE.name +
|
|
||||||
", length = " + (count - headerSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt the fragment and wrap up a record.
|
|
||||||
encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize);
|
|
||||||
|
|
||||||
// deliver this message
|
|
||||||
deliverStream.write(buf, 0, count); // may throw IOException
|
|
||||||
deliverStream.flush(); // may throw IOException
|
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
|
||||||
SSLLogger.fine("Raw write",
|
|
||||||
(new ByteArrayInputStream(buf, 0, count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the internal buffer
|
|
||||||
count = 0; // DON'T use position
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
synchronized void deliver(
|
|
||||||
byte[] source, int offset, int length) throws IOException {
|
|
||||||
if (isClosed()) {
|
|
||||||
throw new SocketException("Connection or outbound has been closed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (writeCipher.authenticator.seqNumOverflow()) {
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
|
||||||
SSLLogger.fine(
|
|
||||||
"sequence number extremely close to overflow " +
|
|
||||||
"(2^64-1 packets). Closing connection.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new SSLHandshakeException("sequence number overflow");
|
if (writeCipher.authenticator.seqNumOverflow()) {
|
||||||
}
|
if (SSLLogger.isOn && SSLLogger.isOn("ssl")) {
|
||||||
|
SSLLogger.fine(
|
||||||
|
"sequence number extremely close to overflow " +
|
||||||
|
"(2^64-1 packets). Closing connection.");
|
||||||
|
}
|
||||||
|
|
||||||
boolean isFirstRecordOfThePayload = true;
|
throw new SSLHandshakeException("sequence number overflow");
|
||||||
for (int limit = (offset + length); offset < limit;) {
|
|
||||||
int fragLen;
|
|
||||||
if (packetSize > 0) {
|
|
||||||
fragLen = Math.min(maxRecordSize, packetSize);
|
|
||||||
fragLen =
|
|
||||||
writeCipher.calculateFragmentSize(fragLen, headerSize);
|
|
||||||
|
|
||||||
fragLen = Math.min(fragLen, Record.maxDataSize);
|
|
||||||
} else {
|
|
||||||
fragLen = Record.maxDataSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fragmentSize > 0) {
|
boolean isFirstRecordOfThePayload = true;
|
||||||
fragLen = Math.min(fragLen, fragmentSize);
|
for (int limit = (offset + length); offset < limit;) {
|
||||||
|
int fragLen;
|
||||||
|
if (packetSize > 0) {
|
||||||
|
fragLen = Math.min(maxRecordSize, packetSize);
|
||||||
|
fragLen = writeCipher.calculateFragmentSize(
|
||||||
|
fragLen, headerSize);
|
||||||
|
|
||||||
|
fragLen = Math.min(fragLen, Record.maxDataSize);
|
||||||
|
} else {
|
||||||
|
fragLen = Record.maxDataSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fragmentSize > 0) {
|
||||||
|
fragLen = Math.min(fragLen, fragmentSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFirstRecordOfThePayload && needToSplitPayload()) {
|
||||||
|
fragLen = 1;
|
||||||
|
isFirstRecordOfThePayload = false;
|
||||||
|
} else {
|
||||||
|
fragLen = Math.min(fragLen, (limit - offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the buf of ByteArrayOutputStream
|
||||||
|
int position = headerSize + writeCipher.getExplicitNonceSize();
|
||||||
|
count = position;
|
||||||
|
write(source, offset, fragLen);
|
||||||
|
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
||||||
|
SSLLogger.fine(
|
||||||
|
"WRITE: " + protocolVersion +
|
||||||
|
" " + ContentType.APPLICATION_DATA.name +
|
||||||
|
", length = " + (count - position));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the fragment and wrap up a record.
|
||||||
|
encrypt(writeCipher,
|
||||||
|
ContentType.APPLICATION_DATA.id, headerSize);
|
||||||
|
|
||||||
|
// deliver this message
|
||||||
|
deliverStream.write(buf, 0, count); // may throw IOException
|
||||||
|
deliverStream.flush(); // may throw IOException
|
||||||
|
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
||||||
|
SSLLogger.fine("Raw write",
|
||||||
|
(new ByteArrayInputStream(buf, 0, count)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset the internal buffer
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
if (isFirstAppOutputRecord) {
|
||||||
|
isFirstAppOutputRecord = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += fragLen;
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
if (isFirstRecordOfThePayload && needToSplitPayload()) {
|
recordLock.unlock();
|
||||||
fragLen = 1;
|
|
||||||
isFirstRecordOfThePayload = false;
|
|
||||||
} else {
|
|
||||||
fragLen = Math.min(fragLen, (limit - offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
// use the buf of ByteArrayOutputStream
|
|
||||||
int position = headerSize + writeCipher.getExplicitNonceSize();
|
|
||||||
count = position;
|
|
||||||
write(source, offset, fragLen);
|
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("record")) {
|
|
||||||
SSLLogger.fine(
|
|
||||||
"WRITE: " + protocolVersion +
|
|
||||||
" " + ContentType.APPLICATION_DATA.name +
|
|
||||||
", length = " + (count - position));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encrypt the fragment and wrap up a record.
|
|
||||||
encrypt(writeCipher, ContentType.APPLICATION_DATA.id, headerSize);
|
|
||||||
|
|
||||||
// deliver this message
|
|
||||||
deliverStream.write(buf, 0, count); // may throw IOException
|
|
||||||
deliverStream.flush(); // may throw IOException
|
|
||||||
|
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("packet")) {
|
|
||||||
SSLLogger.fine("Raw write",
|
|
||||||
(new ByteArrayInputStream(buf, 0, count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the internal buffer
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
if (isFirstAppOutputRecord) {
|
|
||||||
isFirstAppOutputRecord = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += fragLen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
synchronized void setDeliverStream(OutputStream outputStream) {
|
void setDeliverStream(OutputStream outputStream) {
|
||||||
this.deliverStream = outputStream;
|
recordLock.lock();
|
||||||
|
try {
|
||||||
|
this.deliverStream = outputStream;
|
||||||
|
} finally {
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -102,25 +102,21 @@ final class SunX509KeyManagerImpl extends X509ExtendedKeyManager {
|
|||||||
* Basic container for credentials implemented as an inner class.
|
* Basic container for credentials implemented as an inner class.
|
||||||
*/
|
*/
|
||||||
private static class X509Credentials {
|
private static class X509Credentials {
|
||||||
PrivateKey privateKey;
|
final PrivateKey privateKey;
|
||||||
X509Certificate[] certificates;
|
final X509Certificate[] certificates;
|
||||||
private Set<X500Principal> issuerX500Principals;
|
private final Set<X500Principal> issuerX500Principals;
|
||||||
|
|
||||||
X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) {
|
X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) {
|
||||||
// assert privateKey and certificates != null
|
// assert privateKey and certificates != null
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
this.certificates = certificates;
|
this.certificates = certificates;
|
||||||
|
this.issuerX500Principals = new HashSet<>(certificates.length);
|
||||||
|
for (X509Certificate certificate : certificates) {
|
||||||
|
issuerX500Principals.add(certificate.getIssuerX500Principal());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized Set<X500Principal> getIssuerX500Principals() {
|
Set<X500Principal> getIssuerX500Principals() {
|
||||||
// lazy initialization
|
|
||||||
if (issuerX500Principals == null) {
|
|
||||||
issuerX500Principals = new HashSet<X500Principal>();
|
|
||||||
for (int i = 0; i < certificates.length; i++) {
|
|
||||||
issuerX500Principals.add(
|
|
||||||
certificates[i].getIssuerX500Principal());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return issuerX500Principals;
|
return issuerX500Principals;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -496,13 +496,16 @@ class TransportContext implements ConnectionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needCloseNotify) {
|
if (needCloseNotify) {
|
||||||
synchronized (outputRecord) {
|
outputRecord.recordLock.lock();
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
// send a close_notify alert
|
// send a close_notify alert
|
||||||
warning(Alert.CLOSE_NOTIFY);
|
warning(Alert.CLOSE_NOTIFY);
|
||||||
} finally {
|
} finally {
|
||||||
outputRecord.close();
|
outputRecord.close();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
outputRecord.recordLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -541,7 +544,8 @@ class TransportContext implements ConnectionContext {
|
|||||||
|
|
||||||
// Need a lock here so that the user_canceled alert and the
|
// Need a lock here so that the user_canceled alert and the
|
||||||
// close_notify alert can be delivered together.
|
// close_notify alert can be delivered together.
|
||||||
synchronized (outputRecord) {
|
outputRecord.recordLock.lock();
|
||||||
|
try {
|
||||||
try {
|
try {
|
||||||
// send a user_canceled alert if needed.
|
// send a user_canceled alert if needed.
|
||||||
if (useUserCanceled) {
|
if (useUserCanceled) {
|
||||||
@ -553,6 +557,8 @@ class TransportContext implements ConnectionContext {
|
|||||||
} finally {
|
} finally {
|
||||||
outputRecord.close();
|
outputRecord.close();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
outputRecord.recordLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ import java.lang.ref.WeakReference;
|
|||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import sun.security.action.*;
|
import sun.security.action.*;
|
||||||
import sun.security.validator.TrustStoreUtil;
|
import sun.security.validator.TrustStoreUtil;
|
||||||
|
|
||||||
@ -244,6 +245,8 @@ final class TrustStoreManager {
|
|||||||
// objects can be atomically cleared, and reloaded if needed.
|
// objects can be atomically cleared, and reloaded if needed.
|
||||||
private WeakReference<Set<X509Certificate>> csRef;
|
private WeakReference<Set<X509Certificate>> csRef;
|
||||||
|
|
||||||
|
private final ReentrantLock tamLock = new ReentrantLock();
|
||||||
|
|
||||||
private TrustAnchorManager() {
|
private TrustAnchorManager() {
|
||||||
this.descriptor = null;
|
this.descriptor = null;
|
||||||
this.ksRef = new WeakReference<>(null);
|
this.ksRef = new WeakReference<>(null);
|
||||||
@ -255,7 +258,7 @@ final class TrustStoreManager {
|
|||||||
*
|
*
|
||||||
* @return null if the underlying KeyStore is not available.
|
* @return null if the underlying KeyStore is not available.
|
||||||
*/
|
*/
|
||||||
synchronized KeyStore getKeyStore(
|
KeyStore getKeyStore(
|
||||||
TrustStoreDescriptor descriptor) throws Exception {
|
TrustStoreDescriptor descriptor) throws Exception {
|
||||||
|
|
||||||
TrustStoreDescriptor temporaryDesc = this.descriptor;
|
TrustStoreDescriptor temporaryDesc = this.descriptor;
|
||||||
@ -264,14 +267,25 @@ final class TrustStoreManager {
|
|||||||
return ks;
|
return ks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload a new key store.
|
tamLock.lock();
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
try {
|
||||||
SSLLogger.fine("Reload the trust store");
|
// double check
|
||||||
}
|
ks = ksRef.get();
|
||||||
|
if ((ks != null) && descriptor.equals(temporaryDesc)) {
|
||||||
|
return ks;
|
||||||
|
}
|
||||||
|
|
||||||
ks = loadKeyStore(descriptor);
|
// Reload a new key store.
|
||||||
this.descriptor = descriptor;
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
||||||
this.ksRef = new WeakReference<>(ks);
|
SSLLogger.fine("Reload the trust store");
|
||||||
|
}
|
||||||
|
|
||||||
|
ks = loadKeyStore(descriptor);
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
this.ksRef = new WeakReference<>(ks);
|
||||||
|
} finally {
|
||||||
|
tamLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
return ks;
|
return ks;
|
||||||
}
|
}
|
||||||
@ -282,51 +296,62 @@ final class TrustStoreManager {
|
|||||||
*
|
*
|
||||||
* @return empty collection if the underlying KeyStore is not available.
|
* @return empty collection if the underlying KeyStore is not available.
|
||||||
*/
|
*/
|
||||||
synchronized Set<X509Certificate> getTrustedCerts(
|
Set<X509Certificate> getTrustedCerts(
|
||||||
TrustStoreDescriptor descriptor) throws Exception {
|
TrustStoreDescriptor descriptor) throws Exception {
|
||||||
|
|
||||||
KeyStore ks = null;
|
KeyStore ks = null;
|
||||||
TrustStoreDescriptor temporaryDesc = this.descriptor;
|
TrustStoreDescriptor temporaryDesc = this.descriptor;
|
||||||
Set<X509Certificate> certs = csRef.get();
|
Set<X509Certificate> certs = csRef.get();
|
||||||
if (certs != null) {
|
if ((certs != null) && descriptor.equals(temporaryDesc)) {
|
||||||
if (descriptor.equals(temporaryDesc)) {
|
return certs;
|
||||||
return certs;
|
|
||||||
} else {
|
|
||||||
// Use the new descriptor.
|
|
||||||
this.descriptor = descriptor;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Try to use the cached store at first.
|
|
||||||
if (descriptor.equals(temporaryDesc)) {
|
|
||||||
ks = ksRef.get();
|
|
||||||
} else {
|
|
||||||
// Use the new descriptor.
|
|
||||||
this.descriptor = descriptor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reload the trust store if needed.
|
tamLock.lock();
|
||||||
if (ks == null) {
|
try {
|
||||||
|
// double check
|
||||||
|
temporaryDesc = this.descriptor;
|
||||||
|
certs = csRef.get();
|
||||||
|
if (certs != null) {
|
||||||
|
if (descriptor.equals(temporaryDesc)) {
|
||||||
|
return certs;
|
||||||
|
} else {
|
||||||
|
// Use the new descriptor.
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Try to use the cached store at first.
|
||||||
|
if (descriptor.equals(temporaryDesc)) {
|
||||||
|
ks = ksRef.get();
|
||||||
|
} else {
|
||||||
|
// Use the new descriptor.
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload the trust store if needed.
|
||||||
|
if (ks == null) {
|
||||||
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
||||||
|
SSLLogger.fine("Reload the trust store");
|
||||||
|
}
|
||||||
|
ks = loadKeyStore(descriptor);
|
||||||
|
this.ksRef = new WeakReference<>(ks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload trust certs from the key store.
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
||||||
SSLLogger.fine("Reload the trust store");
|
SSLLogger.fine("Reload trust certs");
|
||||||
}
|
}
|
||||||
ks = loadKeyStore(descriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload trust certs from the key store.
|
certs = loadTrustedCerts(ks);
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
||||||
SSLLogger.fine("Reload trust certs");
|
SSLLogger.fine("Reloaded " + certs.size() + " trust certs");
|
||||||
}
|
}
|
||||||
|
|
||||||
certs = loadTrustedCerts(ks);
|
this.csRef = new WeakReference<>(certs);
|
||||||
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
|
} finally {
|
||||||
SSLLogger.fine("Reloaded " + certs.size() + " trust certs");
|
tamLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that as ks is a local variable, it is not
|
|
||||||
// necessary to add it to the ksRef weak reference.
|
|
||||||
this.csRef = new WeakReference<>(certs);
|
|
||||||
|
|
||||||
return certs;
|
return certs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import java.net.Socket;
|
|||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.cert.*;
|
import java.security.cert.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
import sun.security.util.AnchorCertificates;
|
import sun.security.util.AnchorCertificates;
|
||||||
import sun.security.util.HostnameChecker;
|
import sun.security.util.HostnameChecker;
|
||||||
@ -63,6 +64,8 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
// the different extension checks. They are initialized lazily on demand.
|
// the different extension checks. They are initialized lazily on demand.
|
||||||
private volatile Validator clientValidator, serverValidator;
|
private volatile Validator clientValidator, serverValidator;
|
||||||
|
|
||||||
|
private final ReentrantLock validatorLock = new ReentrantLock();
|
||||||
|
|
||||||
X509TrustManagerImpl(String validatorType,
|
X509TrustManagerImpl(String validatorType,
|
||||||
Collection<X509Certificate> trustedCerts) {
|
Collection<X509Certificate> trustedCerts) {
|
||||||
|
|
||||||
@ -157,12 +160,15 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
if (isClient) {
|
if (isClient) {
|
||||||
v = clientValidator;
|
v = clientValidator;
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
synchronized (this) {
|
validatorLock.lock();
|
||||||
|
try {
|
||||||
v = clientValidator;
|
v = clientValidator;
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
v = getValidator(Validator.VAR_TLS_CLIENT);
|
v = getValidator(Validator.VAR_TLS_CLIENT);
|
||||||
clientValidator = v;
|
clientValidator = v;
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
validatorLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -170,12 +176,15 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
|
|||||||
// (guaranteed under the new Tiger memory model)
|
// (guaranteed under the new Tiger memory model)
|
||||||
v = serverValidator;
|
v = serverValidator;
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
synchronized (this) {
|
validatorLock.lock();
|
||||||
|
try {
|
||||||
v = serverValidator;
|
v = serverValidator;
|
||||||
if (v == null) {
|
if (v == null) {
|
||||||
v = getValidator(Validator.VAR_TLS_SERVER);
|
v = getValidator(Validator.VAR_TLS_SERVER);
|
||||||
serverValidator = v;
|
serverValidator = v;
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
validatorLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user