Allow to specify KeyStore type in SslContext (#9003)
Motivation: As brought up in https://github.com/netty/netty/issues/8998, JKS can be substantially faster than pkcs12, JDK's new default. Without an option to set the KeyStore type you must change the configuration of the entire JVM which is impractical. Modification: - Allow to specify KeyStore type - Add test case Result: Fixes https://github.com/netty/netty/issues/8998.
This commit is contained in:
parent
83210c47ca
commit
d3a13a0d6a
@ -54,7 +54,7 @@ import io.netty.util.CharsetUtil;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* ATTENTION: This is an incomplete example! In order to provide a fully functional
|
* ATTENTION: This is an incomplete example! In order to provide a fully functional
|
||||||
* end-to-end example we'd need a X.509 certificate and the matching PrivateKey.
|
* end-to-end example we'd need an X.509 certificate and the matching PrivateKey.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class OcspServerExample {
|
public class OcspServerExample {
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.security.KeyStore;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
@ -44,7 +45,7 @@ final class JdkSslClientContext extends JdkSslContext {
|
|||||||
throws SSLException {
|
throws SSLException {
|
||||||
super(newSSLContext(provider, toX509CertificatesInternal(trustCertCollectionFile),
|
super(newSSLContext(provider, toX509CertificatesInternal(trustCertCollectionFile),
|
||||||
trustManagerFactory, null, null,
|
trustManagerFactory, null, null,
|
||||||
null, null, sessionCacheSize, sessionTimeout), true,
|
null, null, sessionCacheSize, sessionTimeout, KeyStore.getDefaultType()), true,
|
||||||
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
|
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,10 +61,11 @@ final class JdkSslClientContext extends JdkSslContext {
|
|||||||
ApplicationProtocolConfig apn,
|
ApplicationProtocolConfig apn,
|
||||||
String[] protocols,
|
String[] protocols,
|
||||||
long sessionCacheSize,
|
long sessionCacheSize,
|
||||||
long sessionTimeout)
|
long sessionTimeout,
|
||||||
|
String keyStore)
|
||||||
throws SSLException {
|
throws SSLException {
|
||||||
super(newSSLContext(sslContextProvider, trustCertCollection, trustManagerFactory,
|
super(newSSLContext(sslContextProvider, trustCertCollection, trustManagerFactory,
|
||||||
keyCertChain, key, keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout),
|
keyCertChain, key, keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout, keyStore),
|
||||||
true, ciphers, cipherFilter, toNegotiator(apn, false), ClientAuth.NONE, protocols, false);
|
true, ciphers, cipherFilter, toNegotiator(apn, false), ClientAuth.NONE, protocols, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,13 +73,14 @@ final class JdkSslClientContext extends JdkSslContext {
|
|||||||
X509Certificate[] trustCertCollection,
|
X509Certificate[] trustCertCollection,
|
||||||
TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain,
|
TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain,
|
||||||
PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
long sessionCacheSize, long sessionTimeout) throws SSLException {
|
long sessionCacheSize, long sessionTimeout,
|
||||||
|
String keyStore) throws SSLException {
|
||||||
try {
|
try {
|
||||||
if (trustCertCollection != null) {
|
if (trustCertCollection != null) {
|
||||||
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
|
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
|
||||||
}
|
}
|
||||||
if (keyCertChain != null) {
|
if (keyCertChain != null) {
|
||||||
keyManagerFactory = buildKeyManagerFactory(keyCertChain, key, keyPassword, keyManagerFactory);
|
keyManagerFactory = buildKeyManagerFactory(keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
|
||||||
}
|
}
|
||||||
SSLContext ctx = sslContextProvider == null ? SSLContext.getInstance(PROTOCOL)
|
SSLContext ctx = sslContextProvider == null ? SSLContext.getInstance(PROTOCOL)
|
||||||
: SSLContext.getInstance(PROTOCOL, sslContextProvider);
|
: SSLContext.getInstance(PROTOCOL, sslContextProvider);
|
||||||
|
@ -25,6 +25,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.KeyException;
|
import java.security.KeyException;
|
||||||
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
@ -433,7 +434,29 @@ public class JdkSslContext extends SslContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a {@link KeyManagerFactory} based upon a key file, key file password, and a certificate chain.
|
* Build a {@link KeyManagerFactory} based upon a key file, key file password, and a certificate chain.
|
||||||
* @param certChainFile a X.509 certificate chain file in PEM format
|
* @param certChainFile an X.509 certificate chain file in PEM format
|
||||||
|
* @param keyFile a PKCS#8 private key file in PEM format
|
||||||
|
* @param keyPassword the password of the {@code keyFile}.
|
||||||
|
* {@code null} if it's not password-protected.
|
||||||
|
* @param kmf The existing {@link KeyManagerFactory} that will be used if not {@code null}
|
||||||
|
* @param keyStore the {@link KeyStore} that should be used in the {@link KeyManagerFactory}
|
||||||
|
* @return A {@link KeyManagerFactory} based upon a key file, key file password, and a certificate chain.
|
||||||
|
*/
|
||||||
|
static KeyManagerFactory buildKeyManagerFactory(File certChainFile, File keyFile, String keyPassword,
|
||||||
|
KeyManagerFactory kmf, String keyStore)
|
||||||
|
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
||||||
|
NoSuchPaddingException, InvalidKeySpecException, InvalidAlgorithmParameterException,
|
||||||
|
CertificateException, KeyException, IOException {
|
||||||
|
String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
|
||||||
|
if (algorithm == null) {
|
||||||
|
algorithm = "SunX509";
|
||||||
|
}
|
||||||
|
return buildKeyManagerFactory(certChainFile, algorithm, keyFile, keyPassword, kmf, keyStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link KeyManagerFactory} based upon a key file, key file password, and a certificate chain.
|
||||||
|
* @param certChainFile an X.509 certificate chain file in PEM format
|
||||||
* @param keyFile a PKCS#8 private key file in PEM format
|
* @param keyFile a PKCS#8 private key file in PEM format
|
||||||
* @param keyPassword the password of the {@code keyFile}.
|
* @param keyPassword the password of the {@code keyFile}.
|
||||||
* {@code null} if it's not password-protected.
|
* {@code null} if it's not password-protected.
|
||||||
@ -443,23 +466,43 @@ public class JdkSslContext extends SslContext {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
protected static KeyManagerFactory buildKeyManagerFactory(File certChainFile, File keyFile, String keyPassword,
|
protected static KeyManagerFactory buildKeyManagerFactory(File certChainFile, File keyFile, String keyPassword,
|
||||||
KeyManagerFactory kmf)
|
KeyManagerFactory kmf)
|
||||||
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
||||||
NoSuchPaddingException, InvalidKeySpecException, InvalidAlgorithmParameterException,
|
NoSuchPaddingException, InvalidKeySpecException, InvalidAlgorithmParameterException,
|
||||||
CertificateException, KeyException, IOException {
|
CertificateException, KeyException, IOException {
|
||||||
String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
|
return buildKeyManagerFactory(certChainFile, keyFile, keyPassword, kmf, KeyStore.getDefaultType());
|
||||||
if (algorithm == null) {
|
|
||||||
algorithm = "SunX509";
|
|
||||||
}
|
|
||||||
return buildKeyManagerFactory(certChainFile, algorithm, keyFile, keyPassword, kmf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a {@link KeyManagerFactory} based upon a key algorithm, key file, key file password,
|
* Build a {@link KeyManagerFactory} based upon a key algorithm, key file, key file password,
|
||||||
* and a certificate chain.
|
* and a certificate chain.
|
||||||
* @param certChainFile a X.509 certificate chain file in PEM format
|
* @param certChainFile an X.509 certificate chain file in PEM format
|
||||||
* @param keyAlgorithm the standard name of the requested algorithm. See the Java Secure Socket Extension
|
* @param keyAlgorithm the standard name of the requested algorithm. See the Java Secure Socket Extension
|
||||||
* Reference Guide for information about standard algorithm names.
|
* Reference Guide for information about standard algorithm names.
|
||||||
|
* @param keyFile a PKCS#8 private key file in PEM format
|
||||||
|
* @param keyPassword the password of the {@code keyFile}.
|
||||||
|
* {@code null} if it's not password-protected.
|
||||||
|
* @param kmf The existing {@link KeyManagerFactory} that will be used if not {@code null}
|
||||||
|
* @param keyStore the {@link KeyStore} that should be used in the {@link KeyManagerFactory}
|
||||||
|
* @return A {@link KeyManagerFactory} based upon a key algorithm, key file, key file password,
|
||||||
|
* and a certificate chain.
|
||||||
|
*/
|
||||||
|
static KeyManagerFactory buildKeyManagerFactory(File certChainFile,
|
||||||
|
String keyAlgorithm, File keyFile, String keyPassword, KeyManagerFactory kmf,
|
||||||
|
String keyStore)
|
||||||
|
throws KeyStoreException, NoSuchAlgorithmException, NoSuchPaddingException,
|
||||||
|
InvalidKeySpecException, InvalidAlgorithmParameterException, IOException,
|
||||||
|
CertificateException, KeyException, UnrecoverableKeyException {
|
||||||
|
return buildKeyManagerFactory(toX509Certificates(certChainFile), keyAlgorithm,
|
||||||
|
toPrivateKey(keyFile, keyPassword), keyPassword, kmf, keyStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link KeyManagerFactory} based upon a key algorithm, key file, key file password,
|
||||||
|
* and a certificate chain.
|
||||||
|
* @param certChainFile an buildKeyManagerFactory X.509 certificate chain file in PEM format
|
||||||
|
* @param keyAlgorithm the standard name of the requested algorithm. See the Java Secure Socket Extension
|
||||||
|
* Reference Guide for information about standard algorithm names.
|
||||||
* @param keyFile a PKCS#8 private key file in PEM format
|
* @param keyFile a PKCS#8 private key file in PEM format
|
||||||
* @param keyPassword the password of the {@code keyFile}.
|
* @param keyPassword the password of the {@code keyFile}.
|
||||||
* {@code null} if it's not password-protected.
|
* {@code null} if it's not password-protected.
|
||||||
@ -470,11 +513,12 @@ public class JdkSslContext extends SslContext {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
protected static KeyManagerFactory buildKeyManagerFactory(File certChainFile,
|
protected static KeyManagerFactory buildKeyManagerFactory(File certChainFile,
|
||||||
String keyAlgorithm, File keyFile, String keyPassword, KeyManagerFactory kmf)
|
String keyAlgorithm, File keyFile,
|
||||||
throws KeyStoreException, NoSuchAlgorithmException, NoSuchPaddingException,
|
String keyPassword, KeyManagerFactory kmf)
|
||||||
InvalidKeySpecException, InvalidAlgorithmParameterException, IOException,
|
throws KeyStoreException, NoSuchAlgorithmException, NoSuchPaddingException,
|
||||||
CertificateException, KeyException, UnrecoverableKeyException {
|
InvalidKeySpecException, InvalidAlgorithmParameterException, IOException,
|
||||||
|
CertificateException, KeyException, UnrecoverableKeyException {
|
||||||
return buildKeyManagerFactory(toX509Certificates(certChainFile), keyAlgorithm,
|
return buildKeyManagerFactory(toX509Certificates(certChainFile), keyAlgorithm,
|
||||||
toPrivateKey(keyFile, keyPassword), keyPassword, kmf);
|
toPrivateKey(keyFile, keyPassword), keyPassword, kmf, KeyStore.getDefaultType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.security.KeyStore;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
@ -45,7 +46,7 @@ final class JdkSslServerContext extends JdkSslContext {
|
|||||||
throws SSLException {
|
throws SSLException {
|
||||||
super(newSSLContext(provider, null, null,
|
super(newSSLContext(provider, null, null,
|
||||||
toX509CertificatesInternal(certChainFile), toPrivateKeyInternal(keyFile, keyPassword),
|
toX509CertificatesInternal(certChainFile), toPrivateKeyInternal(keyFile, keyPassword),
|
||||||
keyPassword, null, sessionCacheSize, sessionTimeout), false,
|
keyPassword, null, sessionCacheSize, sessionTimeout, KeyStore.getDefaultType()), false,
|
||||||
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
|
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,17 +64,18 @@ final class JdkSslServerContext extends JdkSslContext {
|
|||||||
long sessionTimeout,
|
long sessionTimeout,
|
||||||
ClientAuth clientAuth,
|
ClientAuth clientAuth,
|
||||||
String[] protocols,
|
String[] protocols,
|
||||||
boolean startTls)
|
boolean startTls,
|
||||||
|
String keyStore)
|
||||||
throws SSLException {
|
throws SSLException {
|
||||||
super(newSSLContext(provider, trustCertCollection, trustManagerFactory, keyCertChain, key,
|
super(newSSLContext(provider, trustCertCollection, trustManagerFactory, keyCertChain, key,
|
||||||
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout), false,
|
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout, keyStore), false,
|
||||||
ciphers, cipherFilter, toNegotiator(apn, true), clientAuth, protocols, startTls);
|
ciphers, cipherFilter, toNegotiator(apn, true), clientAuth, protocols, startTls);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SSLContext newSSLContext(Provider sslContextProvider, X509Certificate[] trustCertCollection,
|
private static SSLContext newSSLContext(Provider sslContextProvider, X509Certificate[] trustCertCollection,
|
||||||
TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain,
|
TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain,
|
||||||
PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
long sessionCacheSize, long sessionTimeout)
|
long sessionCacheSize, long sessionTimeout, String keyStore)
|
||||||
throws SSLException {
|
throws SSLException {
|
||||||
if (key == null && keyManagerFactory == null) {
|
if (key == null && keyManagerFactory == null) {
|
||||||
throw new NullPointerException("key, keyManagerFactory");
|
throw new NullPointerException("key, keyManagerFactory");
|
||||||
@ -81,10 +83,10 @@ final class JdkSslServerContext extends JdkSslContext {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (trustCertCollection != null) {
|
if (trustCertCollection != null) {
|
||||||
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
|
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
|
||||||
}
|
}
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
keyManagerFactory = buildKeyManagerFactory(keyCertChain, key, keyPassword, keyManagerFactory);
|
keyManagerFactory = buildKeyManagerFactory(keyCertChain, key, keyPassword, keyManagerFactory, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the SSLContext to work with our key managers.
|
// Initialize the SSLContext to work with our key managers.
|
||||||
|
@ -46,7 +46,8 @@ final class OpenSslClientContext extends OpenSslContext {
|
|||||||
String[] protocols,
|
String[] protocols,
|
||||||
long sessionCacheSize,
|
long sessionCacheSize,
|
||||||
long sessionTimeout,
|
long sessionTimeout,
|
||||||
boolean enableOcsp)
|
boolean enableOcsp,
|
||||||
|
String keyStore)
|
||||||
throws SSLException {
|
throws SSLException {
|
||||||
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
|
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
|
||||||
ClientAuth.NONE, protocols, false, enableOcsp);
|
ClientAuth.NONE, protocols, false, enableOcsp);
|
||||||
@ -54,7 +55,7 @@ final class OpenSslClientContext extends OpenSslContext {
|
|||||||
try {
|
try {
|
||||||
OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
|
OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
|
||||||
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
||||||
keyCertChain, key, keyPassword, keyManagerFactory);
|
keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -48,7 +48,8 @@ final class OpenSslServerContext extends OpenSslContext {
|
|||||||
ClientAuth clientAuth,
|
ClientAuth clientAuth,
|
||||||
String[] protocols,
|
String[] protocols,
|
||||||
boolean startTls,
|
boolean startTls,
|
||||||
boolean enableOcsp)
|
boolean enableOcsp,
|
||||||
|
String keyStore)
|
||||||
throws SSLException {
|
throws SSLException {
|
||||||
super(ciphers, cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER,
|
super(ciphers, cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER,
|
||||||
keyCertChain, clientAuth, protocols, startTls, enableOcsp);
|
keyCertChain, clientAuth, protocols, startTls, enableOcsp);
|
||||||
@ -57,7 +58,7 @@ final class OpenSslServerContext extends OpenSslContext {
|
|||||||
try {
|
try {
|
||||||
OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
|
OpenSslKeyMaterialProvider.validateKeyMaterialSupported(keyCertChain, key, keyPassword);
|
||||||
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
||||||
keyCertChain, key, keyPassword, keyManagerFactory);
|
keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
@ -53,6 +53,8 @@ import java.util.Map;
|
|||||||
* Special {@link KeyManagerFactory} that pre-compute the keymaterial used when {@link SslProvider#OPENSSL} or
|
* Special {@link KeyManagerFactory} that pre-compute the keymaterial used when {@link SslProvider#OPENSSL} or
|
||||||
* {@link SslProvider#OPENSSL_REFCNT} is used and so will improve handshake times and its performance.
|
* {@link SslProvider#OPENSSL_REFCNT} is used and so will improve handshake times and its performance.
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
* Because the keymaterial is pre-computed any modification to the {@link KeyStore} is ignored after
|
* Because the keymaterial is pre-computed any modification to the {@link KeyStore} is ignored after
|
||||||
* {@link #init(KeyStore, char[])} is called.
|
* {@link #init(KeyStore, char[])} is called.
|
||||||
*
|
*
|
||||||
|
@ -62,13 +62,13 @@ public final class ReferenceCountedOpenSslClientContext extends ReferenceCounted
|
|||||||
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
|
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers,
|
||||||
CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
||||||
String[] protocols, long sessionCacheSize, long sessionTimeout,
|
String[] protocols, long sessionCacheSize, long sessionTimeout,
|
||||||
boolean enableOcsp) throws SSLException {
|
boolean enableOcsp, String keyStore) throws SSLException {
|
||||||
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
|
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_CLIENT, keyCertChain,
|
||||||
ClientAuth.NONE, protocols, false, enableOcsp, true);
|
ClientAuth.NONE, protocols, false, enableOcsp, true);
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
||||||
keyCertChain, key, keyPassword, keyManagerFactory);
|
keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -86,8 +86,9 @@ public final class ReferenceCountedOpenSslClientContext extends ReferenceCounted
|
|||||||
OpenSslEngineMap engineMap,
|
OpenSslEngineMap engineMap,
|
||||||
X509Certificate[] trustCertCollection,
|
X509Certificate[] trustCertCollection,
|
||||||
TrustManagerFactory trustManagerFactory,
|
TrustManagerFactory trustManagerFactory,
|
||||||
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
|
X509Certificate[] keyCertChain, PrivateKey key,
|
||||||
KeyManagerFactory keyManagerFactory) throws SSLException {
|
String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
|
String keyStore) throws SSLException {
|
||||||
if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
|
if (key == null && keyCertChain != null || key != null && keyCertChain == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Either both keyCertChain and key needs to be null or none of them");
|
"Either both keyCertChain and key needs to be null or none of them");
|
||||||
@ -107,7 +108,7 @@ public final class ReferenceCountedOpenSslClientContext extends ReferenceCounted
|
|||||||
// javadocs state that keyManagerFactory has precedent over keyCertChain
|
// javadocs state that keyManagerFactory has precedent over keyCertChain
|
||||||
if (keyManagerFactory == null && keyCertChain != null) {
|
if (keyManagerFactory == null && keyCertChain != null) {
|
||||||
char[] keyPasswordChars = keyStorePassword(keyPassword);
|
char[] keyPasswordChars = keyStorePassword(keyPassword);
|
||||||
KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars);
|
KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
|
||||||
if (ks.aliases().hasMoreElements()) {
|
if (ks.aliases().hasMoreElements()) {
|
||||||
keyManagerFactory = new OpenSslX509KeyManagerFactory();
|
keyManagerFactory = new OpenSslX509KeyManagerFactory();
|
||||||
} else {
|
} else {
|
||||||
@ -140,7 +141,7 @@ public final class ReferenceCountedOpenSslClientContext extends ReferenceCounted
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (trustCertCollection != null) {
|
if (trustCertCollection != null) {
|
||||||
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
|
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
|
||||||
} else if (trustManagerFactory == null) {
|
} else if (trustManagerFactory == null) {
|
||||||
trustManagerFactory = TrustManagerFactory.getInstance(
|
trustManagerFactory = TrustManagerFactory.getInstance(
|
||||||
TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
@ -54,25 +54,25 @@ public final class ReferenceCountedOpenSslServerContext extends ReferenceCounted
|
|||||||
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
||||||
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
|
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
|
||||||
boolean enableOcsp) throws SSLException {
|
boolean enableOcsp, String keyStore) throws SSLException {
|
||||||
this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
|
this(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory, ciphers,
|
||||||
cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
|
cipherFilter, toNegotiator(apn), sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
|
||||||
enableOcsp);
|
enableOcsp, keyStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReferenceCountedOpenSslServerContext(
|
ReferenceCountedOpenSslServerContext(
|
||||||
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
|
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
|
||||||
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
|
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, OpenSslApplicationProtocolNegotiator apn,
|
||||||
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
|
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
|
||||||
boolean enableOcsp) throws SSLException {
|
boolean enableOcsp, String keyStore) throws SSLException {
|
||||||
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
|
super(ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, SSL.SSL_MODE_SERVER, keyCertChain,
|
||||||
clientAuth, protocols, startTls, enableOcsp, true);
|
clientAuth, protocols, startTls, enableOcsp, true);
|
||||||
// Create a new SSL_CTX and configure it.
|
// Create a new SSL_CTX and configure it.
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
sessionContext = newSessionContext(this, ctx, engineMap, trustCertCollection, trustManagerFactory,
|
||||||
keyCertChain, key, keyPassword, keyManagerFactory);
|
keyCertChain, key, keyPassword, keyManagerFactory, keyStore);
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
@ -91,7 +91,8 @@ public final class ReferenceCountedOpenSslServerContext extends ReferenceCounted
|
|||||||
X509Certificate[] trustCertCollection,
|
X509Certificate[] trustCertCollection,
|
||||||
TrustManagerFactory trustManagerFactory,
|
TrustManagerFactory trustManagerFactory,
|
||||||
X509Certificate[] keyCertChain, PrivateKey key,
|
X509Certificate[] keyCertChain, PrivateKey key,
|
||||||
String keyPassword, KeyManagerFactory keyManagerFactory)
|
String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
|
String keyStore)
|
||||||
throws SSLException {
|
throws SSLException {
|
||||||
OpenSslKeyMaterialProvider keyMaterialProvider = null;
|
OpenSslKeyMaterialProvider keyMaterialProvider = null;
|
||||||
try {
|
try {
|
||||||
@ -110,7 +111,7 @@ public final class ReferenceCountedOpenSslServerContext extends ReferenceCounted
|
|||||||
// keyManagerFactory for the server so build one if it is not specified.
|
// keyManagerFactory for the server so build one if it is not specified.
|
||||||
if (keyManagerFactory == null) {
|
if (keyManagerFactory == null) {
|
||||||
char[] keyPasswordChars = keyStorePassword(keyPassword);
|
char[] keyPasswordChars = keyStorePassword(keyPassword);
|
||||||
KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars);
|
KeyStore ks = buildKeyStore(keyCertChain, key, keyPasswordChars, keyStore);
|
||||||
if (ks.aliases().hasMoreElements()) {
|
if (ks.aliases().hasMoreElements()) {
|
||||||
keyManagerFactory = new OpenSslX509KeyManagerFactory();
|
keyManagerFactory = new OpenSslX509KeyManagerFactory();
|
||||||
} else {
|
} else {
|
||||||
@ -129,7 +130,7 @@ public final class ReferenceCountedOpenSslServerContext extends ReferenceCounted
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (trustCertCollection != null) {
|
if (trustCertCollection != null) {
|
||||||
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory);
|
trustManagerFactory = buildTrustManagerFactory(trustCertCollection, trustManagerFactory, keyStore);
|
||||||
} else if (trustManagerFactory == null) {
|
} else if (trustManagerFactory == null) {
|
||||||
// Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
|
// Mimic the way SSLContext.getInstance(KeyManager[], null, null) works
|
||||||
trustManagerFactory = TrustManagerFactory.getInstance(
|
trustManagerFactory = TrustManagerFactory.getInstance(
|
||||||
|
@ -339,7 +339,7 @@ public abstract class SslContext {
|
|||||||
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
||||||
long sessionCacheSize, long sessionTimeout) throws SSLException {
|
long sessionCacheSize, long sessionTimeout) throws SSLException {
|
||||||
return newServerContext(provider, null, null, certChainFile, keyFile, keyPassword, null,
|
return newServerContext(provider, null, null, certChainFile, keyFile, keyPassword, null,
|
||||||
ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
|
ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, KeyStore.getDefaultType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -382,12 +382,57 @@ public abstract class SslContext {
|
|||||||
File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
|
File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
||||||
long sessionCacheSize, long sessionTimeout) throws SSLException {
|
long sessionCacheSize, long sessionTimeout) throws SSLException {
|
||||||
|
return newServerContext(provider, trustCertCollectionFile, trustManagerFactory, keyCertChainFile,
|
||||||
|
keyFile, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn,
|
||||||
|
sessionCacheSize, sessionTimeout, KeyStore.getDefaultType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new server-side {@link SslContext}.
|
||||||
|
* @param provider the {@link SslContext} implementation to use.
|
||||||
|
* {@code null} to use the current default one.
|
||||||
|
* @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
|
||||||
|
* This provides the certificate collection used for mutual authentication.
|
||||||
|
* {@code null} to use the system default
|
||||||
|
* @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
|
||||||
|
* that verifies the certificates sent from clients.
|
||||||
|
* {@code null} to use the default or the results of parsing
|
||||||
|
* {@code trustCertCollectionFile}.
|
||||||
|
* This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
|
||||||
|
* @param keyCertChainFile an X.509 certificate chain file in PEM format
|
||||||
|
* @param keyFile a PKCS#8 private key file in PEM format
|
||||||
|
* @param keyPassword the password of the {@code keyFile}.
|
||||||
|
* {@code null} if it's not password-protected.
|
||||||
|
* @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
|
||||||
|
* that is used to encrypt data being sent to clients.
|
||||||
|
* {@code null} to use the default or the results of parsing
|
||||||
|
* {@code keyCertChainFile} and {@code keyFile}.
|
||||||
|
* This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
|
||||||
|
* @param ciphers the cipher suites to enable, in the order of preference.
|
||||||
|
* {@code null} to use the default cipher suites.
|
||||||
|
* @param cipherFilter a filter to apply over the supplied list of ciphers
|
||||||
|
* Only required if {@code provider} is {@link SslProvider#JDK}
|
||||||
|
* @param apn Provides a means to configure parameters related to application protocol negotiation.
|
||||||
|
* @param sessionCacheSize the size of the cache used for storing SSL session objects.
|
||||||
|
* {@code 0} to use the default value.
|
||||||
|
* @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
|
||||||
|
* {@code 0} to use the default value.
|
||||||
|
* @param keyStore the keystore type that should be used
|
||||||
|
* @return a new server-side {@link SslContext}
|
||||||
|
*/
|
||||||
|
static SslContext newServerContext(
|
||||||
|
SslProvider provider,
|
||||||
|
File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
|
||||||
|
File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
|
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
||||||
|
long sessionCacheSize, long sessionTimeout, String keyStore) throws SSLException {
|
||||||
try {
|
try {
|
||||||
return newServerContextInternal(provider, null, toX509Certificates(trustCertCollectionFile),
|
return newServerContextInternal(provider, null, toX509Certificates(trustCertCollectionFile),
|
||||||
trustManagerFactory, toX509Certificates(keyCertChainFile),
|
trustManagerFactory, toX509Certificates(keyCertChainFile),
|
||||||
toPrivateKey(keyFile, keyPassword),
|
toPrivateKey(keyFile, keyPassword),
|
||||||
keyPassword, keyManagerFactory, ciphers, cipherFilter, apn,
|
keyPassword, keyManagerFactory, ciphers, cipherFilter, apn,
|
||||||
sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false, false);
|
sessionCacheSize, sessionTimeout, ClientAuth.NONE, null,
|
||||||
|
false, false, keyStore);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof SSLException) {
|
if (e instanceof SSLException) {
|
||||||
throw (SSLException) e;
|
throw (SSLException) e;
|
||||||
@ -403,7 +448,7 @@ public abstract class SslContext {
|
|||||||
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
|
||||||
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
|
long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
|
||||||
boolean enableOcsp) throws SSLException {
|
boolean enableOcsp, String keyStoreType) throws SSLException {
|
||||||
|
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
provider = defaultServerProvider();
|
provider = defaultServerProvider();
|
||||||
@ -417,19 +462,19 @@ public abstract class SslContext {
|
|||||||
return new JdkSslServerContext(sslContextProvider,
|
return new JdkSslServerContext(sslContextProvider,
|
||||||
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
|
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
|
||||||
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
|
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
|
||||||
clientAuth, protocols, startTls);
|
clientAuth, protocols, startTls, keyStoreType);
|
||||||
case OPENSSL:
|
case OPENSSL:
|
||||||
verifyNullSslContextProvider(provider, sslContextProvider);
|
verifyNullSslContextProvider(provider, sslContextProvider);
|
||||||
return new OpenSslServerContext(
|
return new OpenSslServerContext(
|
||||||
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
|
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
|
||||||
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
|
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
|
||||||
clientAuth, protocols, startTls, enableOcsp);
|
clientAuth, protocols, startTls, enableOcsp, keyStoreType);
|
||||||
case OPENSSL_REFCNT:
|
case OPENSSL_REFCNT:
|
||||||
verifyNullSslContextProvider(provider, sslContextProvider);
|
verifyNullSslContextProvider(provider, sslContextProvider);
|
||||||
return new ReferenceCountedOpenSslServerContext(
|
return new ReferenceCountedOpenSslServerContext(
|
||||||
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
|
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
|
||||||
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
|
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
|
||||||
clientAuth, protocols, startTls, enableOcsp);
|
clientAuth, protocols, startTls, enableOcsp, keyStoreType);
|
||||||
default:
|
default:
|
||||||
throw new Error(provider.toString());
|
throw new Error(provider.toString());
|
||||||
}
|
}
|
||||||
@ -745,7 +790,8 @@ public abstract class SslContext {
|
|||||||
toX509Certificates(trustCertCollectionFile), trustManagerFactory,
|
toX509Certificates(trustCertCollectionFile), trustManagerFactory,
|
||||||
toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword),
|
toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword),
|
||||||
keyPassword, keyManagerFactory, ciphers, cipherFilter,
|
keyPassword, keyManagerFactory, ciphers, cipherFilter,
|
||||||
apn, null, sessionCacheSize, sessionTimeout, false);
|
apn, null, sessionCacheSize, sessionTimeout, false,
|
||||||
|
KeyStore.getDefaultType());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof SSLException) {
|
if (e instanceof SSLException) {
|
||||||
throw (SSLException) e;
|
throw (SSLException) e;
|
||||||
@ -760,7 +806,7 @@ public abstract class SslContext {
|
|||||||
X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory,
|
X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory,
|
||||||
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
|
||||||
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
|
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
|
||||||
long sessionCacheSize, long sessionTimeout, boolean enableOcsp) throws SSLException {
|
long sessionCacheSize, long sessionTimeout, boolean enableOcsp, String keyStoreType) throws SSLException {
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
provider = defaultClientProvider();
|
provider = defaultClientProvider();
|
||||||
}
|
}
|
||||||
@ -771,19 +817,20 @@ public abstract class SslContext {
|
|||||||
}
|
}
|
||||||
return new JdkSslClientContext(sslContextProvider,
|
return new JdkSslClientContext(sslContextProvider,
|
||||||
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
|
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
|
||||||
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout);
|
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize,
|
||||||
|
sessionTimeout, keyStoreType);
|
||||||
case OPENSSL:
|
case OPENSSL:
|
||||||
verifyNullSslContextProvider(provider, sslContextProvider);
|
verifyNullSslContextProvider(provider, sslContextProvider);
|
||||||
return new OpenSslClientContext(
|
return new OpenSslClientContext(
|
||||||
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
|
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
|
||||||
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
|
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
|
||||||
enableOcsp);
|
enableOcsp, keyStoreType);
|
||||||
case OPENSSL_REFCNT:
|
case OPENSSL_REFCNT:
|
||||||
verifyNullSslContextProvider(provider, sslContextProvider);
|
verifyNullSslContextProvider(provider, sslContextProvider);
|
||||||
return new ReferenceCountedOpenSslClientContext(
|
return new ReferenceCountedOpenSslClientContext(
|
||||||
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
|
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
|
||||||
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
|
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
|
||||||
enableOcsp);
|
enableOcsp, keyStoreType);
|
||||||
default:
|
default:
|
||||||
throw new Error(provider.toString());
|
throw new Error(provider.toString());
|
||||||
}
|
}
|
||||||
@ -1026,16 +1073,21 @@ public abstract class SslContext {
|
|||||||
/**
|
/**
|
||||||
* Generates a new {@link KeyStore}.
|
* Generates a new {@link KeyStore}.
|
||||||
*
|
*
|
||||||
* @param certChain a X.509 certificate chain
|
* @param certChain an X.509 certificate chain
|
||||||
* @param key a PKCS#8 private key
|
* @param key a PKCS#8 private key
|
||||||
* @param keyPasswordChars the password of the {@code keyFile}.
|
* @param keyPasswordChars the password of the {@code keyFile}.
|
||||||
* {@code null} if it's not password-protected.
|
* {@code null} if it's not password-protected.
|
||||||
|
* @param keyStoreType The KeyStore Type you want to use
|
||||||
* @return generated {@link KeyStore}.
|
* @return generated {@link KeyStore}.
|
||||||
*/
|
*/
|
||||||
static KeyStore buildKeyStore(X509Certificate[] certChain, PrivateKey key, char[] keyPasswordChars)
|
static KeyStore buildKeyStore(X509Certificate[] certChain, PrivateKey key,
|
||||||
|
char[] keyPasswordChars, String keyStoreType)
|
||||||
throws KeyStoreException, NoSuchAlgorithmException,
|
throws KeyStoreException, NoSuchAlgorithmException,
|
||||||
CertificateException, IOException {
|
CertificateException, IOException {
|
||||||
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
if (keyStoreType == null) {
|
||||||
|
keyStoreType = KeyStore.getDefaultType();
|
||||||
|
}
|
||||||
|
KeyStore ks = KeyStore.getInstance(keyStoreType);
|
||||||
ks.load(null, null);
|
ks.load(null, null);
|
||||||
ks.setKeyEntry(ALIAS, key, keyPasswordChars, certChain);
|
ks.setKeyEntry(ALIAS, key, keyPasswordChars, certChain);
|
||||||
return ks;
|
return ks;
|
||||||
@ -1095,9 +1147,22 @@ public abstract class SslContext {
|
|||||||
protected static TrustManagerFactory buildTrustManagerFactory(
|
protected static TrustManagerFactory buildTrustManagerFactory(
|
||||||
File certChainFile, TrustManagerFactory trustManagerFactory)
|
File certChainFile, TrustManagerFactory trustManagerFactory)
|
||||||
throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
|
throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
|
||||||
|
return buildTrustManagerFactory(certChainFile, trustManagerFactory, KeyStore.getDefaultType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a {@link TrustManagerFactory} from a certificate chain file.
|
||||||
|
* @param certChainFile The certificate file to build from.
|
||||||
|
* @param trustManagerFactory The existing {@link TrustManagerFactory} that will be used if not {@code null}.
|
||||||
|
* @param keyType The KeyStore Type you want to use
|
||||||
|
* @return A {@link TrustManagerFactory} which contains the certificates in {@code certChainFile}
|
||||||
|
*/
|
||||||
|
static TrustManagerFactory buildTrustManagerFactory(
|
||||||
|
File certChainFile, TrustManagerFactory trustManagerFactory, String keyType)
|
||||||
|
throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
|
||||||
X509Certificate[] x509Certs = toX509Certificates(certChainFile);
|
X509Certificate[] x509Certs = toX509Certificates(certChainFile);
|
||||||
|
|
||||||
return buildTrustManagerFactory(x509Certs, trustManagerFactory);
|
return buildTrustManagerFactory(x509Certs, trustManagerFactory, keyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static X509Certificate[] toX509Certificates(File file) throws CertificateException {
|
static X509Certificate[] toX509Certificates(File file) throws CertificateException {
|
||||||
@ -1141,9 +1206,12 @@ public abstract class SslContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static TrustManagerFactory buildTrustManagerFactory(
|
static TrustManagerFactory buildTrustManagerFactory(
|
||||||
X509Certificate[] certCollection, TrustManagerFactory trustManagerFactory)
|
X509Certificate[] certCollection, TrustManagerFactory trustManagerFactory, String keyStoreType)
|
||||||
throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
|
throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
|
||||||
final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
|
if (keyStoreType == null) {
|
||||||
|
keyStoreType = KeyStore.getDefaultType();
|
||||||
|
}
|
||||||
|
final KeyStore ks = KeyStore.getInstance(keyStoreType);
|
||||||
ks.load(null, null);
|
ks.load(null, null);
|
||||||
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
@ -1179,10 +1247,22 @@ public abstract class SslContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChain, PrivateKey key, String keyPassword,
|
static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChain, PrivateKey key, String keyPassword,
|
||||||
KeyManagerFactory kmf)
|
KeyManagerFactory kmf, String keyStoreType)
|
||||||
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
||||||
CertificateException, IOException {
|
CertificateException, IOException {
|
||||||
return buildKeyManagerFactory(certChain, KeyManagerFactory.getDefaultAlgorithm(), key, keyPassword, kmf);
|
return buildKeyManagerFactory(certChain, KeyManagerFactory.getDefaultAlgorithm(), key,
|
||||||
|
keyPassword, kmf, keyStoreType);
|
||||||
|
}
|
||||||
|
|
||||||
|
static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChainFile,
|
||||||
|
String keyAlgorithm, PrivateKey key,
|
||||||
|
String keyPassword, KeyManagerFactory kmf,
|
||||||
|
String keyStore)
|
||||||
|
throws KeyStoreException, NoSuchAlgorithmException, IOException,
|
||||||
|
CertificateException, UnrecoverableKeyException {
|
||||||
|
char[] keyPasswordChars = keyStorePassword(keyPassword);
|
||||||
|
KeyStore ks = buildKeyStore(certChainFile, key, keyPasswordChars, keyStore);
|
||||||
|
return buildKeyManagerFactory(ks, keyAlgorithm, keyPasswordChars, kmf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChainFile,
|
static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChainFile,
|
||||||
@ -1191,7 +1271,7 @@ public abstract class SslContext {
|
|||||||
throws KeyStoreException, NoSuchAlgorithmException, IOException,
|
throws KeyStoreException, NoSuchAlgorithmException, IOException,
|
||||||
CertificateException, UnrecoverableKeyException {
|
CertificateException, UnrecoverableKeyException {
|
||||||
char[] keyPasswordChars = keyStorePassword(keyPassword);
|
char[] keyPasswordChars = keyStorePassword(keyPassword);
|
||||||
KeyStore ks = buildKeyStore(certChainFile, key, keyPasswordChars);
|
KeyStore ks = buildKeyStore(certChainFile, key, keyPasswordChars, KeyStore.getDefaultType());
|
||||||
return buildKeyManagerFactory(ks, keyAlgorithm, keyPasswordChars, kmf);
|
return buildKeyManagerFactory(ks, keyAlgorithm, keyPasswordChars, kmf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import static java.util.Objects.requireNonNull;
|
|||||||
|
|
||||||
import io.netty.util.internal.UnstableApi;
|
import io.netty.util.internal.UnstableApi;
|
||||||
|
|
||||||
|
import java.security.KeyStore;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import javax.net.ssl.KeyManagerFactory;
|
import javax.net.ssl.KeyManagerFactory;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
@ -149,6 +150,7 @@ public final class SslContextBuilder {
|
|||||||
private String[] protocols;
|
private String[] protocols;
|
||||||
private boolean startTls;
|
private boolean startTls;
|
||||||
private boolean enableOcsp;
|
private boolean enableOcsp;
|
||||||
|
private String keyStoreType = KeyStore.getDefaultType();
|
||||||
|
|
||||||
private SslContextBuilder(boolean forServer) {
|
private SslContextBuilder(boolean forServer) {
|
||||||
this.forServer = forServer;
|
this.forServer = forServer;
|
||||||
@ -162,6 +164,14 @@ public final class SslContextBuilder {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link KeyStore} type that should be used. {@code null} uses the default one.
|
||||||
|
*/
|
||||||
|
public SslContextBuilder keyStoreType(String keyStoreType) {
|
||||||
|
this.keyStoreType = keyStoreType;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The SSLContext {@link Provider} to use. {@code null} uses the default one. This is only
|
* The SSLContext {@link Provider} to use. {@code null} uses the default one. This is only
|
||||||
* used with {@link SslProvider#JDK}.
|
* used with {@link SslProvider#JDK}.
|
||||||
@ -447,11 +457,11 @@ public final class SslContextBuilder {
|
|||||||
return SslContext.newServerContextInternal(provider, sslContextProvider, trustCertCollection,
|
return SslContext.newServerContextInternal(provider, sslContextProvider, trustCertCollection,
|
||||||
trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
|
trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
|
||||||
ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
|
ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls,
|
||||||
enableOcsp);
|
enableOcsp, keyStoreType);
|
||||||
} else {
|
} else {
|
||||||
return SslContext.newClientContextInternal(provider, sslContextProvider, trustCertCollection,
|
return SslContext.newClientContextInternal(provider, sslContextProvider, trustCertCollection,
|
||||||
trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
|
trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
|
||||||
ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, enableOcsp);
|
ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout, enableOcsp, keyStoreType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ import java.util.Date;
|
|||||||
* It is purely for testing purposes, and thus it is very insecure.
|
* It is purely for testing purposes, and thus it is very insecure.
|
||||||
* It even uses an insecure pseudo-random generator for faster generation internally.
|
* It even uses an insecure pseudo-random generator for faster generation internally.
|
||||||
* </p><p>
|
* </p><p>
|
||||||
* A X.509 certificate file and a RSA private key file are generated in a system's temporary directory using
|
* An X.509 certificate file and a RSA private key file are generated in a system's temporary directory using
|
||||||
* {@link java.io.File#createTempFile(String, String)}, and they are deleted when the JVM exits using
|
* {@link java.io.File#createTempFile(String, String)}, and they are deleted when the JVM exits using
|
||||||
* {@link java.io.File#deleteOnExit()}.
|
* {@link java.io.File#deleteOnExit()}.
|
||||||
* </p><p>
|
* </p><p>
|
||||||
|
@ -19,7 +19,6 @@ import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
|
|||||||
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
|
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
|
||||||
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
|
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
|
||||||
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
|
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
|
||||||
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory;
|
|
||||||
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
@ -34,7 +33,6 @@ import org.junit.runner.RunWith;
|
|||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLHandshakeException;
|
import javax.net.ssl.SSLHandshakeException;
|
||||||
|
@ -2915,7 +2915,7 @@ public abstract class SSLEngineTest {
|
|||||||
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||||
KeyManagerFactory kmf = useKeyManagerFactory ?
|
KeyManagerFactory kmf = useKeyManagerFactory ?
|
||||||
SslContext.buildKeyManagerFactory(
|
SslContext.buildKeyManagerFactory(
|
||||||
new java.security.cert.X509Certificate[] { ssc.cert()}, ssc.key(), null, null) : null;
|
new java.security.cert.X509Certificate[] { ssc.cert()}, ssc.key(), null, null, null) : null;
|
||||||
|
|
||||||
SslContextBuilder clientContextBuilder = SslContextBuilder.forClient();
|
SslContextBuilder clientContextBuilder = SslContextBuilder.forClient();
|
||||||
if (mutualAuth) {
|
if (mutualAuth) {
|
||||||
@ -3261,7 +3261,7 @@ public abstract class SSLEngineTest {
|
|||||||
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
|
||||||
CertificateException, IOException {
|
CertificateException, IOException {
|
||||||
return SslContext.buildKeyManagerFactory(
|
return SslContext.buildKeyManagerFactory(
|
||||||
new java.security.cert.X509Certificate[] { ssc.cert() }, ssc.key(), null, null);
|
new java.security.cert.X509Certificate[] { ssc.cert() }, ssc.key(), null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class TestTrustManagerFactory extends X509ExtendedTrustManager {
|
private final class TestTrustManagerFactory extends X509ExtendedTrustManager {
|
||||||
|
@ -264,7 +264,7 @@ final class SniClientJava8TestUtil {
|
|||||||
IOException, CertificateException {
|
IOException, CertificateException {
|
||||||
return new SniX509KeyManagerFactory(
|
return new SniX509KeyManagerFactory(
|
||||||
new SNIHostName(hostname), SslContext.buildKeyManagerFactory(
|
new SNIHostName(hostname), SslContext.buildKeyManagerFactory(
|
||||||
new X509Certificate[] { cert.cert() }, cert.key(), null, null));
|
new X509Certificate[] { cert.cert() }, cert.key(), null, null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class SniX509KeyManagerFactory extends KeyManagerFactory {
|
private static final class SniX509KeyManagerFactory extends KeyManagerFactory {
|
||||||
|
@ -107,8 +107,7 @@ public class SniClientTest {
|
|||||||
} else {
|
} else {
|
||||||
// The used OpenSSL version does support a KeyManagerFactory, so use it.
|
// The used OpenSSL version does support a KeyManagerFactory, so use it.
|
||||||
KeyManagerFactory kmf = SniClientJava8TestUtil.newSniX509KeyManagerFactory(cert, sniHostName);
|
KeyManagerFactory kmf = SniClientJava8TestUtil.newSniX509KeyManagerFactory(cert, sniHostName);
|
||||||
|
sslServerContext = SslContextBuilder.forServer(kmf)
|
||||||
sslServerContext = SslContextBuilder.forServer(kmf)
|
|
||||||
.sslProvider(sslServerProvider)
|
.sslProvider(sslServerProvider)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,17 @@ public class SslContextBuilderTest {
|
|||||||
testClientContext(SslProvider.OPENSSL);
|
testClientContext(SslProvider.OPENSSL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeyStoreTypeJdk() throws Exception {
|
||||||
|
testKeyStoreType(SslProvider.JDK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeyStoreTypeOpenssl() throws Exception {
|
||||||
|
Assume.assumeTrue(OpenSsl.isAvailable());
|
||||||
|
testKeyStoreType(SslProvider.OPENSSL);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerContextFromFileJdk() throws Exception {
|
public void testServerContextFromFileJdk() throws Exception {
|
||||||
testServerContextFromFile(SslProvider.JDK);
|
testServerContextFromFile(SslProvider.JDK);
|
||||||
@ -141,6 +152,17 @@ public class SslContextBuilderTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void testKeyStoreType(SslProvider provider) throws Exception {
|
||||||
|
SelfSignedCertificate cert = new SelfSignedCertificate();
|
||||||
|
SslContextBuilder builder = SslContextBuilder.forServer(cert.certificate(), cert.privateKey())
|
||||||
|
.sslProvider(provider)
|
||||||
|
.keyStoreType("PKCS12");
|
||||||
|
SslContext context = builder.build();
|
||||||
|
SSLEngine engine = context.newEngine(UnpooledByteBufAllocator.DEFAULT);
|
||||||
|
engine.closeInbound();
|
||||||
|
engine.closeOutbound();
|
||||||
|
}
|
||||||
|
|
||||||
private static void testInvalidCipher(SslProvider provider) throws Exception {
|
private static void testInvalidCipher(SslProvider provider) throws Exception {
|
||||||
SelfSignedCertificate cert = new SelfSignedCertificate();
|
SelfSignedCertificate cert = new SelfSignedCertificate();
|
||||||
SslContextBuilder builder = SslContextBuilder.forClient()
|
SslContextBuilder builder = SslContextBuilder.forClient()
|
||||||
|
@ -110,7 +110,7 @@ public class SslContextTrustManagerTest {
|
|||||||
throws Exception {
|
throws Exception {
|
||||||
X509Certificate[] certCollection = loadCertCollection(resourceNames);
|
X509Certificate[] certCollection = loadCertCollection(resourceNames);
|
||||||
TrustManagerFactory tmf = SslContext.buildTrustManagerFactory(
|
TrustManagerFactory tmf = SslContext.buildTrustManagerFactory(
|
||||||
certCollection, null);
|
certCollection, null, null);
|
||||||
|
|
||||||
for (TrustManager tm : tmf.getTrustManagers()) {
|
for (TrustManager tm : tmf.getTrustManagers()) {
|
||||||
if (tm instanceof X509TrustManager) {
|
if (tm instanceof X509TrustManager) {
|
||||||
|
Loading…
Reference in New Issue
Block a user