具有自签名证书的Java SSL连接,无需将完整密钥库复制到客户端

问题描述:

我正在设置一个Java许可servlet以及一个客户端应用程序,该应用程序将发布新许可证请求并验证该服务器上的现有许可证。 servlet在Tomcat中运行。我已经配置了Tomcat,以便它只允许通过https连接到servlet,这样就可以了。

I am setting up a licensing servlet in Java together with a client app that will post request for new licenses and validate existing licenses at that server. The servlet runs in Tomcat. I've configured Tomcat so that it only allows connections to the servlet over https, and this works just fine.

我使用'keytool -genkey -alias创建了一个自签名证书www.mysite.com -keyalg RSA -keystore license.store' 创建一个文件 license.store 并将tomcat指向此keystoreFile,其密码为 asdf1234

I have created a self-signed certificate using 'keytool -genkey -alias www.mysite.com -keyalg RSA -keystore license.store' which creates a file license.store and pointed tomcat to this keystoreFile with its password asdf1234.

当我尝试通过Java中的https从客户端连接到servlet时,我收到熟悉的 PKIX路径构建失败因为证书不在信任库中。我尝试使用建议修复此问题,从而生成以下代码:

When I just try to connect from the client to the servlet over https in Java, I receive the familiar PKIX path building failed because the certificate is not in the truststore. I tried to fixed this using this suggestion resulting in the code below:

private SSLSocketFactory getSSLFactory() throws Exception {

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream is = this.getClass().getResourceAsStream("license.store");

    if(is ==null) {
        return null;
    }

    keyStore.load(is, "asdf1234".toCharArray());
    is.close();

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(keyStore);

    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(null, tmf.getTrustManagers(), null);

    return ctx.getSocketFactory();
}

之后我打电话:

HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setSSLSocketFactory(getSSLFactory());

这会导致成功连接。

现在的问题是,当我将 license.store 复制到客户端并将其加载到 KeyStore.load时,我才能解决这个问题。 )。复制服务器使用的私钥及其密码到客户端是非常安全的。有没有办法从license.store中提取公钥并使用它?我一直在搜索这个论坛和其他人一天,似乎无法得到它。

Now the problem is that I only get this to work when I copy the license.store to the client and load that into the KeyStore.load(). It doesn't strike me as very safe to copy the private key and its password that the server uses to the client. Is there any way to extract only the public key from the license.store and use that? I've been searching this forum and others for a day now and just can't seem to get it.

你不应该不是要生成公钥 - 私钥对,而是将服务器的证书导入到您的(客户端)Java信任库中。证书不是秘密,因此不会在客户端提供安全风险。请参阅keytool的 -import 选项。这是一个示例

You shouldn't be generating a public-private key pair, but rather import the certificate of the server into your (the client's) Java truststore. The certificate is not a secret, and thus does not provide a security risk on the client side. See the -import option for keytool. Here's in an example.