From bf1213fc502275a9fac779a06c3a459256726d48 Mon Sep 17 00:00:00 2001 From: Eugene Petrenko Date: Sat, 13 Feb 2016 00:19:54 +0100 Subject: [PATCH 1/3] extract #doInitSignature protected helper --- .../apache/sshd/common/signature/AbstractSignature.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java index e67748baa..785fde1ee 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/AbstractSignature.java @@ -19,6 +19,7 @@ package org.apache.sshd.common.signature; import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SignatureException; @@ -48,16 +49,19 @@ public final String getAlgorithm() { return algorithm; } + protected java.security.Signature doInitSignature() throws GeneralSecurityException { + return SecurityUtils.getSignature(getAlgorithm()); + } @Override public void initVerifier(PublicKey key) throws Exception { - signature = SecurityUtils.getSignature(getAlgorithm()); + signature = doInitSignature(); signature.initVerify(ValidateUtils.checkNotNull(key, "No public key provided")); } @Override public void initSigner(PrivateKey key) throws Exception { - signature = SecurityUtils.getSignature(getAlgorithm()); + signature = doInitSignature(); signature.initSign(ValidateUtils.checkNotNull(key, "No private key provided")); } From 706dbc561a165694edad9082927738364a74d9c4 Mon Sep 17 00:00:00 2001 From: Eugene Petrenko Date: Sat, 13 Feb 2016 00:26:51 +0100 Subject: [PATCH 2/3] SSHD-642. Addede tests to reproduce the issue --- .../common/signature/SignatureRSATest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java diff --git a/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java new file mode 100644 index 000000000..9e61b3549 --- /dev/null +++ b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureRSATest.java @@ -0,0 +1,54 @@ +package org.apache.sshd.common.signature; + +import org.apache.mina.util.Base64; +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigInteger; +import java.security.*; +import java.security.Signature; +import java.security.spec.RSAPublicKeySpec; + +/** + * Created by eugene.petrenko@gmail.com + */ +public class SignatureRSATest { + @Test + public void testLeadingZeroes_BC() throws Throwable { + byte[] msg = Base64.decodeBase64("AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/q1TGV1wHNtCg9fGFGVSKs0VxKF4cfVyrSLtgLjnlXQTn+Lm7xiYKGbBbsTQWOqEDaBVBsRbAkxIkpuvr6/EBxwrtDbKmSQYTJZVJSD2bZRYjGsR9gpZXPorOOKFd5EPCMHXsqnhp2hidTGH7cK6RuLk7MNnPISsY0Nbx8/ZvikiPROGcoTZ8bzUv4IaLr3veW6epSeQem8tJqhnrpTHhbLU99zf045M0Gsnk/azjjlBM+qrHZ5FNdC1kowJnLtf2Oy/rUQNpkGJtcBPT8xvreV0wLsn9t3hSxzsc0+VkDNTQRlfU+o3M=".getBytes("utf-8")); + byte[] sig = Base64.decodeBase64("AAAAB3NzaC1yc2EAAAD/+Ntnf4qfr2J1voDS6I+u3VRjtMn+LdWJsAZfkLDxRkK1rQxP7QAjLdNqpT4CkWHp8dtoTGFlBFt6NieNJCMTA2KSOxJMZKsX7e/lHkh7C+vhQvJ9eLTKWjCxSFUrcM0NvFhmwbRCffwXSHvAKak4wbmofxQMpd+G4jZkNMz5kGpmeICBcNjRLPb7oXzuGr/g4x/3ge5Qaawqrg/gcZr/sKN6SdE8SszgKYO0SB320N4gcUoShVdLYr9uwdJ+kJoobfkUK6Or171JCctP/cu2nM79lDqVnJw/2jOG8OnTc8zRDXAh0RKoR5rOU8cOHm0Ls2MATsFdnyRU5FGUxqZ+".getBytes("utf-8")); + + byte[] exp = Base64.decodeBase64("Iw==".getBytes("utf-8")); + byte[] mod = Base64.decodeBase64("AMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/q1TGV1wHNtCg9fGFGVSKs0VxKF4cfVyrSLtgLjnlXQTn+Lm7xiYKGbBbsTQWOqEDaBVBsRbAkxIkpuvr6/EBxwrtDbKmSQYTJZVJSD2bZRYjGsR9gpZXPorOOKFd5EPCMHXsqnhp2hidTGH7cK6RuLk7MNnPISsY0Nbx8/ZvikiPROGcoTZ8bzUv4IaLr3veW6epSeQem8tJqhnrpTHhbLU99zf045M0Gsnk/azjjlBM+qrHZ5FNdC1kowJnLtf2Oy/rUQNpkGJtcBPT8xvreV0wLsn9t3hSxzsc0+VkDNTQRlfU+o3M=".getBytes("utf-8")); + + final PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger(mod), new BigInteger(exp))); + + final SignatureRSA rsa = new SignatureRSA(); + rsa.initVerifier(publicKey); + rsa.update(msg); + + Assert.assertTrue(rsa.verify(sig)); + } + + @Test + public void testLeadingZeroes_JCE() throws Throwable { + byte[] msg = Base64.decodeBase64("AAAAFPHgK1MeV9zNnok3pwNJhCd8SONqMgAAAAlidWlsZHVzZXIAAAAOc3NoLWNvbm5lY3Rpb24AAAAJcHVibGlja2V5AQAAAAdzc2gtcnNhAAABFQAAAAdzc2gtcnNhAAAAASMAAAEBAMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/q1TGV1wHNtCg9fGFGVSKs0VxKF4cfVyrSLtgLjnlXQTn+Lm7xiYKGbBbsTQWOqEDaBVBsRbAkxIkpuvr6/EBxwrtDbKmSQYTJZVJSD2bZRYjGsR9gpZXPorOOKFd5EPCMHXsqnhp2hidTGH7cK6RuLk7MNnPISsY0Nbx8/ZvikiPROGcoTZ8bzUv4IaLr3veW6epSeQem8tJqhnrpTHhbLU99zf045M0Gsnk/azjjlBM+qrHZ5FNdC1kowJnLtf2Oy/rUQNpkGJtcBPT8xvreV0wLsn9t3hSxzsc0+VkDNTQRlfU+o3M=".getBytes("utf-8")); + byte[] sig = Base64.decodeBase64("AAAAB3NzaC1yc2EAAAD/+Ntnf4qfr2J1voDS6I+u3VRjtMn+LdWJsAZfkLDxRkK1rQxP7QAjLdNqpT4CkWHp8dtoTGFlBFt6NieNJCMTA2KSOxJMZKsX7e/lHkh7C+vhQvJ9eLTKWjCxSFUrcM0NvFhmwbRCffwXSHvAKak4wbmofxQMpd+G4jZkNMz5kGpmeICBcNjRLPb7oXzuGr/g4x/3ge5Qaawqrg/gcZr/sKN6SdE8SszgKYO0SB320N4gcUoShVdLYr9uwdJ+kJoobfkUK6Or171JCctP/cu2nM79lDqVnJw/2jOG8OnTc8zRDXAh0RKoR5rOU8cOHm0Ls2MATsFdnyRU5FGUxqZ+".getBytes("utf-8")); + + byte[] exp = Base64.decodeBase64("Iw==".getBytes("utf-8")); + byte[] mod = Base64.decodeBase64("AMs9HO/NH/Now+6fSnESebaG4wzaYQWA1b/q1TGV1wHNtCg9fGFGVSKs0VxKF4cfVyrSLtgLjnlXQTn+Lm7xiYKGbBbsTQWOqEDaBVBsRbAkxIkpuvr6/EBxwrtDbKmSQYTJZVJSD2bZRYjGsR9gpZXPorOOKFd5EPCMHXsqnhp2hidTGH7cK6RuLk7MNnPISsY0Nbx8/ZvikiPROGcoTZ8bzUv4IaLr3veW6epSeQem8tJqhnrpTHhbLU99zf045M0Gsnk/azjjlBM+qrHZ5FNdC1kowJnLtf2Oy/rUQNpkGJtcBPT8xvreV0wLsn9t3hSxzsc0+VkDNTQRlfU+o3M=".getBytes("utf-8")); + + final PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(new BigInteger(mod), new BigInteger(exp))); + + final SignatureRSA rsa = new SignatureRSA() { + @Override + protected Signature doInitSignature() throws GeneralSecurityException { + return java.security.Signature.getInstance(getAlgorithm()); + } + }; + rsa.initVerifier(publicKey); + rsa.update(msg); + + Assert.assertTrue(rsa.verify(sig)); + } +} From 1ae4258a4779a30f1d51df9ab447ee60496bded4 Mon Sep 17 00:00:00 2001 From: Eugene Petrenko Date: Sat, 13 Feb 2016 00:52:12 +0100 Subject: [PATCH 3/3] include leading zeroes. SSHD-642 is fixed --- .../sshd/common/signature/SignatureRSA.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java index e5d2d4e44..66809ebf3 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/signature/SignatureRSA.java @@ -22,6 +22,9 @@ import org.apache.sshd.common.util.Pair; import org.apache.sshd.common.util.ValidateUtils; +import java.security.PublicKey; +import java.security.interfaces.RSAKey; + /** * RSA Signature * @@ -31,6 +34,8 @@ public class SignatureRSA extends AbstractSignature { public static final String DEFAULT_ALGORITHM = "SHA1withRSA"; + private int verifierSingatureSize = -1; + public SignatureRSA() { super(DEFAULT_ALGORITHM); } @@ -44,6 +49,12 @@ public byte[] sign() throws Exception { return signature.sign(); } + @Override + public void initVerifier(PublicKey key) throws Exception { + super.initVerifier(key); + verifierSingatureSize = (((RSAKey)key).getModulus().bitLength() + Byte.SIZE - 1) / Byte.SIZE; + } + @Override public boolean verify(byte[] sig) throws Exception { byte[] data = sig; @@ -54,6 +65,13 @@ public boolean verify(byte[] sig) throws Exception { data = encoding.getSecond(); } + ValidateUtils.checkTrue(verifierSingatureSize > 0, "Signature size should be initialized"); + if (data.length < verifierSingatureSize) { + byte[] pad = new byte[verifierSingatureSize]; + System.arraycopy(data, 0, pad, pad.length - data.length, data.length); + data = pad; + } + return doVerify(data); }