JAVA - SSL - 客户端证书

Posted

技术标签:

【中文标题】JAVA - SSL - 客户端证书【英文标题】:JAVA - SSL - Client Certifcates 【发布时间】:2012-02-15 10:26:19 【问题描述】:

我一直在使用 JAVA 开发 WS 客户端,但我遇到了 SSL 身份验证问题。 WS 是在 WCF 上创建的,我无法访问服务器,它们通过 HTTPS 工作并使用需要首先安装在客户端上的客户端证书。服务器人员向我发送了我成功安装在操作系统上的 PFX 证书(我正在使用 OS X),然后我可以通过浏览器访问 WS(Safari 或 FF 都是我尝试过的,以前无法访问 WS )。 我认为操作系统中的任何应用程序都会使用此证书,但是当我尝试我的 JAVA 应用程序时它不起作用;起初抛出以下错误:

“javax.net.ssl.SSLHandshakeException:sun.security.validator.ValidatorException:PKIX 路径构建失败:sun.security.provider.certpath.SunCertPathBuilderException:无法找到请求目标的有效证书路径”

我通过将证书导出到 CER 文件并使用 keytool 命令行工具将证书添加到“cacerts”keyStore JAVA 使用来解决这个问题。但是在此错误消失后,以下开始出现:“403,禁止”。这显然是因为它没有使用该站点的 SSL 客户端证书,但我无法找到将其发送给它的方法。任何帮助将不胜感激。

以下是我用来发布到 WS 的代码:

URL url = new URL(p_url);

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);

conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", contentType);

OutputStream out = conn.getOutputStream(); // on this line it shows the error

【问题讨论】:

【参考方案1】:

您可以创建一个特定的SSLContext(使用包含您的客户端证书+私钥的密钥库初始化的KeyManager),从中派生一个SSLSocketFactory,并将其设置到您的HttpsURLConnection中,或者使用全局设置。

您可以设置以下系统属性(用于全局设置):

javax.net.ssl.keyStore=path/to/keystore.pfx javax.net.ssl.keyStoreType=PKCS12 javax.net.ssl.keyStorePassword=xxxxxxxxx

或者,您可以创建自己的KeyManagerFactory/KeyManager,如this answer 中所述。

由于您已在 cacerts 中导入服务器证书,因此请使用 null 作为 SSLContext.init()TrustManager[] 参数(它将采用默认值)。

此外,由于您使用的是 OSX,您可以直接使用 KeychainStore。为此,请使用....keyStore=NONEkeyStoreType=KeychainStorekeyStorePassword=-(任何密码都可以,因为当您从操作系统需要时将授予对密钥的访问权限)。不过,我不确定它是否适用于 Lion。请注意,如果您的商店中有多个证书+私钥,它可能会失败(请参阅this issue)。

【讨论】:

如果您对密钥库/信任库感到困惑,您可能需要阅读以下内容:***.com/a/6341566/372643 谢谢,我确实试过了,但我错过了 keyStoreType=PKCS12。【参考方案2】:

看来您可能需要设置自己的 SSL SocketFactory,

http://vafer.org/blog/20061010073725/

我认为自 2006 年以来情况有所好转,因此您可能只需要在命令行上指定一堆属性:

http://***.com/questions/875467/java-client-certificates-over-https-ssl

【讨论】:

【参考方案3】:

您需要在您的 Java 应用程序中加载他们发送给您的密钥库。 您可以将其作为文件系统从Keystore 对象中加载并使用它。阅读此example,尤其是关于KeyManager 的部分,即createKeyManagers 方法。

另一种选择是从 Windows 加载密钥库。阅读Windows-MY提供者

【讨论】:

看来 OP 已经做到了。阅读他问题中的第二段。

以上是关于JAVA - SSL - 客户端证书的主要内容,如果未能解决你的问题,请参考以下文章

为啥 java 在 SSL 握手期间不发送客户端证书?

在 Java 客户端中接受服务器的自签名 ssl 证书

Java 服务器自签名证书 + 客户端证书和 SSL handshake_failure

如何通过java程序来加载客户端证书进行ssl连接?

Java-HttpClient通过证书实现SSL双向认证(客户端)

java B/S开发,ssl证书是怎么回事