diff --git a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java index 887a583dbb..e031bd5441 100644 --- a/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/JdkSslContext.java @@ -34,19 +34,15 @@ import java.io.File; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.KeyException; -import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.security.Security; import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -165,6 +161,7 @@ public abstract class JdkSslContext extends SslContext { /** * Returns the JDK {@link SSLSessionContext} object held by this context. */ + @Override public final SSLSessionContext sessionContext() { if (isServer()) { return context().getServerSessionContext(); @@ -318,40 +315,8 @@ public abstract class JdkSslContext extends SslContext { throws KeyStoreException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidAlgorithmParameterException, IOException, CertificateException, KeyException, UnrecoverableKeyException { - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - KeyFactory rsaKF = KeyFactory.getInstance("RSA"); - KeyFactory dsaKF = KeyFactory.getInstance("DSA"); - - ByteBuf encodedKeyBuf = PemReader.readPrivateKey(keyFile); - byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()]; - encodedKeyBuf.readBytes(encodedKey).release(); - char[] keyPasswordChars = keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray(); - PKCS8EncodedKeySpec encodedKeySpec = generateKeySpec(keyPasswordChars, encodedKey); - - PrivateKey key; - try { - key = rsaKF.generatePrivate(encodedKeySpec); - } catch (InvalidKeySpecException ignore) { - key = dsaKF.generatePrivate(encodedKeySpec); - } - - List certChain = new ArrayList(); - ByteBuf[] certs = PemReader.readCertificates(certChainFile); - try { - for (ByteBuf buf: certs) { - certChain.add(cf.generateCertificate(new ByteBufInputStream(buf))); - } - } finally { - for (ByteBuf buf: certs) { - buf.release(); - } - } - - ks.setKeyEntry("key", key, keyPasswordChars, certChain.toArray(new Certificate[certChain.size()])); - + KeyStore ks = buildKeyStore(certChainFile, keyFile, keyPasswordChars); // Set up key manager factory to use our key store if (kmf == null) { kmf = KeyManagerFactory.getInstance(keyAlgorithm); diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java index 816e396034..207c0f0355 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslServerContext.java @@ -15,8 +15,7 @@ */ package io.netty.handler.ssl; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufInputStream; +import io.netty.util.internal.EmptyArrays; import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; @@ -25,16 +24,8 @@ import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509ExtendedTrustManager; import javax.net.ssl.X509TrustManager; import java.io.File; -import java.security.KeyFactory; import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.cert.Certificate; -import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.ArrayList; -import java.util.List; import static io.netty.util.internal.ObjectUtil.*; @@ -294,48 +285,15 @@ public final class OpenSslServerContext extends OpenSslContext { throw new SSLException("failed to set certificate: " + certChainFile + " and " + keyFile, e); } try { - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(null, null); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - KeyFactory rsaKF = KeyFactory.getInstance("RSA"); - KeyFactory dsaKF = KeyFactory.getInstance("DSA"); - - ByteBuf encodedKeyBuf = PemReader.readPrivateKey(keyFile); - byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()]; - encodedKeyBuf.readBytes(encodedKey).release(); - - char[] keyPasswordChars = keyPassword.toCharArray(); - PKCS8EncodedKeySpec encodedKeySpec = generateKeySpec(keyPasswordChars, encodedKey); - - PrivateKey key; - try { - key = rsaKF.generatePrivate(encodedKeySpec); - } catch (InvalidKeySpecException ignore) { - key = dsaKF.generatePrivate(encodedKeySpec); - } - - List certChain = new ArrayList(); - ByteBuf[] certs = PemReader.readCertificates(certChainFile); - try { - for (ByteBuf buf: certs) { - certChain.add(cf.generateCertificate(new ByteBufInputStream(buf))); - } - } finally { - for (ByteBuf buf: certs) { - buf.release(); - } - } - - ks.setKeyEntry("key", key, keyPasswordChars, certChain.toArray(new Certificate[certChain.size()])); + char[] keyPasswordChars = keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray(); + KeyStore ks = buildKeyStore(certChainFile, keyFile, keyPasswordChars); if (trustManagerFactory == null) { // Mimic the way SSLContext.getInstance(KeyManager[], null, null) works trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); - trustManagerFactory.init((KeyStore) null); - } else { - trustManagerFactory.init(ks); } + trustManagerFactory.init(ks); final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers()); diff --git a/handler/src/main/java/io/netty/handler/ssl/SslContext.java b/handler/src/main/java/io/netty/handler/ssl/SslContext.java index ebb735d5c0..6fa3b799cb 100644 --- a/handler/src/main/java/io/netty/handler/ssl/SslContext.java +++ b/handler/src/main/java/io/netty/handler/ssl/SslContext.java @@ -16,7 +16,9 @@ package io.netty.handler.ssl; +import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; @@ -41,11 +43,18 @@ import java.io.File; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; +import java.security.KeyException; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.ArrayList; import java.util.List; /** @@ -861,4 +870,58 @@ public abstract class SslContext { return encryptedPrivateKeyInfo.getKeySpec(cipher); } + + /** + * Generates a new {@link KeyStore}. + * + * @param certChainFile a X.509 certificate chain file in PEM format, + * @param keyFile a PKCS#8 private key file in PEM format, + * @param keyPasswordChars the password of the {@code keyFile}. + * {@code null} if it's not password-protected. + * @return generated {@link KeyStore}. + */ + static KeyStore buildKeyStore(File certChainFile, File keyFile, char[] keyPasswordChars) + throws KeyStoreException, NoSuchAlgorithmException, + NoSuchPaddingException, InvalidKeySpecException, InvalidAlgorithmParameterException, + CertificateException, KeyException, IOException { + ByteBuf encodedKeyBuf = PemReader.readPrivateKey(keyFile); + byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()]; + encodedKeyBuf.readBytes(encodedKey).release(); + + PKCS8EncodedKeySpec encodedKeySpec = generateKeySpec(keyPasswordChars, encodedKey); + + PrivateKey key; + try { + key = KeyFactory.getInstance("RSA").generatePrivate(encodedKeySpec); + } catch (InvalidKeySpecException ignore) { + try { + key = KeyFactory.getInstance("DSA").generatePrivate(encodedKeySpec); + } catch (InvalidKeySpecException ignore2) { + try { + key = KeyFactory.getInstance("EC").generatePrivate(encodedKeySpec); + } catch (InvalidKeySpecException e) { + throw new InvalidKeySpecException("Neither RSA, DSA nor EC worked", e); + } + } + } + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + ByteBuf[] certs = PemReader.readCertificates(certChainFile); + List certChain = new ArrayList(certs.length); + + try { + for (ByteBuf buf: certs) { + certChain.add(cf.generateCertificate(new ByteBufInputStream(buf))); + } + } finally { + for (ByteBuf buf: certs) { + buf.release(); + } + } + + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + ks.setKeyEntry("key", key, keyPasswordChars, certChain.toArray(new Certificate[certChain.size()])); + return ks; + } }