如何使用apache.commons.net.ftps配置客户端身份validation?

我使用apache.commons.net -framework在java中实现了FTPS客户端(FTP over SSL / TLS)。 它被配置为在默认端口21上执行显式安全性。

ftpsClient = new FTPSClient(false); ftpsClient.setTrustManager(getConfiguration().getCertificatesManager()); ftpsClient.connect(getConfiguration().getHostName(), getConfiguration().getPort()); 

只要我不在服务器上强制执行客户端身份validation,一切正常。 但我需要启用客户端身份validation,因此我在服务器上强制执行它并配置客户端系统属性:

 -Djavax.net.ssl.keyStore="D:/.../ftps-client-auth.keystore" -Djavax.net.ssl.keyStorePassword="*****" -Djavax.net.ssl.keyStoreType=JKS 

我得到的就像没有设置系统属性一样:

 javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1806) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:986) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181) at org.apache.commons.net.ftp.FTPSClient.sslNegotiation(FTPSClient.java:265) at org.apache.commons.net.ftp.FTPSClient._connectAction_(FTPSClient.java:207) at org.apache.commons.net.SocketClient.connect(SocketClient.java:172) at org.apache.commons.net.SocketClient.connect(SocketClient.java:192) 

服务器日志说:

 DEBUG: Client "", "SSL_accept failed: error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate" 

似乎没错 – 我启用了-Djavax.net.debug = all ,这表明服务器发送了它接受的CN列表,但是客户端发送了一个空的证书链。

  • 我做错了什么?
  • 我是否需要以编程方式进行一些配置?
  • 证书或私钥是否需要支持SSL / TLS的特殊function?

弄清楚:你需要以编程方式设置KeyManager 。 设置系统属性( -Djavax.net.ssl.keyStore ,…)是不够的,因为框架不使用Suns SSLSocketFactory

例:

 ftpsClient = new FTPSClient(false); ftpsClient.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager()); KeyManager keyManager = org.apache.commons.net.util.KeyManagerUtils.createClientKeyManager(new File(keystorePath), keystorePass); ftpsClient.setKeyManager(keyManager); ftpsClient.connect(getConfiguration().getHostName(), getConfiguration().getPort()); 

您可能希望选择不同的Trust-Manager,例如基于Java密钥库的Trust-Manager。 utils也提供了一种方法: TrustManagerUtils.getDefaultTrustManager(keystore)