Our Products:   CompleteFTP  edtFTPnet/Free  edtFTPnet/PRO  edtFTPj/Free  edtFTPj/PRO
0 votes
852 views
in Java FTP by (290 points)
I've read through your doc about how to specify what algorithms (RSA or DSA) you can ask the server to use when host validation is turned on.  We would like to accept both (which I think is the default).  However, similar to FTPS where you can specify a minimum TLS version needed before allowing the connection, we would like to specify a minimum key size (in this case 2048) as part of validating the SFTP host that we are connecting to.  I did not see anything in the doc for how to do this (note that I'm using the multi-protocol client for these connections).

Is this even possible with the current release I have (5.3.0)?  if not, is this something you could add in a future release?

1 Answer

0 votes
by (161k points)
 
Best answer

There's a class called SSHFTPValidator that you can extend as described here. You override the validate method. In here you could check the keysize and return false if it isn't large enough. You are supplied with the SSHFTPPublicKey which has a method getBitLength().

by (290 points)
I was able to get this to work, but now I have a follow on question.  Lets say there is a host in the known_hosts file using RSA with a length of 1024, & I want to enforce a size of 2048.  If the server admin changes the RSA key to be of size 2048, what would be the value of hostKnown in the following method that I need to override:

protected boolean validate(String hostSpecifier, SSHFTPPublicKey publicKey, boolean hostKnown)

