强制SSL客户端套接字发送证书

时间:2012-03-09 23:31:12

标签: java ssl vmware

我正在尝试编写一个客户端(实际上是一个中间件,它是一个实体的客户端,但也充当其他人的服务器)。在其客户端容量中,它应该与另一台服务器(VMware的VirtualCenter)通信,并要求它代表它执行操作。

为了给您提供更多上下文,VirtualCenter允许应用程序注册为扩展。所述申请可以在注册时注册其证书(setCertificate)。之后,应用程序可以使用其证书(loginExtensionByCertificate()方法)登录VirtualCenter,从而无需存储用户名和密码。但是,要使其正常工作,客户端(我的应用程序)必须将证书作为其SSL连接的一部分发送,即使服务器(VirtualCenter)没有特别要求它。

我正在用Java编写我的应用程序。创建了我自己的密钥管理器,将其连接到我的密钥库并指定要使用的别名。然后初始化我的ssl上下文以使用该密钥管理器。在创建的套接字中,我确实看到他们的SSLContext中有我的密钥管理器。但是,我没有看到密钥管理器被调用来获取证书。出于某种原因,套接字认为不需要发送证书。

我了解服务器可能会要求客户提供其证书。在这种情况下,它不会发生。我想知道是否有办法强制创建的套接字提供证书,无论服务器是否要求它。

5 个答案:

答案 0 :(得分:4)

客户端证书只能在服务器请求时发送。见TLS Spec. - Client Certificate message (RFC 4346, Section 7.4.6)

  

这是客户端收到邮件后可以发送的第一条消息   服务器你好完成消息。此消息仅在发送时发送   服务器请求证书。

您无法强制客户端发送客户端证书,而服务器尚未请求客户端证书。

编辑:当然,您还需要确保正确设置了keymanager / keystore。您可能遇到类似于why doesn't java send the client certificate during SSL handshake?

中描述的问题

答案 1 :(得分:2)

  

但是,为此,客户端(我的应用程序)必须发送证书   作为其SSL连接的一部分,即使服务器(VirtualCenter)   并不特别要求

要使其正常工作,服务器必须要求它。这就是SSL协议的定义方式。如果你可以安排你的客户端发送不请自来的,你不能,服务器必然会断开连接。

解决方法是在服务器端。你是100%肯定它不问吗?也许是在问,但你的客户没有发送?例如,因为证书未由服务器信任的CA签名。

答案 2 :(得分:0)

VMware VC将始终要求客户端的SSL证书,因为这是多少经过身份验证的扩展登录VC。所以,你走在正确的轨道上。

我怀疑你刚刚遇到SSL / Java交互问题,而不是特别是VMware问题(尽管SSL总是很难说明......)。

我想你想按照这里的建议:Java client certificates over HTTPS/SSL

答案 3 :(得分:0)

最后,解决了这个问题。 VMware似乎采取了一条完全不同的道路。这个问题被误解了。

首先,我使用WireShark跟踪连接,并且服务器在任何时候都不会询问(需要或想要)证书。但是,VirtualCenter(VC)确实提供了一种将证书注册为连接的一种方法,然后使用该证书进行身份验证。为此,它们提供了隧道连接的方法。

我使用的序列是:

  • 首先指定要连接的URL为https:// :(注意协议是安全的,但端口不是)。

  • 初始套接字将打开到明文端口。但是使用https作为协议会强制调用我自己的SSLSocketFactory。在我的套接字工厂中,我接到了public Socket createSocket(Socket s, String host, int port, boolean autoClose)方法的调用,这允许我根据自己的喜好将我的套接字转换为SSLSocket。

我的代码基本上是这样的:

@Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose)
    throws IOException {
    s.setKeepAlive(true);
    String connectReq = "CONNECT /sdkTunnel HTTP/1.1\r\n\r\n";
    OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
    writer.write(connectReq, 0, connectReq.length());
    writer.flush();
    // In this initial response, all that matters is the http code. If
    // it is 200, the rest can be ignored.
    READ_AND_VERIFY_INITIAL_RESPONSE();
    SSLSocket sock = (SSLSocket) origSslSockFactory
        .createSocket(s, s.getInetAddress().getHostName(), s.getPort(), true);
    // Depending on whether the caller actually does the handshake
    // or not, you may need to call handshake here. In my case, I
    // did not need to, since HTTPClient I am using calls the
    // handshake. Axis does not call, so you may have to in that
    // case.

    // sock.startHandshake();
    return sock;
}

在上面的块中,origSslSockFactory是由您的实现替换的SSLSocketFactory。在我的例子中,它是sun.security.ssl.SSLSocketFactoryImpl。

的一个实例

在该过程之后,调用ExtensionManager.setExtensionCertificate()成功。随后,对SessionManager.loginExtensionByCertificate()的所有调用也会成功。

我想发布这个,因为似乎有很多关于此的问题。

答案 4 :(得分:0)

安装vCenter时,它在端口443上使用反向代理,通过HTTP将请求转发给实际服务。代理从不要求客户端证书也不能转发它。

尝试找到运行该服务的实际端口并连接到该端口。