Add support for EC Keys when using SslServerContext
Motivation: Sometimes it's useful to use EC keys and not DSA or RSA. We should support it. Modifications: Support EC keys and share the code between JDK and Openssl impl. Result: It's possible to use EC keys now.
This commit is contained in:
parent
4d56028df5
commit
216d5ee583
@ -34,19 +34,15 @@ 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.KeyFactory;
|
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.UnrecoverableKeyException;
|
import java.security.UnrecoverableKeyException;
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -165,6 +161,7 @@ public abstract class JdkSslContext extends SslContext {
|
|||||||
/**
|
/**
|
||||||
* Returns the JDK {@link SSLSessionContext} object held by this context.
|
* Returns the JDK {@link SSLSessionContext} object held by this context.
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public final SSLSessionContext sessionContext() {
|
public final SSLSessionContext sessionContext() {
|
||||||
if (isServer()) {
|
if (isServer()) {
|
||||||
return context().getServerSessionContext();
|
return context().getServerSessionContext();
|
||||||
@ -318,40 +315,8 @@ public abstract class JdkSslContext extends SslContext {
|
|||||||
throws KeyStoreException, NoSuchAlgorithmException, NoSuchPaddingException,
|
throws KeyStoreException, NoSuchAlgorithmException, NoSuchPaddingException,
|
||||||
InvalidKeySpecException, InvalidAlgorithmParameterException, IOException,
|
InvalidKeySpecException, InvalidAlgorithmParameterException, IOException,
|
||||||
CertificateException, KeyException, UnrecoverableKeyException {
|
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();
|
char[] keyPasswordChars = keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray();
|
||||||
PKCS8EncodedKeySpec encodedKeySpec = generateKeySpec(keyPasswordChars, encodedKey);
|
KeyStore ks = buildKeyStore(certChainFile, keyFile, keyPasswordChars);
|
||||||
|
|
||||||
PrivateKey key;
|
|
||||||
try {
|
|
||||||
key = rsaKF.generatePrivate(encodedKeySpec);
|
|
||||||
} catch (InvalidKeySpecException ignore) {
|
|
||||||
key = dsaKF.generatePrivate(encodedKeySpec);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Certificate> certChain = new ArrayList<Certificate>();
|
|
||||||
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()]));
|
|
||||||
|
|
||||||
// Set up key manager factory to use our key store
|
// Set up key manager factory to use our key store
|
||||||
if (kmf == null) {
|
if (kmf == null) {
|
||||||
kmf = KeyManagerFactory.getInstance(keyAlgorithm);
|
kmf = KeyManagerFactory.getInstance(keyAlgorithm);
|
||||||
|
@ -15,8 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.util.internal.EmptyArrays;
|
||||||
import io.netty.buffer.ByteBufInputStream;
|
|
||||||
import org.apache.tomcat.jni.SSL;
|
import org.apache.tomcat.jni.SSL;
|
||||||
import org.apache.tomcat.jni.SSLContext;
|
import org.apache.tomcat.jni.SSLContext;
|
||||||
|
|
||||||
@ -25,16 +24,8 @@ import javax.net.ssl.TrustManagerFactory;
|
|||||||
import javax.net.ssl.X509ExtendedTrustManager;
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.KeyStore;
|
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.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.*;
|
import static io.netty.util.internal.ObjectUtil.*;
|
||||||
|
|
||||||
@ -266,48 +257,15 @@ public final class OpenSslServerContext extends OpenSslContext {
|
|||||||
throw new SSLException("failed to set certificate: " + certChainFile + " and " + keyFile, e);
|
throw new SSLException("failed to set certificate: " + certChainFile + " and " + keyFile, e);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
KeyStore ks = KeyStore.getInstance("JKS");
|
char[] keyPasswordChars = keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray();
|
||||||
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<Certificate> certChain = new ArrayList<Certificate>();
|
|
||||||
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);
|
||||||
if (trustManagerFactory == null) {
|
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(
|
||||||
TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory.getDefaultAlgorithm());
|
||||||
trustManagerFactory.init((KeyStore) null);
|
|
||||||
} else {
|
|
||||||
trustManagerFactory.init(ks);
|
|
||||||
}
|
}
|
||||||
|
trustManagerFactory.init(ks);
|
||||||
|
|
||||||
final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
|
final X509TrustManager manager = chooseTrustManager(trustManagerFactory.getTrustManagers());
|
||||||
|
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import io.netty.buffer.ByteBufInputStream;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
|
||||||
@ -38,11 +40,18 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.InvalidKeyException;
|
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.NoSuchAlgorithmException;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -668,4 +677,58 @@ public abstract class SslContext {
|
|||||||
|
|
||||||
return encryptedPrivateKeyInfo.getKeySpec(cipher);
|
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<Certificate> certChain = new ArrayList<Certificate>(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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user