在Netty中设置SSL

时间:2017-07-06 04:42:15

标签: ssl netty

我尝试使用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方面你应该做些什么。

0 个答案:

没有答案