如何请求需要客户端证书进行身份验证的 URL

2022-09-02 20:39:53

我需要从使用客户端证书进行身份验证的服务器请求 URL,但找不到为我的应用程序执行此操作的方法。

我的问题是,我正在使用的Java客户端具有本地可用的证书文件,但由于PC上的限制,它将在其上运行,因此无法在密钥库中安装证书。

简而言之,我只想能够明确指定要用于我需要检索的URL的证书。

有什么建议吗?


答案 1

目前尚不清楚您正在谈论的限制是什么。更具体地说,我不确定您认为本地证书文件和密钥库之间的区别是什么。大多数密钥库都是基于文件的,因此您可能能够直接以这种方式加载文件,而无需安装过程。这些限制是否与 JVM 本身使用的安全策略相关(这可能会阻止您实例化 s)?KeyStore

首先,它不仅仅是客户端需要的证书,而是它的私钥。通常,人们在此上下文中使用“证书”一词来表示两者,但您确实需要确保您的文件不包含没有私钥的证书。通常,您会在PKCS#12文件(.p12 / .pfx)中找到私钥+证书的组合,许多工具都以这种格式导入/导出;它也是 Sun JVM(类型)本身支持的密钥库格式。PKCS12

要实现此目的,您需要配置与相应密钥库建立连接的原因。SSL/TLS 客户端证书身份验证始终由服务器启动:如果客户端有证书(并希望使用它),则使用证书进行响应。要为特定的URL配置它,你需要找出建立连接的原因(也许)并将其设置在那里(除非它是在默认上下文中设置的 - 即使它是在默认上下文中设置的,它也只会用于请求它的服务器)。HttpsURLConnection

要在 JVM 上全局设置密钥库(这可能是您的限制所阻止的),您可以设置(和相关)系统属性。(由于密码可能是可见的,因此最好不要在命令行上执行此操作)。javax.net.ssl.keyStorejavax.net.ssl.keyStorePassword

这些系统属性用于配置默认值(通常由库或类透明地使用,例如用于构建 然后,使用这些属性进行初始化)。SSLContextHttpsURLConnectionSSLSocketFactorySSLSocket

您可以从专门用于该连接的文件进行构建。它实际上是 或 的工厂,您可以在给定的 中设置 。SSLContextSSLContextSSLSocketFactorySSLEngineSSLSocketFactoryHttpsURLConnection

下面将使用“/path/to/file.p12”构建一个密钥库(即包含私钥和要发送的证书的密钥库),并保留信任库的默认设置(您还需要捕获输入流的异常)。SSLContext

KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream("/path/to/file.p12");
ks.load(fis, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "password".toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);

从那里,您可以像这样配置连接(如果这是您正在使用的):

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if (connection instanceof HttpsURLConnection) {
    ((HttpsURLConnection)connection)
         .setSSLSocketFactory(sc.getSocketFactory());
}

有些库会允许你直接传递一个(Apache HTTP Client 4支持它,这可以通过Apache HTTP Client 3使用它来完成。SSLContext

请注意,在加载密钥库时,您不需要提供密码作为直接参数,您也可以使用回调(从 GUI 的角度来看可能更好)。

也许这个库可以提供帮助(但这不是必需的):您可以使用KeystoreLoader为其帮助程序执行此操作。此库中还有 SSLContextFactories(但您可能不需要任何包装器,因为它们往往用于自定义信任管理或密钥选择)。

这通常是使用客户端证书的配置方式,但是如果不详细说明您的限制究竟是什么(以及您正在使用的库),则很难提供更多详细信息。


答案 2

您可以在调用应用程序时通过属性更改缺省 JSSE 密钥库。-Djavax.net.ssl.keystore=somefile

因此,您可以使用keytool命令将证书导入密钥库,并调用指向该密钥库的应用程序,例如

keytool -importcert -file mycert -keystore mystore
java -Djavax.net.ssl.keystore=mystore ...