How to configure client authentication with apache.commons.net.ftps?

12,982

Figured it out: you need to programmatically set a KeyManager. Setting the system properties (-Djavax.net.ssl.keyStore, ...) is not sufficient, because the the framework does not use Suns SSLSocketFactory.

Example:

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());

You may want to choose a different Trust-Manager, e.g. one that is based on a Java-keystore. The utils provide a method for that, too: TrustManagerUtils.getDefaultTrustManager(keystore)

Share:
12,982
Andy
Author by

Andy

I'm an IT-Architect/Software Architect/Developer/Analyst/Tech Lead/Dev Coach/Reviewer living in Vienna, Austria.

Updated on June 04, 2022

Comments

  • Andy
    Andy almost 2 years

    I implemented a FTPS client (FTP over SSL/TLS) in java using the apache.commons.net-framework. It is configured to do explicit security on the default port 21.

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

    As long as I don't enforce client-authentication on the server, everything works fine. But I need to enable client-authentication, so I enforce it on the server and configured the client-system properties:

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

    What I got was the same as if I did not set the system properties:

    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)
    

    The server-log says:

    DEBUG: Client "<my ip address>", "SSL_accept failed: error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate"
    

    Seems right - I enabled -Djavax.net.debug=all, what shows that the server sends a list of CNs it accepts, but the client sends an empty certificate chain.

    • What have I done wrong?
    • Do I need to do some configuration programatically?
    • Do the certificates or the private key need to support anything special for SSL/TLS?
    • trynacode
      trynacode almost 7 years
      How did you set up your server? Having troubles setting up a server that enforces SSL and client authentication. Any help as to what you used to set it up?
    • Andy
      Andy almost 7 years
      @trynacode a colleague set up a vsftp server with client authentication. Unfortunately, I don't know the settings he used.
    • trynacode
      trynacode almost 7 years
      I'lll look into that then Andy. Thanks for the reply!
  • PankajAndroid
    PankajAndroid almost 8 years
    What this getConfiguration(). ??
  • Wilson Soethe Cursino
    Wilson Soethe Cursino over 6 years
    getConfiguration ?? where do you find it?
  • Andy
    Andy over 6 years
    I updated the example. Take a look at TrustManagerUtils to create an instance.