如何使用 Java 中的 X.509 证书签署 HTTP 请求?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2916075/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 23:26:44  来源:igfitidea点击:

How do I sign a HTTP request with a X.509 certificate in Java?

javahttphttpsx509certificateclient-certificates

提问by Rune

How do I perform an HTTP request and sign it with a X.509 certificate using Java?

如何使用 Java 执行 HTTP 请求并使用 X.509 证书对其进行签名?

I usually program in C#. Now, what I would like to do is something similar to the following, only in Java:

我通常用 C# 编程。现在,我想做的是类似于以下内容,仅在 Java 中:

 private HttpWebRequest CreateRequest(Uri uri, X509Certificate2 cert) 
 {
     HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
     request.ClientCertificates.Add(cert);
     /* ... */
     return request;
 }

In Java I have created a java.security.cert.X509Certificateinstance but I cannot figure out how to associate it to a HTTP request. I can create a HTTP request using a java.net.URL instance, but I don't seem to be able to associate my certificate with that instance (and I'm not sure whether using java.net.URL is even appropriate).

在 Java 中,我创建了一个java.security.cert.X509Certificate实例,但我不知道如何将它与 HTTP 请求相关联。我可以使用 java.net.URL 实例创建 HTTP 请求,但我似乎无法将我的证书与该实例相关联(我不确定使用 java.net.URL 是否合适)。

回答by jasonmp85

I'm not a C# programmer, but I'm presuming that code makes a call using HTTPS/TLS and provides a client certificate for authentication? Aka, you're not asking how to use WS-Security, right?

我不是 C# 程序员,但我假设代码使用 HTTPS/TLS 进行调用并提供客户端证书进行身份验证?也就是,您不是在问如何使用 WS-Security,对吗?

In that case, I think the answers hereand herewill be of use to you. You need to use an openssl utility to import your certificate into a p12 client keystore. If your server is using a non-standard CA or self-signed cert, you'll need to set up a client truststore with those certificates as well.

在这种情况下,我认为此处此处的答案对您有用。您需要使用 openssl 实用程序将您的证书导入 p12 客户端密钥库。如果您的服务器使用非标准 CA 或自签名证书,您还需要使用这些证书设置客户端信任库。

At this point, look at the questions I've linked: you'll need to specify a whole slew of JVM arguments. Finally, try to make your call again (using standard Java objects or httpclient). The client should accept the server cert if your truststore is correct and the server should ask for a client cert. If your keystore is set up correctly, the client with authenticate with the X.509 client cert and you'll be good to go.

在这一点上,看看我链接的问题:您需要指定一整套 JVM 参数。最后,尝试再次调用(使用标准 Java 对象或 httpclient)。如果您的信任库正确,则客户端应接受服务器证书,并且服务器应要求提供客户端证书。如果您的密钥库设置正确,客户端使用 X.509 客户端证书进行身份验证,您就可以开始了。

回答by Bruno

It looks like you're trying to use HTTPS with client-certificate authentication. I'm assuming that your server is configured to request this (because the client certificate can only be requested by the server).

看起来您正在尝试将 HTTPS 与客户端证书身份验证结合使用。我假设您的服务器配置为请求此(因为客户端证书只能由服务器请求)。

In Java, java.security.cert.X509Certificateis really just the certificate (a public key certificate, without the private key). What you need on the client side is to configure the private key with it. Assuming that your private key and certificate are in a keystore (to simplify, I'm assuming there's only one suitable certificate with its private key, perhaps with other certificates in the chain, in that keystore), and that you're using the default trust store:

在 Java 中,java.security.cert.X509Certificate实际上只是证书(公钥证书,没有私钥)。您需要在客户端配置私钥。假设您的私钥和证书在密钥库中(为了简化,我假设只有一个合适的证书及其私钥,可能还有链中的其他证书,在该密钥库中),并且您使用的是默认值信托商店:

KeyStore ks = ...
/* load the keystore */

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), null, null);

URL url = new URL("https://example/");
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();

connection.setSSLSocketFactory(sslContext.getSSLSocketFactory());

Other libraries will allow you to set the SSLContextor the KeyStoreslightly differently, but the principles should be the same.

其他库将允许您设置SSLContextKeyStore略有不同,但原则应该是相同的。

(You could also use the javax.net.ssl.keyStoresystem properties if it's appropriate.)

javax.net.ssl.keyStore如果合适,您也可以使用系统属性。)

回答by Peter Bratton

I would recommend the open source HttpClientlibrary from Apache Commons. Covers this use case and many others.

我会推荐来自 Apache Commons 的开源HttpClient库。涵盖此用例和许多其他用例。