package sun.security.ssl;
import java.io.FileInputStream;
import java.net.Socket;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import javax.net.ssl.*;
import sun.security.action.GetPropertyAction;
import sun.security.provider.certpath.AlgorithmChecker;
import sun.security.validator.Validator;
public abstract class SSLContextImpl extends SSLContextSpi {
private final EphemeralKeyManager ephemeralKeyManager;
private final SSLSessionContextImpl clientCache;
private final SSLSessionContextImpl serverCache;
private boolean isInitialized;
private X509ExtendedKeyManager keyManager;
private X509TrustManager trustManager;
private SecureRandom secureRandom;
private volatile HelloCookieManager.Builder helloCookieManagerBuilder;
private final boolean clientEnableStapling = Utilities.getBooleanProperty(
"jdk.tls.client.enableStatusRequestExtension", true);
private final boolean serverEnableStapling = Utilities.getBooleanProperty(
"jdk.tls.server.enableStatusRequestExtension", false);
private static final Collection<CipherSuite> clientCustomizedCipherSuites =
getCustomizedCipherSuites("jdk.tls.client.cipherSuites");
private static final Collection<CipherSuite> serverCustomizedCipherSuites =
getCustomizedCipherSuites("jdk.tls.server.cipherSuites");
private volatile StatusResponseManager statusResponseManager;
private final ReentrantLock contextLock = new ReentrantLock();
final HashMap<Integer,
SessionTicketExtension.StatelessKey> keyHashMap = new HashMap<>();
SSLContextImpl() {
ephemeralKeyManager = new EphemeralKeyManager();
clientCache = new SSLSessionContextImpl(false);
serverCache = new SSLSessionContextImpl(true);
}
@Override
protected void engineInit(KeyManager[] km, TrustManager[] tm,
SecureRandom sr) throws KeyManagementException {
isInitialized = false;
keyManager = chooseKeyManager(km);
if (tm == null) {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore)null);
tm = tmf.getTrustManagers();
} catch (Exception e) {
}
}
trustManager = chooseTrustManager(tm);
if (sr == null) {
secureRandom = new SecureRandom();
} else {
secureRandom = sr;
}
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.finest("trigger seeding of SecureRandom");
}
secureRandom.nextInt();
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.finest("done seeding of SecureRandom");
}
isInitialized = true;
}
private X509TrustManager chooseTrustManager(TrustManager[] tm)
throws KeyManagementException {
for (int i = 0; tm != null && i < tm.length; i++) {
if (tm[i] instanceof X509TrustManager) {
if (tm[i] instanceof X509ExtendedTrustManager) {
return (X509TrustManager)tm[i];
} else {
return new AbstractTrustManagerWrapper(
(X509TrustManager)tm[i]);
}
}
}
return DummyX509TrustManager.INSTANCE;
}
private X509ExtendedKeyManager chooseKeyManager(KeyManager[] kms)
throws KeyManagementException {
for (int i = 0; kms != null && i < kms.length; i++) {
KeyManager km = kms[i];
if (!(km instanceof X509KeyManager)) {
continue;
}
if (km instanceof X509ExtendedKeyManager) {
return (X509ExtendedKeyManager)km;
}
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.warning(
"X509KeyManager passed to SSLContext.init(): need an " +
"X509ExtendedKeyManager for SSLEngine use");
}
return new AbstractKeyManagerWrapper((X509KeyManager)km);
}
return DummyX509KeyManager.INSTANCE;
}
abstract SSLEngine createSSLEngineImpl();
abstract SSLEngine createSSLEngineImpl(String host, int port);
@Override
protected SSLEngine engineCreateSSLEngine() {
if (!isInitialized) {
throw new IllegalStateException("SSLContext is not initialized");
}
return createSSLEngineImpl();
}
@Override
protected SSLEngine engineCreateSSLEngine(String host, int port) {
if (!isInitialized) {
throw new IllegalStateException("SSLContext is not initialized");
}
return createSSLEngineImpl(host, port);
}
@Override
protected SSLSocketFactory engineGetSocketFactory() {
if (!isInitialized) {
throw new IllegalStateException("SSLContext is not initialized");
}
if (isDTLS()) {
throw new UnsupportedOperationException(
"DTLS not supported with SSLSocket");
}
return new SSLSocketFactoryImpl(this);
}
@Override
protected SSLServerSocketFactory engineGetServerSocketFactory() {
if (!isInitialized) {
throw new IllegalStateException("SSLContext is not initialized");
}
if (isDTLS()) {
throw new UnsupportedOperationException(
"DTLS not supported with SSLServerSocket");
}
return new SSLServerSocketFactoryImpl(this);
}
@Override
protected SSLSessionContext engineGetClientSessionContext() {
return clientCache;
}
@Override
protected SSLSessionContext engineGetServerSessionContext() {
return serverCache;
}
SecureRandom getSecureRandom() {
return secureRandom;
}
X509ExtendedKeyManager getX509KeyManager() {
return keyManager;
}
X509TrustManager getX509TrustManager() {
return trustManager;
}
EphemeralKeyManager getEphemeralKeyManager() {
return ephemeralKeyManager;
}
HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) {
if (helloCookieManagerBuilder == null) {
contextLock.lock();
try {
if (helloCookieManagerBuilder == null) {
helloCookieManagerBuilder =
new HelloCookieManager.Builder(secureRandom);
}
} finally {
contextLock.unlock();
}
}
return helloCookieManagerBuilder.valueOf(protocolVersion);
}
StatusResponseManager getStatusResponseManager() {
if (serverEnableStapling && statusResponseManager == null) {
contextLock.lock();
try {
if (statusResponseManager == null) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.finest(
"Initializing StatusResponseManager");
}
statusResponseManager = new StatusResponseManager();
}
} finally {
contextLock.unlock();
}
}
return statusResponseManager;
}
abstract List<ProtocolVersion> getSupportedProtocolVersions();
abstract List<ProtocolVersion> getServerDefaultProtocolVersions();
abstract List<ProtocolVersion> getClientDefaultProtocolVersions();
abstract List<CipherSuite> getSupportedCipherSuites();
abstract List<CipherSuite> getServerDefaultCipherSuites();
abstract List<CipherSuite> getClientDefaultCipherSuites();
abstract boolean isDTLS();
List<ProtocolVersion> getDefaultProtocolVersions(boolean roleIsServer) {
return roleIsServer ? getServerDefaultProtocolVersions()
: getClientDefaultProtocolVersions();
}
List<CipherSuite> getDefaultCipherSuites(boolean roleIsServer) {
return roleIsServer ? getServerDefaultCipherSuites()
: getClientDefaultCipherSuites();
}
boolean isDefaultProtocolVesions(List<ProtocolVersion> protocols) {
return (protocols == getServerDefaultProtocolVersions()) ||
(protocols == getClientDefaultProtocolVersions());
}
boolean isDefaultCipherSuiteList(List<CipherSuite> cipherSuites) {
return (cipherSuites == getServerDefaultCipherSuites()) ||
(cipherSuites == getClientDefaultCipherSuites());
}
boolean isStaplingEnabled(boolean isClient) {
return isClient ? clientEnableStapling : serverEnableStapling;
}
private static List<CipherSuite> getApplicableSupportedCipherSuites(
List<ProtocolVersion> protocols) {
return getApplicableCipherSuites(
CipherSuite.allowedCipherSuites(), protocols);
}
private static List<CipherSuite> getApplicableEnabledCipherSuites(
List<ProtocolVersion> protocols, boolean isClient) {
if (isClient) {
if (!clientCustomizedCipherSuites.isEmpty()) {
return getApplicableCipherSuites(
clientCustomizedCipherSuites, protocols);
}
} else {
if (!serverCustomizedCipherSuites.isEmpty()) {
return getApplicableCipherSuites(
serverCustomizedCipherSuites, protocols);
}
}
return getApplicableCipherSuites(
CipherSuite.defaultCipherSuites(), protocols);
}
private static List<CipherSuite> getApplicableCipherSuites(
Collection<CipherSuite> allowedCipherSuites,
List<ProtocolVersion> protocols) {
LinkedHashSet<CipherSuite> suites = new LinkedHashSet<>();
if (protocols != null && (!protocols.isEmpty())) {
for (CipherSuite suite : allowedCipherSuites) {
if (!suite.isAvailable()) {
continue;
}
boolean isSupported = false;
for (ProtocolVersion protocol : protocols) {
if (!suite.supports(protocol) ||
!suite.bulkCipher.isAvailable()) {
continue;
}
if (SSLAlgorithmConstraints.DEFAULT.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
suite.name, null)) {
suites.add(suite);
isSupported = true;
} else if (SSLLogger.isOn &&
SSLLogger.isOn("ssl,sslctx,verbose")) {
SSLLogger.fine(
"Ignore disabled cipher suite: " + suite.name);
}
break;
}
if (!isSupported && SSLLogger.isOn &&
SSLLogger.isOn("ssl,sslctx,verbose")) {
SSLLogger.finest(
"Ignore unsupported cipher suite: " + suite);
}
}
}
return new ArrayList<>(suites);
}
private static Collection<CipherSuite> getCustomizedCipherSuites(
String propertyName) {
String property = GetPropertyAction.privilegedGetProperty(propertyName);
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.fine(
"System property " + propertyName + " is set to '" +
property + "'");
}
if (property != null && !property.isEmpty()) {
if (property.length() > 1 && property.charAt(0) == '"' &&
property.charAt(property.length() - 1) == '"') {
property = property.substring(1, property.length() - 1);
}
}
if (property != null && !property.isEmpty()) {
String[] cipherSuiteNames = property.split(",");
Collection<CipherSuite> cipherSuites =
new ArrayList<>(cipherSuiteNames.length);
for (int i = 0; i < cipherSuiteNames.length; i++) {
cipherSuiteNames[i] = cipherSuiteNames[i].trim();
if (cipherSuiteNames[i].isEmpty()) {
continue;
}
CipherSuite suite;
try {
suite = CipherSuite.nameOf(cipherSuiteNames[i]);
} catch (IllegalArgumentException iae) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.fine(
"Unknown or unsupported cipher suite name: " +
cipherSuiteNames[i]);
}
continue;
}
if (suite != null && suite.isAvailable()) {
cipherSuites.add(suite);
} else {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) {
SSLLogger.fine(
"The current installed providers do not " +
"support cipher suite: " + cipherSuiteNames[i]);
}
}
}
return cipherSuites;
}
return Collections.emptyList();
}
private static List<ProtocolVersion> getAvailableProtocols(
ProtocolVersion[] protocolCandidates) {
List<ProtocolVersion> availableProtocols =
Collections.<ProtocolVersion>emptyList();
if (protocolCandidates != null && protocolCandidates.length != 0) {
availableProtocols = new ArrayList<>(protocolCandidates.length);
for (ProtocolVersion p : protocolCandidates) {
if (p.isAvailable) {
availableProtocols.add(p);
}
}
}
return availableProtocols;
}
private abstract static class AbstractTLSContext extends SSLContextImpl {
private static final List<ProtocolVersion> supportedProtocols;
private static final List<ProtocolVersion> serverDefaultProtocols;
private static final List<CipherSuite> supportedCipherSuites;
private static final List<CipherSuite> serverDefaultCipherSuites;
static {
supportedProtocols = Arrays.asList(
ProtocolVersion.TLS13,
ProtocolVersion.TLS12,
ProtocolVersion.TLS11,
ProtocolVersion.TLS10,
ProtocolVersion.SSL30,
ProtocolVersion.SSL20Hello
);
serverDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.TLS13,
ProtocolVersion.TLS12,
ProtocolVersion.TLS11,
ProtocolVersion.TLS10
});
supportedCipherSuites = getApplicableSupportedCipherSuites(
supportedProtocols);
serverDefaultCipherSuites = getApplicableEnabledCipherSuites(
serverDefaultProtocols, false);
}
@Override
List<ProtocolVersion> getSupportedProtocolVersions() {
return supportedProtocols;
}
@Override
List<CipherSuite> getSupportedCipherSuites() {
return supportedCipherSuites;
}
@Override
List<ProtocolVersion> getServerDefaultProtocolVersions() {
return serverDefaultProtocols;
}
@Override
List<CipherSuite> getServerDefaultCipherSuites() {
return serverDefaultCipherSuites;
}
@Override
SSLEngine createSSLEngineImpl() {
return new SSLEngineImpl(this);
}
@Override
SSLEngine createSSLEngineImpl(String host, int port) {
return new SSLEngineImpl(this, host, port);
}
@Override
boolean isDTLS() {
return false;
}
}
public static final class TLS10Context extends AbstractTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
static {
clientDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.TLS10
});
clientDefaultCipherSuites = getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
}
public static final class TLS11Context extends AbstractTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
static {
clientDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.TLS11,
ProtocolVersion.TLS10
});
clientDefaultCipherSuites = getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
}
public static final class TLS12Context extends AbstractTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
static {
clientDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.TLS12,
ProtocolVersion.TLS11,
ProtocolVersion.TLS10
});
clientDefaultCipherSuites = getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
}
public static final class TLS13Context extends AbstractTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
static {
clientDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.TLS13,
ProtocolVersion.TLS12,
ProtocolVersion.TLS11,
ProtocolVersion.TLS10
});
clientDefaultCipherSuites = getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
}
private static class CustomizedSSLProtocols {
private static final String JDK_TLS_CLIENT_PROTOCOLS =
"jdk.tls.client.protocols";
private static final String JDK_TLS_SERVER_PROTOCOLS =
"jdk.tls.server.protocols";
static IllegalArgumentException reservedException = null;
static final ArrayList<ProtocolVersion> customizedClientProtocols =
new ArrayList<>();
static final ArrayList<ProtocolVersion> customizedServerProtocols =
new ArrayList<>();
static {
populate(JDK_TLS_CLIENT_PROTOCOLS, customizedClientProtocols);
populate(JDK_TLS_SERVER_PROTOCOLS, customizedServerProtocols);
}
private static void populate(String propname,
ArrayList<ProtocolVersion> arrayList) {
String property = GetPropertyAction.privilegedGetProperty(propname);
if (property == null) {
return;
}
if (!property.isEmpty()) {
if (property.length() > 1 && property.charAt(0) == '"' &&
property.charAt(property.length() - 1) == '"') {
property = property.substring(1, property.length() - 1);
}
}
if (!property.isEmpty()) {
String[] protocols = property.split(",");
for (int i = 0; i < protocols.length; i++) {
protocols[i] = protocols[i].trim();
ProtocolVersion pv =
ProtocolVersion.nameOf(protocols[i]);
if (pv == null) {
reservedException = new IllegalArgumentException(
propname + ": " + protocols[i] +
" is not a supported SSL protocol name");
}
if (!arrayList.contains(pv)) {
arrayList.add(pv);
}
}
}
}
}
private static class CustomizedTLSContext extends AbstractTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<ProtocolVersion> serverDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
private static final List<CipherSuite> serverDefaultCipherSuites;
private static final IllegalArgumentException reservedException;
static {
reservedException = CustomizedSSLProtocols.reservedException;
if (reservedException == null) {
clientDefaultProtocols = customizedProtocols(true,
CustomizedSSLProtocols.customizedClientProtocols);
serverDefaultProtocols = customizedProtocols(false,
CustomizedSSLProtocols.customizedServerProtocols);
clientDefaultCipherSuites =
getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
serverDefaultCipherSuites =
getApplicableEnabledCipherSuites(
serverDefaultProtocols, false);
} else {
clientDefaultProtocols = null;
serverDefaultProtocols = null;
clientDefaultCipherSuites = null;
serverDefaultCipherSuites = null;
}
}
private static List<ProtocolVersion> customizedProtocols(
boolean client, List<ProtocolVersion> customized) {
List<ProtocolVersion> refactored = new ArrayList<>();
for (ProtocolVersion pv : customized) {
if (!pv.isDTLS) {
refactored.add(pv);
}
}
ProtocolVersion[] candidates;
if (refactored.isEmpty()) {
candidates = new ProtocolVersion[] {
ProtocolVersion.TLS13,
ProtocolVersion.TLS12,
ProtocolVersion.TLS11,
ProtocolVersion.TLS10
};
} else {
candidates =
refactored.toArray(new ProtocolVersion[0]);
}
return getAvailableProtocols(candidates);
}
protected CustomizedTLSContext() {
if (reservedException != null) {
throw reservedException;
}
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<ProtocolVersion> getServerDefaultProtocolVersions() {
return serverDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
@Override
List<CipherSuite> getServerDefaultCipherSuites() {
return serverDefaultCipherSuites;
}
}
public static final class TLSContext extends CustomizedTLSContext {
}
private static final class DefaultManagersHolder {
private static final String NONE = "NONE";
private static final String P11KEYSTORE = "PKCS11";
private static final TrustManager[] trustManagers;
private static final KeyManager[] keyManagers;
private static final Exception reservedException;
static {
Exception reserved = null;
TrustManager[] tmMediator = null;
try {
tmMediator = getTrustManagers();
} catch (Exception e) {
reserved = e;
if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) {
SSLLogger.warning(
"Failed to load default trust managers", e);
}
}
KeyManager[] kmMediator = null;
if (reserved == null) {
try {
kmMediator = getKeyManagers();
} catch (Exception e) {
reserved = e;
if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) {
SSLLogger.warning(
"Failed to load default key managers", e);
}
}
}
if (reserved != null) {
trustManagers = new TrustManager[0];
keyManagers = new KeyManager[0];
reservedException =
new KeyManagementException(reserved.getMessage());
} else {
trustManagers = tmMediator;
keyManagers = kmMediator;
reservedException = null;
}
}
private static TrustManager[] getTrustManagers() throws Exception {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
if ("SunJSSE".equals(tmf.getProvider().getName())) {
tmf.init((KeyStore)null);
} else {
KeyStore ks = TrustStoreManager.getTrustedKeyStore();
tmf.init(ks);
}
return tmf.getTrustManagers();
}
private static KeyManager[] getKeyManagers() throws Exception {
final Map<String,String> props = new HashMap<>();
AccessController.doPrivileged(
new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
props.put("keyStore", System.getProperty(
"javax.net.ssl.keyStore", ""));
props.put("keyStoreType", System.getProperty(
"javax.net.ssl.keyStoreType",
KeyStore.getDefaultType()));
props.put("keyStoreProvider", System.getProperty(
"javax.net.ssl.keyStoreProvider", ""));
props.put("keyStorePasswd", System.getProperty(
"javax.net.ssl.keyStorePassword", ""));
return null;
}
});
final String defaultKeyStore = props.get("keyStore");
String defaultKeyStoreType = props.get("keyStoreType");
String defaultKeyStoreProvider = props.get("keyStoreProvider");
if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) {
SSLLogger.fine("keyStore is : " + defaultKeyStore);
SSLLogger.fine("keyStore type is : " +
defaultKeyStoreType);
SSLLogger.fine("keyStore provider is : " +
defaultKeyStoreProvider);
}
if (P11KEYSTORE.equals(defaultKeyStoreType) &&
!NONE.equals(defaultKeyStore)) {
throw new IllegalArgumentException("if keyStoreType is "
+ P11KEYSTORE + ", then keyStore must be " + NONE);
}
FileInputStream fs = null;
KeyStore ks = null;
char[] passwd = null;
try {
if (!defaultKeyStore.isEmpty() &&
!NONE.equals(defaultKeyStore)) {
fs = AccessController.doPrivileged(
new PrivilegedExceptionAction<FileInputStream>() {
@Override
public FileInputStream run() throws Exception {
return new FileInputStream(defaultKeyStore);
}
});
}
String defaultKeyStorePassword = props.get("keyStorePasswd");
if (!defaultKeyStorePassword.isEmpty()) {
passwd = defaultKeyStorePassword.toCharArray();
}
if ((defaultKeyStoreType.length()) != 0) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) {
SSLLogger.finest("init keystore");
}
if (defaultKeyStoreProvider.isEmpty()) {
ks = KeyStore.getInstance(defaultKeyStoreType);
} else {
ks = KeyStore.getInstance(defaultKeyStoreType,
defaultKeyStoreProvider);
}
ks.load(fs, passwd);
}
} finally {
if (fs != null) {
fs.close();
fs = null;
}
}
if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) {
SSLLogger.fine("init keymanager of type " +
KeyManagerFactory.getDefaultAlgorithm());
}
KeyManagerFactory kmf = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
if (P11KEYSTORE.equals(defaultKeyStoreType)) {
kmf.init(ks, null);
} else {
kmf.init(ks, passwd);
}
return kmf.getKeyManagers();
}
}
private static final class DefaultSSLContextHolder {
private static final SSLContextImpl sslContext;
private static final Exception reservedException;
static {
Exception reserved = null;
SSLContextImpl mediator = null;
if (DefaultManagersHolder.reservedException != null) {
reserved = DefaultManagersHolder.reservedException;
} else {
try {
mediator = new DefaultSSLContext();
} catch (Exception e) {
reserved = new KeyManagementException(e.getMessage());
if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) {
SSLLogger.warning(
"Failed to load default SSLContext", e);
}
}
}
sslContext = mediator;
reservedException = reserved;
}
}
public static final class DefaultSSLContext extends CustomizedTLSContext {
public DefaultSSLContext() throws Exception {
if (DefaultManagersHolder.reservedException != null) {
throw DefaultManagersHolder.reservedException;
}
try {
super.engineInit(DefaultManagersHolder.keyManagers,
DefaultManagersHolder.trustManagers, null);
} catch (Exception e) {
if (SSLLogger.isOn && SSLLogger.isOn("ssl,defaultctx")) {
SSLLogger.fine("default context init failed: ", e);
}
throw e;
}
}
@Override
protected void engineInit(KeyManager[] km, TrustManager[] tm,
SecureRandom sr) throws KeyManagementException {
throw new KeyManagementException
("Default SSLContext is initialized automatically");
}
static SSLContextImpl getDefaultImpl() throws Exception {
if (DefaultSSLContextHolder.reservedException != null) {
throw DefaultSSLContextHolder.reservedException;
}
return DefaultSSLContextHolder.sslContext;
}
}
private abstract static class AbstractDTLSContext extends SSLContextImpl {
private static final List<ProtocolVersion> supportedProtocols;
private static final List<ProtocolVersion> serverDefaultProtocols;
private static final List<CipherSuite> supportedCipherSuites;
private static final List<CipherSuite> serverDefaultCipherSuites;
static {
supportedProtocols = Arrays.asList(
ProtocolVersion.DTLS12,
ProtocolVersion.DTLS10
);
serverDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.DTLS12,
ProtocolVersion.DTLS10
});
supportedCipherSuites = getApplicableSupportedCipherSuites(
supportedProtocols);
serverDefaultCipherSuites = getApplicableEnabledCipherSuites(
serverDefaultProtocols, false);
}
@Override
protected SSLParameters engineGetDefaultSSLParameters() {
SSLEngine engine = createSSLEngineImpl();
engine.setUseClientMode(true);
return engine.getSSLParameters();
}
@Override
protected SSLParameters engineGetSupportedSSLParameters() {
SSLEngine engine = createSSLEngineImpl();
SSLParameters params = new SSLParameters();
params.setCipherSuites(engine.getSupportedCipherSuites());
params.setProtocols(engine.getSupportedProtocols());
return params;
}
@Override
List<ProtocolVersion> getSupportedProtocolVersions() {
return supportedProtocols;
}
@Override
List<CipherSuite> getSupportedCipherSuites() {
return supportedCipherSuites;
}
@Override
List<ProtocolVersion> getServerDefaultProtocolVersions() {
return serverDefaultProtocols;
}
@Override
List<CipherSuite> getServerDefaultCipherSuites() {
return serverDefaultCipherSuites;
}
@Override
SSLEngine createSSLEngineImpl() {
return new SSLEngineImpl(this);
}
@Override
SSLEngine createSSLEngineImpl(String host, int port) {
return new SSLEngineImpl(this, host, port);
}
@Override
boolean isDTLS() {
return true;
}
}
public static final class DTLS10Context extends AbstractDTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
static {
clientDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.DTLS10
});
clientDefaultCipherSuites = getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
}
public static final class DTLS12Context extends AbstractDTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
static {
clientDefaultProtocols = getAvailableProtocols(
new ProtocolVersion[] {
ProtocolVersion.DTLS12,
ProtocolVersion.DTLS10
});
clientDefaultCipherSuites = getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
}
private static class CustomizedDTLSContext extends AbstractDTLSContext {
private static final List<ProtocolVersion> clientDefaultProtocols;
private static final List<ProtocolVersion> serverDefaultProtocols;
private static final List<CipherSuite> clientDefaultCipherSuites;
private static final List<CipherSuite> serverDefaultCipherSuites;
private static IllegalArgumentException reservedException;
static {
reservedException = CustomizedSSLProtocols.reservedException;
if (reservedException == null) {
clientDefaultProtocols = customizedProtocols(true,
CustomizedSSLProtocols.customizedClientProtocols);
serverDefaultProtocols = customizedProtocols(false,
CustomizedSSLProtocols.customizedServerProtocols);
clientDefaultCipherSuites =
getApplicableEnabledCipherSuites(
clientDefaultProtocols, true);
serverDefaultCipherSuites =
getApplicableEnabledCipherSuites(
serverDefaultProtocols, false);
} else {
clientDefaultProtocols = null;
serverDefaultProtocols = null;
clientDefaultCipherSuites = null;
serverDefaultCipherSuites = null;
}
}
private static List<ProtocolVersion> customizedProtocols(boolean client,
List<ProtocolVersion> customized) {
List<ProtocolVersion> refactored = new ArrayList<>();
for (ProtocolVersion pv : customized) {
if (pv.isDTLS) {
refactored.add(pv);
}
}
ProtocolVersion[] candidates;
if (refactored.isEmpty()) {
candidates = new ProtocolVersion[]{
ProtocolVersion.DTLS12,
ProtocolVersion.DTLS10
};
if (!client)
return Arrays.asList(candidates);
} else {
candidates =
new ProtocolVersion[customized.size()];
candidates = customized.toArray(candidates);
}
return getAvailableProtocols(candidates);
}
protected CustomizedDTLSContext() {
if (reservedException != null) {
throw reservedException;
}
}
@Override
List<ProtocolVersion> getClientDefaultProtocolVersions() {
return clientDefaultProtocols;
}
@Override
List<ProtocolVersion> getServerDefaultProtocolVersions() {
return serverDefaultProtocols;
}
@Override
List<CipherSuite> getClientDefaultCipherSuites() {
return clientDefaultCipherSuites;
}
@Override
List<CipherSuite> getServerDefaultCipherSuites() {
return serverDefaultCipherSuites;
}
}
public static final class DTLSContext extends CustomizedDTLSContext {
}
}
final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager
implements X509TrustManager {
private final X509TrustManager tm;
AbstractTrustManagerWrapper(X509TrustManager tm) {
this.tm = tm;
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
tm.checkClientTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
tm.checkServerTrusted(chain, authType);
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return tm.getAcceptedIssuers();
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,
Socket socket) throws CertificateException {
tm.checkClientTrusted(chain, authType);
checkAdditionalTrust(chain, authType, socket, true);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType,
Socket socket) throws CertificateException {
tm.checkServerTrusted(chain, authType);
checkAdditionalTrust(chain, authType, socket, false);
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,
SSLEngine engine) throws CertificateException {
tm.checkClientTrusted(chain, authType);
checkAdditionalTrust(chain, authType, engine, true);
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType,
SSLEngine engine) throws CertificateException {
tm.checkServerTrusted(chain, authType);
checkAdditionalTrust(chain, authType, engine, false);
}
private void checkAdditionalTrust(X509Certificate[] chain,
String authType, Socket socket,
boolean checkClientTrusted) throws CertificateException {
if (socket != null && socket.isConnected() &&
socket instanceof SSLSocket) {
SSLSocket sslSocket = (SSLSocket)socket;
SSLSession session = sslSocket.getHandshakeSession();
if (session == null) {
throw new CertificateException("No handshake session");
}
String identityAlg = sslSocket.getSSLParameters().
getEndpointIdentificationAlgorithm();
if (identityAlg != null && !identityAlg.isEmpty()) {
X509TrustManagerImpl.checkIdentity(session, chain,
identityAlg, checkClientTrusted);
}
AlgorithmConstraints constraints;
if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) {
if (session instanceof ExtendedSSLSession) {
ExtendedSSLSession extSession =
(ExtendedSSLSession)session;
String[] peerSupportedSignAlgs =
extSession.getLocalSupportedSignatureAlgorithms();
constraints = new SSLAlgorithmConstraints(
sslSocket, peerSupportedSignAlgs, true);
} else {
constraints =
new SSLAlgorithmConstraints(sslSocket, true);
}
} else {
constraints = new SSLAlgorithmConstraints(sslSocket, true);
}
checkAlgorithmConstraints(chain, constraints, checkClientTrusted);
}
}
private void checkAdditionalTrust(X509Certificate[] chain,
String authType, SSLEngine engine,
boolean checkClientTrusted) throws CertificateException {
if (engine != null) {
SSLSession session = engine.getHandshakeSession();
if (session == null) {
throw new CertificateException("No handshake session");
}
String identityAlg = engine.getSSLParameters().
getEndpointIdentificationAlgorithm();
if (identityAlg != null && !identityAlg.isEmpty()) {
X509TrustManagerImpl.checkIdentity(session, chain,
identityAlg, checkClientTrusted);
}
AlgorithmConstraints constraints;
if (ProtocolVersion.useTLS12PlusSpec(session.getProtocol())) {
if (session instanceof ExtendedSSLSession) {
ExtendedSSLSession extSession =
(ExtendedSSLSession)session;
String[] peerSupportedSignAlgs =
extSession.getLocalSupportedSignatureAlgorithms();
constraints = new SSLAlgorithmConstraints(
engine, peerSupportedSignAlgs, true);
} else {
constraints =
new SSLAlgorithmConstraints(engine, true);
}
} else {
constraints = new SSLAlgorithmConstraints(engine, true);
}
checkAlgorithmConstraints(chain, constraints, checkClientTrusted);
}
}
private void checkAlgorithmConstraints(X509Certificate[] chain,
AlgorithmConstraints constraints,
boolean checkClientTrusted) throws CertificateException {
try {
int checkedLength = chain.length - 1;
Collection<X509Certificate> trustedCerts = new HashSet<>();
X509Certificate[] certs = tm.getAcceptedIssuers();
if ((certs != null) && (certs.length > 0)){
Collections.addAll(trustedCerts, certs);
}
if (trustedCerts.contains(chain[checkedLength])) {
checkedLength--;
}
if (checkedLength >= 0) {
AlgorithmChecker checker =
new AlgorithmChecker(constraints, null,
(checkClientTrusted ? Validator.VAR_TLS_CLIENT :
Validator.VAR_TLS_SERVER));
checker.init(false);
for (int i = checkedLength; i >= 0; i--) {
X509Certificate cert = chain[i];
checker.check(cert, Collections.<String>emptySet());
}
}
} catch (CertPathValidatorException cpve) {
throw new CertificateException(
"Certificates do not conform to algorithm constraints", cpve);
}
}
}
final class DummyX509TrustManager extends X509ExtendedTrustManager
implements X509TrustManager {
static final X509TrustManager INSTANCE = new DummyX509TrustManager();
private DummyX509TrustManager() {
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new CertificateException(
"No X509TrustManager implementation avaiable");
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new CertificateException(
"No X509TrustManager implementation available");
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,
Socket socket) throws CertificateException {
throw new CertificateException(
"No X509TrustManager implementation available");
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType,
Socket socket) throws CertificateException {
throw new CertificateException(
"No X509TrustManager implementation available");
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,
SSLEngine engine) throws CertificateException {
throw new CertificateException(
"No X509TrustManager implementation available");
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType,
SSLEngine engine) throws CertificateException {
throw new CertificateException(
"No X509TrustManager implementation available");
}
}
final class AbstractKeyManagerWrapper extends X509ExtendedKeyManager {
private final X509KeyManager km;
AbstractKeyManagerWrapper(X509KeyManager km) {
this.km = km;
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return km.getClientAliases(keyType, issuers);
}
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers,
Socket socket) {
return km.chooseClientAlias(keyType, issuers, socket);
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return km.getServerAliases(keyType, issuers);
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers,
Socket socket) {
return km.chooseServerAlias(keyType, issuers, socket);
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return km.getCertificateChain(alias);
}
@Override
public PrivateKey getPrivateKey(String alias) {
return km.getPrivateKey(alias);
}
}
final class DummyX509KeyManager extends X509ExtendedKeyManager {
static final X509ExtendedKeyManager INSTANCE = new DummyX509KeyManager();
private DummyX509KeyManager() {
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return null;
}
@Override
public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
Socket socket) {
return null;
}
@Override
public String chooseEngineClientAlias(
String[] keyTypes, Principal[] issuers, SSLEngine engine) {
return null;
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return null;
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers,
Socket socket) {
return null;
}
@Override
public String chooseEngineServerAlias(
String keyType, Principal[] issuers, SSLEngine engine) {
return null;
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return null;
}
@Override
public PrivateKey getPrivateKey(String alias) {
return null;
}
}