Signature length not correct: got 127 but was expe

2019-04-07 05:26发布

问题:

I am facing a strange problem after java 1.8 upgrade. I am using jsch-0.1.54.jar in one of our utility programs to download files from various places. This particular utility was being used for almost 4-5 years without any problem(back then it jsch-0.1.48). At that time environment was java 1.6. Recently we upgraded to java 1.8 and as a result we upgraded this particular utility. Now we are encountering a strange problem and it occurs occasionally, and most of the time the download of files are prefect.

Error log

INFO: SSH_MSG_KEXDH_INIT sent
INFO: expecting SSH_MSG_KEXDH_REPLY
INFO: Disconnecting from SRV2000 port 22
2016-10-28 08:42:18:0576 ERROR  [main] net.AerisAbstractMethod - Failed to open connection 
com.jcraft.jsch.JSchException: Session.connect: java.security.SignatureException: Signature length not correct: got 127 but was expecting 128
    at com.jcraft.jsch.Session.connect(Session.java:565)
    at com.jcraft.jsch.Session.connect(Session.java:183)
    at com.aeris.net.AerisSFTPMethod.connectToServer(AerisSFTPMethod.java:65)
    at com.aeris.net.AerisAbstractMethod.getListOfFiles(AerisAbstractMethod.java:143)
    at com.aeris.worker.AerisUploaderDownloader.performUploadDownloadListing(AerisUploaderDownloader.java:112)
    at com.aeris.main.AerisCommonSftpUtility.main(AerisCommonSftpUtility.java:102)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at com.simontuffs.onejar.Boot.run(Boot.java:340)
    at com.simontuffs.onejar.Boot.main(Boot.java:166)

Success Log: (in most of the cases it is success)

INFO: SSH_MSG_KEXDH_INIT sent
INFO: expecting SSH_MSG_KEXDH_REPLY
INFO: ssh_rsa_verify: signature true
WARN: Permanently added 'SRV2000' (RSA) to the list of known hosts.
INFO: SSH_MSG_NEWKEYS sent
INFO: SSH_MSG_NEWKEYS received
INFO: SSH_MSG_SERVICE_REQUEST sent
INFO: SSH_MSG_SERVICE_ACCEPT received
INFO: Authentications that can continue: publickey,password,keyboard-interactive
INFO: Next authentication method: publickey
INFO: Authentication succeeded (publickey).
2016-10-28 08:36:48:0794 INFO   [main] net.AerisAbstractMethod - Session connected to server
2016-10-28 08:36:48:0794 INFO   [main] net.AerisAbstractMethod - Opening SFTP channel..
2016-10-28 08:36:48:0810 INFO   [main] net.AerisAbstractMethod - Connecting to server through channel.
2016-10-28 08:36:48:0857 INFO   [main] net.AerisAbstractMethod - Connection successful.
2016-10-28 08:36:48:0857 INFO   [main] net.AerisAbstractMethod - Changing to directory:C:/interfaces/ib/wf/work
2016-10-28 08:36:48:0888 INFO   [main] net.AerisAbstractMethod - Start file Listing of the remote directory:C:/interfaces/ib/wf/work

       0 Oct 28, 2016 04:15 ./
       0 Oct 28, 2016 04:15 ../

I did a complete analysis with Vandyke (sftp software provider) but did not find any error at that end. I also tried to sftp using different tools but I am not getting any error. Following is the code snippet to connect of SFTP server. Can any one help in this matter?

protected void connectToServer() throws AerisConnectionException {
        JSch jSch =(JSch)this.client;
        try {

            session = jSch.getSession(config.getUsername(), config.getRemoteserver(), config.getPort());
            LOGGER.info("Creating SSH Session using Username:"+config.getUsername()+ " Server :" +config.getRemoteserver()+ " at PORT:"+config.getPort());
            if(config.getAuth().equalsIgnoreCase("PASSWD")||config.getAuth().equalsIgnoreCase("KEYPASS")){
                LOGGER.info("Setting password ...");
                session.setPassword(config.getPassword());
            }

            Properties jShconfig = new Properties();            
            jShconfig.put("StrictHostKeyChecking", "no");
            jShconfig.put("PreferredAuthentications", 
                      "publickey,password,keyboard-interactive");
            jShconfig.put("LogLevel", "VERBOSE");


            LOGGER.info("Setting timeout to "+config.getTimeOut());
            session.setTimeout(config.getTimeOut()*1000);
            session.setConfig(jShconfig);           

            session.connect();
            LOGGER.info("Session connected to server");
            this.connected=true;

        } catch (JSchException e) {
            LOGGER.error("Failed to open connection ",e);
            throw new AerisConnectionException("Failed to open connection.");
        }

    }

回答1:

Although it would be nice to have the stacktrace to confirm, I'll bet the server is using an RSA 'host' key to authenticate and is wrongly 'trimming' leading zero in rare cases.

RSA signature values (and encrypted values also) defined by PKCS#1, which SSH uses (as do many other things including SSL), are required to be encoded as an octet string of fixed length 'k' equal to the length required to encode the modulus, or informally 'the same size as the modulus'. However, since the underlying mathematical value is a large nonnegative (aka unsigned) integer, specifically modexp(s,d,n), historically some implementations have omitted leading zero octets -- an omission which is valid when treating the value as an integer -- resulting in an encoded value that is sometimes shorter than it should be.

The RSA signature (or encrypted) value is effectively a uniform random number in (1,n). Thus when the RSA key used by the server has a 'round binary' size like 1024 as here, this trimming will happen approximately 1 in 200 times at random, or 400 if trimmed as a signed number.

I did not know, but on testing I confirm that (Oracle) Java 6 does accept such a 'short' value for Signature type RSA or as actually used here SHA1withRSA, both of which imply the PKCS1-v1_5 scheme, but Java 7 and 8 throw the exception you saw. OTOH both OpenSSH and PuTTY (also used by WinSCP and FileZilla) do accept 'short' values, while always sending correct length values; this Postelian behavior may make it more difficult to detect when a peer is misbehaving this way. (Note: I checked OpenSSH 5.5 and 7.3, the oldest and newest I have conveniently at hand, but only the current PuTTY 0.67 because that's all I keep online.)

You can try pointing the server software implementor to the published standards, but it may not do any good. You could ask jcraft to special-case this; they already have logic in the DSA and ECDSA cases for mpint/ASN.1 that I might argue is equally ugly. Or if the server has another (usable) key, request that by configuring "server_host_key" to NOT include ssh-rsa -- easiest just get the existing/default list, split, remove "ssh-rsa" (and check not empty) and rejoin, instead of possibly confusing your users and/or (co)maintainers by listing today's specific algorithms.