Would it be true because only the key size has changed, not the algorithm, or would it be false because they both have to match?
by (161k points)
If the RSA key is changed to 2048, it's a different hostkey and so it's not going to match the existing entry.  So the host will be unknown.
by (290 points)
Good, that's what I would expect...so heres my class to do that:

    class MyServerValidator extends SSHFTPValidator {
        protected boolean validate(String hostSpecifier, SSHFTPPublicKey publicKey, boolean hostKnown) {
            int keySize=publicKey.getBitLength();
            if (!hostKnown) {
                try {
                    addKnownHost(hostSpecifier, publicKey);
                    //check if the key size of this host matches our reqs
                    if (keySize>=MIN_SSH_KEY_SIZE) {
                        //key size meets the minimum reqs, so go ahead & add it permanently to the known hosts file
                        saveKnownHosts();
                    }
                }
                catch (Exception ex) {
                    log.error("Failed to add host '" + hostSpecifier + "' to known hosts", ex);
                           }
            return true;
            }
}


But when this code is executed for a host that does meet the minimum key length, I get a NPEx from executing saveKnownHosts().

Is what I have coded not the correct way of permanently saving a key that meets our minimum requrements?
From the abbreviated debug trace below, you can see that I successfully load a known hosts file, but then for some reason the path to that file is forgotten (or is set to null) when I go to save to it.


DEBUG [SSHFTPValidator] 16 Oct 2018 19:51:06.309 : Loading known hosts file /home/WebSphere/.ssh/known_hosts
DEBUG [SshPrivateKeyFile] 16 Oct 2018 19:51:06.410 : Parsing private key file
DEBUG [SshPrivateKeyFormatFactory] 16 Oct 2018 19:51:06.412 : Loading private key formats
DEBUG [SshPrivateKeyFormatFactory] 16 Oct 2018 19:51:06.413 : Installing OpenSSH-PrivateKey private key format
DEBUG [SshPrivateKeyFormatFactory] 16 Oct 2018 19:51:06.416 : Installing SSH.COM-PrivateKey-Base64Encoded private key format
DEBUG [SshPrivateKeyFormatFactory] 16 Oct 2018 19:51:06.417 : Installing PuTTY-User-Key-File-2 private key format
DEBUG [SshPrivateKeyFormatFactory] 16 Oct 2018 19:51:06.418 : Installing SSHTools-PrivateKey-Base64Encoded private key format
DEBUG [FTPTaskProcessor] 16 Oct 2018 19:51:06.427 : Using the master context
DEBUG [FTPTaskProcessor] 16 Oct 2018 19:51:06.427 : Using the master context
DEBUG [FTPTaskProcessor] 16 Oct 2018 19:51:06.429 : Using the master context
DEBUG [FTPTaskProcessor] 16 Oct 2018 19:51:06.429 : Added task 1 to the queue for processing
INFO [FTPTaskProcessor] 16 Oct 2018 19:51:06.430 : Processing task 1:Connect[transfer.cwp.pnp-hcl.com:22]
DEBUG [ConnectResult] 16 Oct 2018 19:51:06.430 : endAsync() called: com.enterprisedt.net.ftp.async.ConnectResult@302e24f2
DEBUG [AsyncResult] 16 Oct 2018 19:51:06.430 : waitTillComplete() called: com.enterprisedt.net.ftp.async.ConnectResult@302e24f2
DEBUG [AsyncResult] 16 Oct 2018 19:51:06.430 : Waiting until operation complete - com.enterprisedt.net.ftp.async.ConnectResult
INFO [LicensePropertiesBase] 16 Oct 2018 19:51:06.431 : Licence expiry date: 31 Dec 9999
INFO [LicensePropertiesBase] 16 Oct 2018 19:51:06.431 : Production licence
DEBUG [SCPClient] 16 Oct 2018 19:51:06.432 : Class: com.enterprisedt.net.ftp.ssh.SSHFTPClient
Location: file:/tmp/AE_Test/edtftpj-pro.jar
Version: 5.3.1
Build timestamp: 11-Oct-2018 13:46:36 BST
Java version: 1.8.0_181
CLASSPATH: AE_MPClient.jar:edtftpj-pro.jar
OS name: AIX
OS arch: ppc64
OS version: 7.1

DEBUG [SshClient] 16 Oct 2018 19:51:06.432 : Setting maxpacketsize=32648
DEBUG [SSHFTPClient] 16 Oct 2018 19:51:06.432 : Created SFTP client.
DEBUG [FTPConnectionPool] 16 Oct 2018 19:51:06.437 : Created connection #1 [free=0,busy=0,max=1,created=1,cleared=0]
DEBUG [SshClient] 16 Oct 2018 19:51:06.437 : Setting maxpacketsize=32648
DEBUG [SshPrivateKeyFile] 16 Oct 2018 19:51:06.439 : Parsing private key file
INFO [OpenSSHPrivateKeyFormat] 16 Oct 2018 19:51:06.443 : Unpacking OpenSSH formatted private key
INFO [OpenSSHPrivateKeyFormat] 16 Oct 2018 19:51:06.447 : RSA private key
INFO [SCPClient] 16 Oct 2018 19:51:06.452 : SCPClient settings validated.
DEBUG [SCPClient] 16 Oct 2018 19:51:06.452 : Connecting to transfer.cwp.pnp-hcl.com:22
DEBUG [SCPClient] 16 Oct 2018 19:51:06.452 : Version: 5.3.1
DEBUG [StreamSocketFactory] 16 Oct 2018 19:51:06.457 : Connecting to transfer.cwp.pnp-hcl.com:22 via standard socket
DEBUG [StreamSocketFactory] 16 Oct 2018 19:51:06.564 : setSoTimeout(60000)
INFO [TransportProtocolCommon] 16 Oct 2018 19:51:06.581 : Timeout=60000
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.581 : Starting transport protocol
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.589 : Wait for state update timeout=60000
DEBUG [State] 16 Oct 2018 19:51:06.589 : Updated state to 2
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.589 : Registering transport protocol messages with inputstream
INFO [cryptix] 16 Oct 2018 19:51:06.602 : GLOBAL_TRACE=false
INFO [cryptix] 16 Oct 2018 19:51:06.602 : GLOBAL_DEBUG=false
INFO [cryptix] 16 Oct 2018 19:51:06.602 : GLOBAL_DEBUG_SLOW=false
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.603 : Negotiating protocol version
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.603 : Local identification: SSH-2.0-edtFTPjPRO_5.3.1
'EBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.659 : Read: 'SSH-2.0-OpenSSH_7.4
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.660 : EOL is guessed at CR+LF
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.660 : Remote identification: 'SSH-2.0-OpenSSH_7.4'
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.660 : Protocol negotiation complete
Supported Public Keys ssh-dss,ssh-rsa
Supported Encryption Client->Server aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,blowfish-cbc,arcfour
Supported Encryption Server->Client aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc,aes128-ctr,aes192-ctr,aes256-ctr,blowfish-cbc,arcfour
Supported Mac Client->Server hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96,hmac-sha2-256,hmac-sha2-512
Supported Mac Server->Client hmac-sha1,hmac-sha1-96,hmac-md5,hmac-md5-96,hmac-sha2-256,hmac-sha2-512
DEBUG [DhFixedGroup] 16 Oct 2018 19:51:06.884 : calculateExchangeHash()
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.890 : Verifying host transfer.cwp.pnp-hcl.com,52.201.182.148
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.890 : Preferred algorithm null
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.890 : Determine Algorithm
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.890 : Client Algorithms: [ssh-dss, ssh-rsa]
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.890 : Server Algorithms: [ssh-rsa, rsa-sha2-512, rsa-sha2-256, ecdsa-sha2-nistp256, ssh-ed25519]
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.890 : Returning ssh-rsa
DEBUG [TransportProtocolCommon] 16 Oct 2018 19:51:06.891 : Selected algorithm ssh-rsa
DEBUG [SshRsaPublicKey] 16 Oct 2018 19:51:06.891 : Signature length=271
DEBUG [SshRsaPublicKey] 16 Oct 2018 19:51:06.893 : Verifying signature (com.enterprisedt.cryptix.provider.rsa.SHA1_RSA_PKCS1Signature)
DEBUG [SSHFTPValidator] 16 Oct 2018 19:51:06.895 : Adding known host 'transfer.cwp.pnp-hcl.com,52.201.182.148'
DEBUG [AbstractKnownHostsKeyVerification] 16 Oct 2018 19:51:06.896 : Allowing transfer.cwp.pnp-hcl.com,52.201.182.148 with fingerprint 2048: 59 d0 54 5c b7 69 19 c7 3b 18 f9 5e 5b de 22 5
DEBUG [SSHFTPValidator] 16 Oct 2018 19:51:06.896 : Saving to known hosts file null
ERROR [com.ibm.isa.net.ftp.AESecureFileTransferClient] 16 Oct 2018 19:51:06.897 : Failed to add host 'transfer.cwp.pnp-hcl.com,52.201.182.148' to known hosts : null
java.lang.NullPointerException
        at java.io.File.<init>(File.java:288)
        at com.enterprisedt.net.j2ssh.transport.AbstractKnownHostsKeyVerification.saveHostFile(AbstractKnownHostsKeyVerification.java:460)
        at com.enterprisedt.net.j2ssh.transport.AbstractKnownHostsKeyVerification.saveHostFile(AbstractKnownHostsKeyVerification.java:449)
        at com.enterprisedt.net.ftp.ssh.SSHFTPValidator.saveKnownHosts(SSHFTPValidator.java:223)
        at com.ibm.isa.net.ftp.AESecureFileTransferClient$MyServerValidator.validate(AESecureFileTransferClient.java:571)
        at com.enterprisedt.net.ftp.ssh.SSHFTPValidator$1.onUnknownHost(SSHFTPValidator.java:362)
        at com.enterprisedt.net.j2ssh.transport.AbstractKnownHostsKeyVerification.verifyHost(AbstractKnownHostsKeyVerification.java:411)
        at com.enterprisedt.net.ftp.ssh.SSHFTPValidator$1.verifyHost(SSHFTPValidator.java:346)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolClient.verifyHostKey(TransportProtocolClient.java:535)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolClient.performKeyExchange(TransportProtocolClient.java:426)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.beginKeyExchange(TransportProtocolCommon.java:731)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.a(TransportProtocolCommon.java:1373)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.startBinaryPacketProtocol(TransportProtocolCommon.java:1087)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.run(TransportProtocolCommon.java:428)
        at java.lang.Thread.run(Thread.java:812)


java.lang.NullPointerException
        at java.io.File.<init>(File.java:288)
        at com.enterprisedt.net.j2ssh.transport.AbstractKnownHostsKeyVerification.saveHostFile(AbstractKnownHostsKeyVerification.java:460)
        at com.enterprisedt.net.j2ssh.transport.AbstractKnownHostsKeyVerification.saveHostFile(AbstractKnownHostsKeyVerification.java:449)
        at com.enterprisedt.net.ftp.ssh.SSHFTPValidator.saveKnownHosts(SSHFTPValidator.java:223)
        at com.ibm.isa.net.ftp.AESecureFileTransferClient$MyServerValidator.validate(AESecureFileTransferClient.java:571)
        at com.enterprisedt.net.ftp.ssh.SSHFTPValidator$1.onUnknownHost(SSHFTPValidator.java:362)
        at com.enterprisedt.net.j2ssh.transport.AbstractKnownHostsKeyVerification.verifyHost(AbstractKnownHostsKeyVerification.java:411)
        at com.enterprisedt.net.ftp.ssh.SSHFTPValidator$1.verifyHost(SSHFTPValidator.java:346)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolClient.verifyHostKey(TransportProtocolClient.java:535)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolClient.performKeyExchange(TransportProtocolClient.java:426)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.beginKeyExchange(TransportProtocolCommon.java:731)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.a(TransportProtocolCommon.java:1373)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.startBinaryPacketProtocol(TransportProtocolCommon.java:1087)
        at com.enterprisedt.net.j2ssh.transport.TransportProtocolCommon.run(TransportProtocolCommon.java:428)
        at java.lang.Thread.run(Thread.java:812)
by (290 points)
Just want to follow up and see if there is anything wrong with the code I listed in the previous comment, or do I need to open a support ticket?
by (161k points)
Sorry, the public forums aren't the first priority for answering, so for the most rapid answers it is best to raise a support ticket.

I'm not sure where the error in your code is, but it clearly isn't getting supplied the name of the known hosts file - it's null, causing the exception in the stack trace.

Categories

...