diff --git a/ChangeLog.md b/ChangeLog.md index dee777b8..ddc53f68 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,9 @@ * [0.2.10](https://github.com/mwiede/jsch/releases/tag/jsch-0.2.10) * Fix new Java 21 compiler warning: `possible 'this' escape before subclass is fully initialized`. * Tweak OSGi bundle manifest to allow Log4j 3. + * [#362](https://github.com/mwiede/jsch/issues/362) fix PEM key parsing to work with windows line endings. + * [#361](https://github.com/mwiede/jsch/issues/361) guard against `UIKeyboardInteractive` implementations that include NULL elements in the `String[]` returned from `promptKeyboardInteractive()`. + * Add a default implmentation of the deprecated `decrypt()` method to the `Identity` interface that throws an `UnsupportedOperationException`. * [0.2.9](https://github.com/mwiede/jsch/releases/tag/jsch-0.2.9) * [#293](https://github.com/mwiede/jsch/issues/293) allow UserAuthNone to be extended. * Make JGSS module optional. diff --git a/pom.xml b/pom.xml index 3fdd037d..654bea71 100644 --- a/pom.xml +++ b/pom.xml @@ -156,15 +156,15 @@ test - com.kohlschutter.junixsocket - junixsocket-native-common - ${junixsocket.version} + commons-io + commons-io + 2.13.0 test - com.google.guava - guava - 32.1.1-jre + com.kohlschutter.junixsocket + junixsocket-native-common + ${junixsocket.version} test diff --git a/src/main/java/com/jcraft/jsch/AgentIdentity.java b/src/main/java/com/jcraft/jsch/AgentIdentity.java index 2fe5a2bc..3f83e4fb 100644 --- a/src/main/java/com/jcraft/jsch/AgentIdentity.java +++ b/src/main/java/com/jcraft/jsch/AgentIdentity.java @@ -60,12 +60,6 @@ public byte[] getSignature(byte[] data, String alg) { return agent.sign(blob, data, alg); } - @Override - @Deprecated - public boolean decrypt() { - throw new RuntimeException("not implemented"); - } - @Override public String getAlgName() { return algname; diff --git a/src/main/java/com/jcraft/jsch/Identity.java b/src/main/java/com/jcraft/jsch/Identity.java index 5aee38c8..f27c36bb 100644 --- a/src/main/java/com/jcraft/jsch/Identity.java +++ b/src/main/java/com/jcraft/jsch/Identity.java @@ -83,22 +83,30 @@ public default byte[] getSignature(byte[] data, String alg) { } /** + * This method is deprecated and the default implmentation of this method will throw an + * {@link UnsupportedOperationException}. + * * @deprecated The decryption should be done automatically in {@link #setPassphrase(byte[])} + * @return true if the decryption is succeeded or this identity is not cyphered. * @see #setPassphrase(byte[]) */ @Deprecated - public boolean decrypt(); + public default boolean decrypt() { + throw new UnsupportedOperationException("not implemented"); + } /** * Returns the name of the key algorithm. * - * @return "ssh-rsa" or "ssh-dss" + * @return the name of the key algorithm */ public String getAlgName(); /** * Returns the name of this identity. It will be useful to identify this object in the * {@link IdentityRepository}. + * + * @return the name of this identity */ public String getName(); diff --git a/src/main/java/com/jcraft/jsch/IdentityFile.java b/src/main/java/com/jcraft/jsch/IdentityFile.java index 89555674..af55a0b4 100644 --- a/src/main/java/com/jcraft/jsch/IdentityFile.java +++ b/src/main/java/com/jcraft/jsch/IdentityFile.java @@ -45,7 +45,7 @@ static IdentityFile newInstance(String name, byte[] prvkey, byte[] pubkey, return new IdentityFile(name, kpair); } - private IdentityFile(String name, KeyPair kpair) throws JSchException { + private IdentityFile(String name, KeyPair kpair) { this.identity = name; this.kpair = kpair; } @@ -94,30 +94,21 @@ public byte[] getSignature(byte[] data, String alg) { return kpair.getSignature(data, alg); } - /** - * @deprecated This method should not be invoked. - * @see #setPassphrase(byte[] passphrase) - */ - @Override - @Deprecated - public boolean decrypt() { - throw new RuntimeException("not implemented"); - } - /** * Returns the name of the key algorithm. * - * @return "ssh-rsa" or "ssh-dss" + * @return the name of the key algorithm */ @Override public String getAlgName() { - byte[] name = kpair.getKeyTypeName(); - return Util.byte2str(name); + return kpair.getKeyTypeString(); } /** * Returns the name of this identity. It will be useful to identify this object in the * {@link IdentityRepository}. + * + * @return the name of this identity */ @Override public String getName() { diff --git a/src/main/java/com/jcraft/jsch/KeyPair.java b/src/main/java/com/jcraft/jsch/KeyPair.java index 7e29f888..041a4862 100644 --- a/src/main/java/com/jcraft/jsch/KeyPair.java +++ b/src/main/java/com/jcraft/jsch/KeyPair.java @@ -891,6 +891,7 @@ static KeyPair load(JSch.InstanceLogger instLogger, byte[] prvkey, byte[] pubkey start = 0; i = 0; + int xds = 0; int _len = _buf.length; while (i < _len) { @@ -898,8 +899,10 @@ static KeyPair load(JSch.InstanceLogger instLogger, byte[] prvkey, byte[] pubkey boolean xd = (_buf[i - 1] == '\r'); // ignore \n (or \r\n) System.arraycopy(_buf, i + 1, _buf, i - (xd ? 1 : 0), _len - (i + 1)); - if (xd) + if (xd) { _len--; + xds++; + } _len--; continue; } @@ -909,8 +912,8 @@ static KeyPair load(JSch.InstanceLogger instLogger, byte[] prvkey, byte[] pubkey i++; } - if (i - start > 0) - data = Util.fromBase64(_buf, start, i - start); + if (i - xds - start > 0) + data = Util.fromBase64(_buf, start, i - xds - start); Util.bzero(_buf); } diff --git a/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java b/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java index c7aff920..cd5d5eda 100644 --- a/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java +++ b/src/main/java/com/jcraft/jsch/UserAuthKeyboardInteractive.java @@ -141,7 +141,7 @@ public boolean start(Session session) throws Exception { if (_response != null) { response = new byte[_response.length][]; for (int i = 0; i < _response.length; i++) { - response[i] = Util.str2byte(_response[i]); + response[i] = _response[i] != null ? Util.str2byte(_response[i]) : Util.empty; } } } diff --git a/src/main/java/com/jcraft/jsch/UserAuthPassword.java b/src/main/java/com/jcraft/jsch/UserAuthPassword.java index 6d75da94..111e0def 100644 --- a/src/main/java/com/jcraft/jsch/UserAuthPassword.java +++ b/src/main/java/com/jcraft/jsch/UserAuthPassword.java @@ -127,7 +127,7 @@ public boolean start(Session session) throws Exception { throw new JSchAuthCancelException("password"); } - byte[] newpassword = Util.str2byte(response[0]); + byte[] newpassword = response[0] != null ? Util.str2byte(response[0]) : Util.empty; // send // byte SSH_MSG_USERAUTH_REQUEST(50) diff --git a/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java b/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java index 0af63f77..508de07c 100644 --- a/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java +++ b/src/test/java/com/jcraft/jsch/AbstractBufferMargin.java @@ -6,7 +6,6 @@ import com.github.valfirst.slf4jtest.LoggingEvent; import com.github.valfirst.slf4jtest.TestLogger; import com.github.valfirst.slf4jtest.TestLoggerFactory; -import com.google.common.io.ByteStreams; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -17,6 +16,7 @@ import java.util.List; import java.util.Random; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.input.BoundedInputStream; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -209,7 +209,7 @@ private void doScp(Session session, boolean debugException) throws Exception { byte[] buf = new byte[17]; is.read(buf, 0, 17); sendAck(os); - Files.copy(ByteStreams.limit(is, 100L * 1024L), out); + Files.copy(new BoundedInputStream(is, 100L * 1024L), out); checkAck(is); sendAck(os); } diff --git a/src/test/java/com/jcraft/jsch/KeyPairTest.java b/src/test/java/com/jcraft/jsch/KeyPairTest.java index 9ab555a3..066382db 100644 --- a/src/test/java/com/jcraft/jsch/KeyPairTest.java +++ b/src/test/java/com/jcraft/jsch/KeyPairTest.java @@ -35,6 +35,8 @@ static Stream keyArgs() { Arguments.of("docker/ssh_host_dsa_key", null, "ssh-dss"), // encrypted dsa Arguments.of("encrypted_openssh_private_key_dsa", "secret123", "ssh-dss"), + // unencrypted RSA with windows (\r\n) line endings + Arguments.of("issue362_rsa", null, "ssh-rsa"), // ecdsa EC private key format Arguments.of("docker/id_ecdsa256", null, "ecdsa-sha2-nistp256"), // Arguments.of("docker/id_ecdsa384", null, "ecdsa-sha2-nistp384"), // diff --git a/src/test/resources/docker/authorized_keys.KeyPairIT b/src/test/resources/docker/authorized_keys.KeyPairIT index fc007f26..ac83da75 100644 --- a/src/test/resources/docker/authorized_keys.KeyPairIT +++ b/src/test/resources/docker/authorized_keys.KeyPairIT @@ -5,6 +5,7 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDNVEfQu64p2GczvWj0AlncuNG+PzPd0jZ1/hfx/JDz ssh-dss AAAAB3NzaC1kc3MAAACBAKCQzxCEIM7yb5fbSmuJCz/+v40WEbULx4JKCXBb7zmRtDtweBqUJXDM1bMjQ4VwGB1EkfMZJQR7rPrOAxfdMdCpkqgPR0+xlljZLVarSJHwt1KR9EudUjUdD2ZrPlvPlG1sAyvMVTK5KCx2QaS2Bn/gukxrvT7DkaqCFHg2P7rLAAAAFQCF+m0B12XxhF1P+3hF3ktGmfYpywAAAIBX+azef1TX90FwS7vyngCrdJsOYqWtj1zQ8MlrwrWL0jdbjcIG/0vcq1x84LTgs+hAPylDBCGGJa/td88kJ6jIUeWiebRUG0zEH8LM+nehQA5O6TuEV3U0Dg73I0Mb04ZzN2GqYqW+KwHdiaU5M8XQv3V/PCmY8d7R5WcMKKDCcQAAAIEAmy0FgQoaWyHdD84b7zD0YjziMsVELAbGWwdxNuNe6wtACcctCdIQigQYaC2HwGjlDKVMjQfd4RWArshg7p0PlEw7//HSgoVhwcBbDpmWGCS6TxSSQpDmdDgiVegERMYjo2BZoZQTuJIx/BhQggVISkELwZfsi1BnPC5Aecq7ILI= test ssh-dss AAAAB3NzaC1kc3MAAACBAMKmaZwslPWE83wv+Ofl9oaMeOR03Yk0cyDc5fSAgjepXZQR5sps0KFORRufI6dLQHY4XLoyPc/Hr0ra+vY/l+p20cJVjQ07oosPU/d2eLdZ66rdjXCyrJPjFjnNJtumnBnJZqWGObKspnWk73vPOflReyGpUFe51PF1usur3uDLAAAAFQC3dSlxZZVNbvqjJpg8/oSMuG27/QAAAIEApkd3miYVc/Cl1QwdqwInIjby1yGNCfFsZALGBYc67lkd5lGBdNlL+fgi+BwC6UXu5OAqWB/b9OtvJR8NRcM77V252IER4t95t2ZdG66M1T5q1aOVL/ehPZFHf0oPXHJLcsybzqKFAtQj5hEbnrwJYW0fWi87C9LApplzPTVYQikAAACAUEu5tFmImzyQsUBMN/j1GWCCSVznjfRHkeGwx5koC0D2iK3mMphnF9avsoX2PrboEbGqy69JPCekKQiPPWxcQRTRqFS/ySkECJ5lJ2zJrW1whjLQEJbOq7WmusSML9UXCpNSwCqhJxPYx5a8Pq7lrrBP21jT/Z/A4m4c4wMkLXo= test ssh-dss AAAAB3NzaC1kc3MAAACBAPmIBCP1AA8EiTL0VAdzau+1KuRmPkg+H2du4zt4ifhzEx4MscZ7cpBsUAM/EBC/ECWTHzDiWyFFuenvxDlfTi9XxySdOKM6XGLkY7oLsY1y5bShyLrycxDD7MRQ8HpUc9TPzE2PDH4Od6o98e+vdXP0+IDUZGbSuwEnaABX/1+ZAAAAFQDIB9KUd1/gnzM4s4FXCQb7zCnjVwAAAIBptrE9g/ooRnh4bOWiA3/StxbjMRmA9f9bJbM55CinL4yf/GdGmeBp6YjDBxDyk1oXmVJ2hLVXgW6kETbt+D01SouCTgLPlFwLFhqZQ+A4JQOKuLIBaM92hI7sAfTewkxbmAk/e1vyOeyfcQDhbncESzVBZrheXC1fTKv7O2PgbgAAAIBKhGEiNwKNA/pfYvkEbX90/jVoIEKZfqTk+PB2gbVMT98LWPaexrDwEGuCCK3KOtMncDai+0r1ujf1hzNJ4z43Z1n15tPvAIwQsObTL+eUQkVjHA8LXOq8n4yYyPidkjGzWcfBAm4Lm6vKkzFM3VRouQIHpWpjRl3wGTJZkOoH0Q== test +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDY+326Z0bUOn8kYUc399P2mr7Eh0E7Nc9zPrv80B05ykfmsCM053SiGYQgwP5aBzZk83PdWdYIK12U9eO5WzTwT2po9PrZT0AvsBGnU7MkzSSlXX79e9ELbGYNWV4DafT/VHxVwCuoctG7XKUorGA3ZHxGbhNWyo/+6LNwyCMcxfpjpCelJWn4MTwFqs0DVme4R2Sy+LaVg3Nv5Vbbi27cIbA+6Orit2ajDUUCHJvcQlpGrM6x9w0zbt4pUI6yHPCHIIqZEPzj1285GCF6ZQzi0TMEf4wHtA8fN1Xgn1vBw+IEkrAAnQUeTWOR1nc6CDFEGTlyYlIuz634I4BwfhBl test ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBcLHSACx0yr1S902vlRRnXA12YpaXIOkZUXoNFb01+CxQBgGpVTEVMuakLpIW/XcD9ltu+c6Czk5WnBKEoHNuI= test ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBPKyvhX/3Q32EEhZKF6s+fEzfQwabsSpXgFJ2LwpGxKFxzE2jw4Nvwe9W3YbPyrZU6K2MMA7p7ZdJwdDP/tQ9dhttOGGSkea9Cq4dcdgC9cdBuQ4aGb8crmY3Z5wc1dPxQ== test ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAG3XTlAFoQd4iIBt5KoTHJk46v1AdZSd+wfCSpc2/GCzHNGVqidrKCrypszpkQOW6vYG8riilyfF36rJa9ipjR+5gDApLIe/ix1Fknr8MU6nWoYv2+NBTsEcaS/VTeiUuMKftMtlO2wOaWFcbZBQUAlb3LDnpMyYKCqIXhhl4vqCxBukg== test diff --git a/src/test/resources/issue362_rsa b/src/test/resources/issue362_rsa new file mode 100644 index 00000000..0c0e41d8 --- /dev/null +++ b/src/test/resources/issue362_rsa @@ -0,0 +1,3 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA2Pt9umdG1Dp/JGFHN/fT9pq+xIdBOzXPcz67/NAdOcpH5rAjNOd0ohmEIMD+Wgc2ZPNz3VnWCCtdlPXjuVs08E9qaPT62U9AL7ARp1OzJM0kpV1+/XvRC2xmDVleA2n0/1R8VcArqHLRu1ylKKxgN2R8Rm4TVsqP/uizcMgjHMX6Y6QnpSVp+DE8BarNA1ZnuEdksvi2lYNzb+VW24tu3CGwPujq4rdmow1FAhyb3EJaRqzOsfcNM27eKVCOshzwhyCKmRD849dvORghemUM4tEzBH+MB7QPHzdV4J9bwcPiBJKwAJ0FHk1jkdZ3OggxRBk5cmJSLs+t+COAcH4QZQIDAQABAoIBAGcA5AuEEWyYJFkZ0Nwxyq6LgTn8VywLfGJiCo2WIfmYHA/X1666nXSCFmYSF+yW9exwYbVXezI/m9ol7CfGs1fM61/Nw/M7GuZId+jt4+H5fIb/3lPo3jDFEaEOpoGKYCKBcdCnPFJnx0ZhUYoAYmCJVDF++bE+0aKZxu0oJPr35Lda1hBeCfrb8fDReAAU71jIoOGyuSyOXlCVyT+OmBhVme0u2xDpdY8cd5t9YueTK7BFNjNt3sJOI4L+2wRskNwxqHCrECtuOXmzEyza7vqo8cjRGSx1HZfqhoKgiRpRkRmSi8p+X1+DZOVZuCxc3BTZ7WrPgVZhu7u9hsISKyECgYEA+C9ajUNsx7Hx9gOg6Zvr+zV461PjKI/0n9g0DTZ5RHdcAfeNs3ugmsiDK6b9SayUW08EVyveJ1OJjT/NPvdP0/KhCAjUt+kN0j9f9CPdHKEWoboDca8u67dayOAhC10mNhoAp3tFQryfgpb678GIzqnXkVjGgyWC/8Z81AN7uAkCgYEA39CcJAUVMc6FigTwoMOkdOgNK6qCxAxkNBTdfB/cBBtG3h8g49n0u/fAMjkfL6awdl53j3jVCP4pUZgSSqArLb0aGo84G2vP92iN3d3j/kPiox22w8KG2XR7tHLWcc+CFfk8mdiKdPFxaWVQaYJ6htGq9LGqY3sw5lVzmk0wlH0CgYEAuWim/WGhoo4NdPzA+cTCRqlr7GJ/EY558fBS8ov/jGafFdkawztYgEnLtJDMKH4FVzFwzK65CCggWqWPb7rSqERaiOYQBFTXPnqZ9InWZczyW1/bstJs+yu/ZtIJ3bN5GHHUi0pMM882Wxjv3q12xu2bXbo0k0Uy2GIwXzM6+gECgYBDByur0eXeC7aMdhxGWTEoXdKL8D3HTtq3ikQmhzgR9sVLglEMS9rybCkgIWFImQgh+vqdehd64Pso130q4jrsMMTfjWLFO42Fz8ck2e4M2PHH3f89M0XFXBAsI3Q7k2SnBgRzIpmcmi5X3SKu5oehVqt3KroXnu4vHQpI/LL+1QKBgD3zxf795zFXw53iZXtKkzYNQhEMVRzbx6dQE+tguB0YCb2vPvYaxfejg/02hCQ4twIMuMK18v0Y9W7E34C0m++lP8UbnHdR0Dsg9ryH7OlUMp4662060HWDnDy79swB/Nnk9dxf+BoPIXGny84bEpk6cLoiHuL6TRpQhuJ292DW +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/issue362_rsa.pub b/src/test/resources/issue362_rsa.pub new file mode 100644 index 00000000..d378cbe0 --- /dev/null +++ b/src/test/resources/issue362_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDY+326Z0bUOn8kYUc399P2mr7Eh0E7Nc9zPrv80B05ykfmsCM053SiGYQgwP5aBzZk83PdWdYIK12U9eO5WzTwT2po9PrZT0AvsBGnU7MkzSSlXX79e9ELbGYNWV4DafT/VHxVwCuoctG7XKUorGA3ZHxGbhNWyo/+6LNwyCMcxfpjpCelJWn4MTwFqs0DVme4R2Sy+LaVg3Nv5Vbbi27cIbA+6Orit2ajDUUCHJvcQlpGrM6x9w0zbt4pUI6yHPCHIIqZEPzj1285GCF6ZQzi0TMEf4wHtA8fN1Xgn1vBw+IEkrAAnQUeTWOR1nc6CDFEGTlyYlIuz634I4BwfhBl test