我尝试使用Java生成的实际密钥与Netty一起设置SSL,并且在理解所需内容方面遇到了一些麻烦。我基本上修改了EchoClient / EchoServer示例,但尝试添加SSL。我的证书/加密知识非常薄弱,只是随时随地学习。我遵循了一些不同的示例,并使用此帮助程序类为netty服务器创建我的根密钥和证书。
package crypto;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
import org.bouncycastle.util.io.pem.PemObject;
import javax.security.auth.x500.X500PrivateCredential;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import static crypto.JcaUtils.*;
public class KeyStoreHelper {
public static String ROOT_ALIAS = "root";
public static String INTERMEDIATE_ALIAS = "intermediate";
public static String END_ENTITY_ALIAS = "end";
public static char[] keyPassword = "password".toCharArray();
public static final String SERVER_NAME = "server";
public static final char[] SERVER_PASSWORD = "server".toCharArray();
public static final String CLIENT_NAME = "client";
public static final char[] CLIENT_PASSWORD = "client".toCharArray();
public static final String TRUST_STORE_NAME = "trustStore";
public static final char[] TRUST_STORE_PASSWORD = "trust".toCharArray();
static {
Security.addProvider(new BouncyCastleProvider());
}
public static void main(String[] args) throws Exception {
KeyStore store = createKeyStore();
char[] password = "store".toCharArray();
FileOutputStream fileOutputStream = new FileOutputStream("ssl-test.jks");
ByteArrayOutputStream bout = new ByteArrayOutputStream();
// save store
store.store(fileOutputStream, password);
fileOutputStream.close();
CreateSSLKeyStores();
}
public static void CreateSSLKeyStores() throws Exception {
X500PrivateCredential rootCredential = createRootCredential();
JcaUtils.saveCertificateAsPEMFile(rootCredential.getCertificate(), "root8cert.pem");
X500PrivateCredential interCredential = createIntermediateCredential(rootCredential.getPrivateKey(), rootCredential.getCertificate());
X500PrivateCredential endCredential = createEndEntityCredential(interCredential.getPrivateKey(), interCredential.getCertificate());
// client creds
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setKeyEntry(CLIENT_NAME, endCredential.getPrivateKey(), CLIENT_PASSWORD,
new Certificate[] {
endCredential.getCertificate(),
interCredential.getCertificate(),
rootCredential.getCertificate()
});
keyStore.store(new FileOutputStream(CLIENT_NAME + ".jks"), CLIENT_PASSWORD);
// trust store for server and client
keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setCertificateEntry(SERVER_NAME, rootCredential.getCertificate());
keyStore.store(new FileOutputStream(TRUST_STORE_NAME + ".jks"), TRUST_STORE_PASSWORD);
// server creds
keyStore.getInstance("JKS");
keyStore.load(null, null);
keyStore.setKeyEntry(SERVER_NAME, rootCredential.getPrivateKey(), SERVER_PASSWORD,
new Certificate[] {
rootCredential.getCertificate()
});
keyStore.store(new FileOutputStream(SERVER_NAME + ".jks"), SERVER_PASSWORD);
}
public static KeyStore createKeyStore() throws Exception {
KeyStore store = KeyStore.getInstance("JKS");
store.load(null, null);
X500PrivateCredential rootCredential = createRootCredential();
X500PrivateCredential interCredential = createIntermediateCredential(rootCredential.getPrivateKey(), rootCredential.getCertificate());
X500PrivateCredential endCredential = createEndEntityCredential(interCredential.getPrivateKey(), interCredential.getCertificate());
Certificate[] chain = new Certificate[3];
chain[0] = endCredential.getCertificate();
chain[1] = interCredential.getCertificate();
chain[2] = rootCredential.getCertificate();
store.setCertificateEntry(rootCredential.getAlias(), rootCredential.getCertificate());
store.setKeyEntry(endCredential.getAlias(), endCredential.getPrivateKey(), keyPassword, chain);
return store;
}
/**
* Generate a X500PrivateCredential for the root entity.
*
*/
public static X500PrivateCredential createRootCredential() throws Exception {
KeyPair rootPair = generateRSAKeyPair();
X509Certificate rootCert = buildRootCert(rootPair);
JcaPKCS8Generator generator = new JcaPKCS8Generator(rootPair.getPrivate(), null);
PemObject pemObject = generator.generate();
saveCertificateAsPEMFile(pemObject, "root8.pem"); // this works
return new X500PrivateCredential(rootCert, rootPair.getPrivate(), ROOT_ALIAS);
}
/**
* Generate a X500PrivateCredential for the intermediate entity.
*/
public static X500PrivateCredential createIntermediateCredential(PrivateKey caKey, X509Certificate caCert) throws Exception {
KeyPair interPair = generateRSAKeyPair();
X509Certificate interCert = buildIntermediateCert(interPair.getPublic(), caKey, caCert);
return new X500PrivateCredential(interCert, interPair.getPrivate(), INTERMEDIATE_ALIAS);
}
/**
* Generate a X500PrivateCredential for the end entity.
*/
public static X500PrivateCredential createEndEntityCredential(PrivateKey caKey, X509Certificate caCert) throws Exception {
KeyPair endPair = generateRSAKeyPair();
X509Certificate endCert = buildEndEntityCert(endPair.getPublic(), caKey, caCert);
return new X500PrivateCredential(endCert, endPair.getPrivate(), END_ENTITY_ALIAS);
}
}
在我的netty服务器中,我用
启动它Path rootkeyPath = FileSystems.getDefault().getPath("root8.pem");
Path rootkeyCert = FileSystems.getDefault().getPath("root8cert.pem");
// final SslContext sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
final SslContext sslContext = SslContextBuilder.forServer(rootkeyCert.toFile(), rootkeyPath.toFile()).clientAuth(ClientAuth.REQUIRE).build();
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new EchoServerInitializer(sslContext));
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
所以从帮助程序类开始,我基本上会提前创建证书和密钥。所以我给我的服务器根pkcs8密钥和根证书。我的第一个问题是
1)这是正确的吗?我应该给出根密钥和证书吗?我看到很多例子创建了一个信任链,一个终端实体证书,不确定我是否应该在某个地方使用结束或中间?
然后在我的EchoClient中,我尝试做类似的事情。
EventLoopGroup group = new NioEventLoopGroup();
Path rootkeyPath = FileSystems.getDefault().getPath("client.jks");
TrustManagerFactory trustFact = TrustManagerFactory.getInstance("SunX509");
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("trustStore.jks"), "trust".toCharArray());
trustFact.init(trustStore);
// final SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
final SslContext sslContext = SslContextBuilder.forClient().
trustManager(trustFact).build();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(
// SSLEngine engine = sslContext.newEngine(ch.alloc());
// ch.pipeline().addFirst("ssl", new SslHandler(engine, false));
// ch.pipeline().addLast(sslContext.newHandler(ch.alloc(), host, port));
// ch.pipeline().addLast(new EchoClientHandler());
new EchoClientInitializer(sslContext)
);
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
所以这不起作用。老老实实,我不确定在客户端和服务器身份验证SSL方面你应该做些什么。