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

2022-01-19 00:00:00 url network-programming security java

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

I need to request a URL from a server that uses client certificates for authentication and can't find a way to do this for my application.

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

My problem is that the Java client I'm working on has the certificate file available locally but due to restrictions on the PCs it will be running on it cannot install the certificate in a keystore.

简而言之,我只是希望能够明确指定用于我需要检索的 URL 的证书.

In short, I just want to be able to explicilty specify the certificate to use for the URL I need to retrieve.

有什么建议吗?

推荐答案

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

It's not clear what the restrictions you're talking about are. More specifically, I'm not sure what you consider the difference between the local certificate file and a keystore. Most keystores are file-based, so you might be able to load the file this way directly, without needing an installation process. Are the restrictions related to the security policies used by the JVM itself (which may prevent you from instantiating KeyStores)?

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

First, it's not just the certificate you need on the client side, but its private key. Often, people use the word "certificate" in this context to mean both, but you do need to make sure your file doesn't contain the certificate without the private key. Typically, you'll find the combination of private key + certificate in a PKCS#12 file (.p12/.pfx), a lot of tools import/export in this format; it's also a keystore format natively supported by the Sun JVM (type PKCS12).

要完成这项工作,您需要配置与适当的密钥库建立连接的原因.SSL/TLS 客户端证书身份验证始终由服务器发起:如果客户端拥有证书(并且想要使用它),则客户端会以证书进行响应.要为特定 URL 配置它,您需要找出连接的原因(可能是 HttpsURLConnection)并将其设置在那里(除非它是在默认上下文中设置的——即使它是在默认上下文,它只会用于请求它的服务器).

To make this work, you need to configure what makes the connection with the appropriate keystore. SSL/TLS client-certificate authentication is always initiated by the server: the client responds with a certificate if it has one (and wants to use it). To configure it for a specific URL, you need to find out what makes the connection (perhaps HttpsURLConnection) and set it there (unless it's set up in the default context -- even if it's set up in the default context, it will only be used for servers that request it).

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

To set up the keystore globally on the JVM (which may be what your restrictions prevent you to do), you can set the javax.net.ssl.keyStore javax.net.ssl.keyStorePassword (and related) system properties. (Because the password could be visible, it's better not to do it on the command line).

这些系统属性用于配置默认的 SSLContext(通常透明地由库或类如 HttpsURLConnection 使用来构建 SSLSocketFactory 然后是 SSLSocket,用这些属性初始化).

These system properties are used for the configuration of the default SSLContext (which is used, often transparently, by libraries or classes such as HttpsURLConnection to build the SSLSocketFactory and then SSLSocket, initialized with those properties).

您可以从您的文件中构建 SSLContext 专门用于该连接.SSLContext 实际上是 SSLSocketFactorySSLEngine 的工厂,您可以在给定的 SSLSocketFactory 中设置代码>HttpsURLConnection.

You could build SSLContext from your file specifically for use for that connection. The SSLContext is effectively a factory for the SSLSocketFactory or SSLEngine, and you can set the SSLSocketFactory in a given HttpsURLConnection.

以下将构建一个 SSLContext 使用/path/to/file.p12"作为您的密钥库(即带有您的私钥和您要发送的证书的密钥库)和保留信任库的默认设置(您还需要捕获输入流的异常).

The following would build an SSLContext using "/path/to/file.p12" as your keystore (that is the one with your private key and the certificate you're going to send) and keep the default settings for the truststore (you'd need to catch the exception for the input stream too).

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);

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

From there you can configure the connection like this (if this is what you're using):

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

一些库会让你直接传递 SSLContext(Apache HTTP Client 4 支持这一点,这可以通过 Apache HTTP Client 3 使用这个.)

Some libraries will let you pass an SSLContext directly (Apache HTTP Client 4 supports that, and this can be done with Apache HTTP Client 3 using this.)

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

Note that you don't need to provide the password as a direct parameter when loading the keystore, you could also use a callback (maybe better from the GUI point of view).

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

Perhaps this library could help (but it's not necessary): you could use the KeystoreLoader for its helpers to do this. There are also SSLContextFactories in this libraries (but you would probably not need any of the wrappers as they tend to be for customizing the trust management or key selection).

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

This is generally how using a client-certificate is configured, but it's difficult to provide more details without clarifications regarding what your restrictions exactly are (and which libraries you're using).

相关文章