我正在尝试编写一个客户端(实际上是一个中间件,它是一个实体的客户端,但也充当其他人的服务器)。在其客户端容量中,它应该与另一台服务器(VMware的VirtualCenter)通信,并要求它代表它执行操作。
为了给您提供更多上下文,VirtualCenter允许应用程序注册为扩展。所述申请可以在注册时注册其证书(setCertificate)。之后,应用程序可以使用其证书(loginExtensionByCertificate()方法)登录VirtualCenter,从而无需存储用户名和密码。但是,要使其正常工作,客户端(我的应用程序)必须将证书作为其SSL连接的一部分发送,即使服务器(VirtualCenter)没有特别要求它。
我正在用Java编写我的应用程序。创建了我自己的密钥管理器,将其连接到我的密钥库并指定要使用的别名。然后初始化我的ssl上下文以使用该密钥管理器。在创建的套接字中,我确实看到他们的SSLContext中有我的密钥管理器。但是,我没有看到密钥管理器被调用来获取证书。出于某种原因,套接字认为不需要发送证书。
我了解服务器可能会要求客户提供其证书。在这种情况下,它不会发生。我想知道是否有办法强制创建的套接字提供证书,无论服务器是否要求它。
答案 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将请求转发给实际服务。代理从不要求客户端证书也不能转发它。
尝试找到运行该服务的实际端口并连接到该端口。