http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java new file mode 100644 index 0000000..48f7ec4 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsCloneTest.java @@ -0,0 +1,120 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.config.keys; + +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.sshd.common.cipher.ECCurves; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@Category({ NoIoTestCase.class }) +public class KeyUtilsCloneTest extends JUnitTestSupport { + private final String keyType; + private final int keySize; + + public KeyUtilsCloneTest(String keyType, int keySize) { + this.keyType = ValidateUtils.checkNotNullAndNotEmpty(keyType, "No key type specified"); + this.keySize = keySize; + } + + @Parameters(name = "type={0}, size={1}") + public static List<Object[]> parameters() { + List<Object[]> list = new ArrayList<>(); + addTests(list, KeyPairProvider.SSH_DSS, DSS_SIZES); + addTests(list, KeyPairProvider.SSH_RSA, RSA_SIZES); + if (SecurityUtils.isECCSupported()) { + for (ECCurves curve : ECCurves.VALUES) { + if (!curve.isSupported()) { + continue; + } + addTests(list, curve.getKeyType(), Collections.singletonList(curve.getKeySize())); + } + } + if (SecurityUtils.isEDDSACurveSupported()) { + addTests(list, KeyPairProvider.SSH_ED25519, ED25519_SIZES); + } + return Collections.unmodifiableList(list); + } + + private static void addTests(List<Object[]> list, String keyType, Collection<Integer> sizes) { + for (Integer keySize : sizes) { + list.add(new Object[]{keyType, keySize}); + } + } + + @Test + @SuppressWarnings("checkstyle:avoidnestedblocks") + public void testKeyPairCloning() throws GeneralSecurityException { + outputDebugMessage("generateKeyPair(%s)[%d]", keyType, keySize); + KeyPair original = KeyUtils.generateKeyPair(keyType, keySize); + + outputDebugMessage("cloneKeyPair(%s)[%d]", keyType, keySize); + KeyPair cloned = KeyUtils.cloneKeyPair(keyType, original); + + String prefix = keyType + "[" + keySize + "]"; + assertNotSame(prefix + ": Key pair not cloned", original, cloned); + assertTrue(prefix + ": Cloned pair not equals", KeyUtils.compareKeyPairs(original, cloned)); + + { + PublicKey k1 = original.getPublic(); + PublicKey k2 = cloned.getPublic(); + assertNotSame(prefix + ": Public key not cloned", k1, k2); + assertTrue(prefix + ": Cloned public key not equals", KeyUtils.compareKeys(k1, k2)); + + String f1 = KeyUtils.getFingerPrint(k1); + String f2 = KeyUtils.getFingerPrint(k2); + assertEquals(prefix + ": Mismatched fingerprints", f1, f2); + } + + { + PrivateKey k1 = original.getPrivate(); + PrivateKey k2 = cloned.getPrivate(); + assertNotSame(prefix + ": Private key not cloned", k1, k2); + assertTrue(prefix + ": Cloned private key not equals", KeyUtils.compareKeys(k1, k2)); + } + } + +}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java new file mode 100644 index 0000000..ae0b86d --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintCaseSensitivityTest.java @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.config.keys; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Arrays; +import java.util.Collection; + +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@Category({ NoIoTestCase.class }) +public class KeyUtilsFingerprintCaseSensitivityTest extends JUnitTestSupport { + + // CHECKSTYLE:OFF + private static final String KEY_STRING = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxr3N5fkt966xJINl0hH7Q6lLDRR1D0yMjcXCE5roE9VFut2ctGFuo90TCOxkPOMnwzwConeyScVF4ConZeWsxbG9VtRh61IeZ6R5P5ZTvE9xPdZBgIEWvU1bRfrrOfSMihqF98pODspE6NoTtND2eglwSGwxcYFmpdTAmu+8qgxgGxlEaaCjqwdiNPZhygrH81Mv2ruolNeZkn4Bj+wFFmZTD/waN1pQaMf+SO1+kEYIYFNl5+8JRGuUcr8MhHHJB+gwqMTF2BSBVITJzZUiQR0TMtkK6Vbs7yt1F9hhzDzAFDwhV+rsfNQaOHpl3zP07qH+/99A0XG1CVcEdHqVMw== lgoldstein@LGOLDSTEIN-WIN7"; + // CHECKSTYLE:ON + private static final String MD5_PREFIX = "MD5:"; + private static final String MD5 = "24:32:3c:80:01:b3:e1:fa:7c:53:ca:e3:e8:4e:c6:8e"; + private static final String MD5_FULL = MD5_PREFIX + MD5; + private static final String SHA1_PREFIX = "SHA1:"; + private static final String SHA1 = "ZNLzC6u+F37oq8BpEAwP69EQtoA"; + private static final String SHA1_FULL = SHA1_PREFIX + SHA1; + + private static PublicKey key; + + private String expected; + private String test; + + public KeyUtilsFingerprintCaseSensitivityTest(String expected, String test) { + this.expected = expected; + this.test = test; + } + + @BeforeClass + public static void beforeClass() throws GeneralSecurityException, IOException { + key = PublicKeyEntry.parsePublicKeyEntry(KEY_STRING).resolvePublicKey(PublicKeyEntryResolver.FAILING); + } + + @Parameters(name = "expected={0}, test={1}") + public static Collection<Object[]> parameters() { + return Arrays.asList( + new Object[] {MD5_FULL, MD5_FULL}, + new Object[] {MD5_FULL, MD5_FULL.toUpperCase()}, + new Object[] {MD5_FULL, MD5_FULL.toLowerCase()}, + new Object[] {MD5_FULL, MD5_PREFIX.toUpperCase() + MD5}, + new Object[] {MD5_FULL, MD5_PREFIX.toLowerCase() + MD5}, + new Object[] {MD5_FULL, MD5.toLowerCase()}, + new Object[] {MD5_FULL, MD5.toUpperCase()}, + new Object[] {SHA1_FULL, SHA1_FULL}, + new Object[] {SHA1_FULL, SHA1_PREFIX.toUpperCase() + SHA1}, + new Object[] {SHA1_FULL, SHA1_PREFIX.toLowerCase() + SHA1} + ); + } + + @Test + public void testCase() throws Exception { + assertEquals("Check failed", new SimpleImmutableEntry<>(true, expected), KeyUtils.checkFingerPrint(test, key)); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java new file mode 100644 index 0000000..9a8fb7a --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsFingerprintGenerationTest.java @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.config.keys; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.apache.sshd.common.digest.BuiltinDigests; +import org.apache.sshd.common.digest.DigestFactory; +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@Category({ NoIoTestCase.class }) +public class KeyUtilsFingerprintGenerationTest extends JUnitTestSupport { + private final PublicKey key; + private final DigestFactory digestFactory; + private final String expected; + + public KeyUtilsFingerprintGenerationTest(PublicKey key, DigestFactory digestFactory, String expected) { + this.key = key; + this.digestFactory = digestFactory; + this.expected = expected; + } + + @Parameters(name = "key={0}, digestFactory={1}, expected={2}") + public static Collection<Object[]> parameters() throws IOException, GeneralSecurityException { + List<? extends Map.Entry<String, List<? extends Map.Entry<DigestFactory, String>>>> keyEntries = + Collections.unmodifiableList(Arrays.asList( + new SimpleImmutableEntry<>( + // CHECKSTYLE:OFF + "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxr3N5fkt966xJINl0hH7Q6lLDRR1D0yMjcXCE5roE9VFut2ctGFuo90TCOxkPOMnwzwConeyScVF4ConZeWsxbG9VtRh61IeZ6R5P5ZTvE9xPdZBgIEWvU1bRfrrOfSMihqF98pODspE6NoTtND2eglwSGwxcYFmpdTAmu+8qgxgGxlEaaCjqwdiNPZhygrH81Mv2ruolNeZkn4Bj+wFFmZTD/waN1pQaMf+SO1+kEYIYFNl5+8JRGuUcr8MhHHJB+gwqMTF2BSBVITJzZUiQR0TMtkK6Vbs7yt1F9hhzDzAFDwhV+rsfNQaOHpl3zP07qH+/99A0XG1CVcEdHqVMw== lgoldstein@LGOLDSTEIN-WIN7", + // CHECKSTYLE:ON + Arrays.asList( + new SimpleImmutableEntry<>( + BuiltinDigests.md5, + "MD5:24:32:3c:80:01:b3:e1:fa:7c:53:ca:e3:e8:4e:c6:8e" + ), + new SimpleImmutableEntry<>( + BuiltinDigests.sha256, + "SHA256:1wNOZO+/XgNGJMx8UUJst33V+bBMTz5EcL0B6y2iRv0" + ) + ) + ), + new SimpleImmutableEntry<>( + // CHECKSTYLE:OFF + "ssh-dss AAAAB3NzaC1kc3MAAACBAMg/IxsG5BxnF5gM7IKqqR0rftxZC+n5GlbO+J4H+iIb/KR8NBehkxG3CrBZMF96M2K1sEGYLob+3k4r71oWaPul8n5rt9kpd+JSq4iD2ygOyg6Kd1/YDBHoxneizy6I/bGsLwhAAKWcRNrXmYVKGzhrhvZWN12AJDq2mGdj3szLAAAAFQD7a2MltdUSF7FU3//SpW4WGjZbeQAAAIBf0nNsfKQL/TEMo7IpTrEMg5V0RnSigCX0+yUERS42GW/ZeCZBJw7oL2XZbuBtu63vMjDgVpnb92BdrcPgjJ7EFW6DlcyeuywStmg1ygXmDR2AQCxv0eX2CQgrdUczmRa155SDVUTvTQlO1IyKx0vwKAh1H7E3yJUfkTAJstbGYQAAAIEAtv+cdRfNevYFkp55jVqazc8zRLvfb64jzgc5oSJVc64kFs4yx+abYpGX9WxNxDlG6g2WiY8voDBB0YnUJsn0kVRjBKX9OceROxrfT4K4dVbQZsdt+SLaXWL4lGJFrFZL3LZqvySvq6xfhJfakQDDivW4hUOhFPXPHrE5/Ia3T7A= dsa-key-20130709", + // CHECKSTYLE:ON + Arrays.asList( + new SimpleImmutableEntry<>( + BuiltinDigests.md5, + "MD5:fb:29:14:8d:94:f9:1d:cf:6b:0e:a4:35:1d:83:44:2f" + ), + new SimpleImmutableEntry<>( + BuiltinDigests.sha256, + "SHA256:grxw4KhY1cK6eOczBWs7tDVvo9V0PQw4E1wN1gJvHlw" + ) + ) + ), + new SimpleImmutableEntry<>( + // CHECKSTYLE:OFF + "ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFImZtcTj842stlcVHLFBFxTEx7lu3jW9aZCvd0r9fUNKZ6LbRPh6l1oJ4ozArnw7XreQBUc5oNd9HB5RNJ8jl1nWXY5cXBA7McZrKZrYmk+zxNhH6UL+kMLaJkyngJHQw== root@osv-linux", + // CHECKSTYLE:ON + Arrays.asList( + new SimpleImmutableEntry<>( + BuiltinDigests.md5, + "MD5:e6:dc:a2:4f:5b:11:b2:3c:0f:e8:f6:d8:d1:01:e9:d3" + ), + new SimpleImmutableEntry<>( + BuiltinDigests.sha512, + "SHA512:4w6ZB78tmFWhpN2J50Ok6WeMJhZp1X0xN0EKWxZmRLcYDbCWhyJDe8lgrQKWqdTCMZ5aNEBl9xQUklcC5Gt2jg" + ) + ) + ) + )); + + List<Object[]> ret = new ArrayList<>(); + for (Map.Entry<String, ? extends Collection<? extends Map.Entry<DigestFactory, String>>> kentry : keyEntries) { + String keyValue = kentry.getKey(); + try { + PublicKey key = PublicKeyEntry.parsePublicKeyEntry(keyValue).resolvePublicKey(PublicKeyEntryResolver.FAILING); + for (Map.Entry<DigestFactory, String> dentry : kentry.getValue()) { + DigestFactory factory = dentry.getKey(); + String fingerprint = dentry.getValue(); + if (!factory.isSupported()) { + System.out.println("Skip unsupported digest: " + fingerprint); + continue; + } + + ret.add(new Object[]{key, factory, fingerprint}); + } + } catch (InvalidKeySpecException e) { + System.out.println("Skip unsupported key: " + keyValue); + } + } + + return ret; + } + + @Test + public void testFingerprint() throws Exception { + String name = digestFactory.getName(); + assertEquals( + String.format("Fingerprint does not match for digest %s", name), + expected, + KeyUtils.getFingerPrint(digestFactory, key) + ); + assertEquals( + String.format("Fingerprint check failed for digest %s", name), + new SimpleImmutableEntry<>(true, expected), + KeyUtils.checkFingerPrint(expected, digestFactory, key) + ); + assertEquals( + String.format("Fingerprint check succeeded for invalid digest %s", name), + new SimpleImmutableEntry<>(false, expected), + KeyUtils.checkFingerPrint(expected + "A", digestFactory, key) + ); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java new file mode 100644 index 0000000..00b273f --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/KeyUtilsTest.java @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.config.keys; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.security.DigestException; +import java.util.Collection; +import java.util.Date; +import java.util.Map; + +import org.apache.sshd.common.digest.BaseDigest; +import org.apache.sshd.common.digest.BuiltinDigests; +import org.apache.sshd.common.digest.Digest; +import org.apache.sshd.common.digest.DigestFactory; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.OsUtils; +import org.apache.sshd.common.util.io.IoUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class KeyUtilsTest extends JUnitTestSupport { + public KeyUtilsTest() { + super(); + } + + @Test + public void testGenerateFingerPrintOnException() { + for (DigestFactory info : BuiltinDigests.VALUES) { + if (!info.isSupported()) { + System.out.println("Skip unsupported digest: " + info.getAlgorithm()); + continue; + } + + Exception thrown = new DigestException(info.getAlgorithm() + ":" + info.getBlockSize()); + Digest digest = new BaseDigest(info.getAlgorithm(), info.getBlockSize()) { + @Override + public byte[] digest() throws Exception { + throw thrown; + } + }; + String actual = KeyUtils.getFingerPrint(new DigestFactory() { + @Override + public String getName() { + return getCurrentTestName(); + } + + @Override + public String getAlgorithm() { + return digest.getAlgorithm(); + } + + @Override + public boolean isSupported() { + return info.isSupported(); + } + + @Override + public int getBlockSize() { + return info.getBlockSize(); + } + + @Override + public Digest create() { + return digest; + } + }, getCurrentTestName()); + String expected = thrown.getClass().getSimpleName(); + assertEquals("Mismatched fingerprint for " + thrown.getMessage(), expected, actual); + } + } + + @Test + public void testGenerateDefaultFingerprintDigest() { + DigestFactory defaultValue = KeyUtils.getDefaultFingerPrintFactory(); + assertNotNull("No current default fingerprint digest factory", defaultValue); + try { + for (DigestFactory f : BuiltinDigests.VALUES) { + if (!f.isSupported()) { + System.out.println("Skip unsupported digest=" + f.getAlgorithm()); + continue; + } + + KeyUtils.setDefaultFingerPrintFactory(f); + + String data = getClass().getName() + "#" + getCurrentTestName() + "(" + f.getName() + ")"; + String expected = KeyUtils.getFingerPrint(f, data); + String actual = KeyUtils.getFingerPrint(data); + assertEquals("Mismatched fingerprint for digest=" + f.getName(), expected, actual); + } + } finally { + KeyUtils.setDefaultFingerPrintFactory(defaultValue); // restore the original + } + } + + @Test // see SSHD-606 + public void testValidateStrictKeyFilePermissions() throws IOException { + Path file = getTempTargetRelativeFile(getClass().getSimpleName(), getCurrentTestName()); + outputDebugMessage("%s deletion result=%s", file, Files.deleteIfExists(file)); + assertNull("Unexpected violation for non-existent file: " + file, KeyUtils.validateStrictKeyFilePermissions(file)); + + assertHierarchyTargetFolderExists(file.getParent()); + try (OutputStream output = Files.newOutputStream(file)) { + output.write((getClass().getName() + "#" + getCurrentTestName() + "@" + new Date(System.currentTimeMillis())).getBytes(StandardCharsets.UTF_8)); + } + + Collection<PosixFilePermission> perms = IoUtils.getPermissions(file); + if (GenericUtils.isEmpty(perms)) { + assertNull("Unexpected violation for no permissions file: " + file, KeyUtils.validateStrictKeyFilePermissions(file)); + } else if (OsUtils.isUNIX()) { + Map.Entry<String, Object> violation = null; + for (PosixFilePermission p : KeyUtils.STRICTLY_PROHIBITED_FILE_PERMISSION) { + if (perms.contains(p)) { + violation = KeyUtils.validateStrictKeyFilePermissions(file); + assertNotNull("Unexpected success for permission=" + p + " of file " + file + " permissions=" + perms, violation); + break; + } + } + + if (violation == null) { // we expect a failure since the parent does not have the necessary permissions + assertNotNull("Unexpected UNIX success for file " + file + " permissions=" + perms, KeyUtils.validateStrictKeyFilePermissions(file)); + } + } else { + assertNull("Unexpected Windows violation for file " + file + " permissions=" + perms, KeyUtils.validateStrictKeyFilePermissions(file)); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.java new file mode 100644 index 0000000..1fd372f --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/PublicKeyEntryTest.java @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.config.keys; + +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.Arrays; + +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class PublicKeyEntryTest extends JUnitTestSupport { + public PublicKeyEntryTest() { + super(); + } + + @Test + public void testFallbackResolver() throws Exception { + PublicKeyEntry entry = // TODO use some + PublicKeyEntry.parsePublicKeyEntry( + GenericUtils.join( + Arrays.asList(getCurrentTestName(), "AAAA", getClass().getSimpleName()), ' ')); + for (PublicKeyEntryResolver resolver : new PublicKeyEntryResolver[]{ + null, PublicKeyEntryResolver.FAILING, PublicKeyEntryResolver.IGNORING}) { + try { + PublicKey key = entry.resolvePublicKey(resolver); + assertSame("Mismatched successful resolver", PublicKeyEntryResolver.IGNORING, resolver); + assertNull("Unexpected success for resolver=" + resolver + ": " + KeyUtils.getFingerPrint(key), key); + } catch (GeneralSecurityException e) { + assertObjectInstanceOf("Mismatched thrown exception for resolver=" + resolver, InvalidKeySpecException.class, e); + } + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java new file mode 100644 index 0000000..48797b8 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/AESPrivateKeyObfuscatorTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sshd.common.config.keys.loader; + +import java.security.GeneralSecurityException; +import java.security.Key; +import java.util.List; +import java.util.Random; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@Category({ NoIoTestCase.class }) +public class AESPrivateKeyObfuscatorTest extends JUnitTestSupport { + private static final Random RANDOMIZER = new Random(System.currentTimeMillis()); + + private final int keyLength; + + public AESPrivateKeyObfuscatorTest(int keyLength) { + this.keyLength = keyLength; + } + + @Parameters(name = "keyLength={0}") + public static List<Object[]> parameters() { + List<Integer> lengths = AESPrivateKeyObfuscator.getAvailableKeyLengths(); + assertFalse("No lengths available", GenericUtils.isEmpty(lengths)); + return parameterize(lengths); + } + + @Test + public void testAvailableKeyLengthExists() throws GeneralSecurityException { + assertEquals("Not a BYTE size multiple", 0, keyLength % Byte.SIZE); + + byte[] iv = new byte[keyLength / Byte.SIZE]; + synchronized (RANDOMIZER) { + RANDOMIZER.nextBytes(iv); + } + + Key key = new SecretKeySpec(iv, AESPrivateKeyObfuscator.CIPHER_NAME); + Cipher c = SecurityUtils.getCipher(AESPrivateKeyObfuscator.CIPHER_NAME); + c.init(Cipher.DECRYPT_MODE, key); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java new file mode 100644 index 0000000..d5c6aba --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sshd.common.config.keys.loader.openssh; + +import java.net.URL; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Collection; +import java.util.List; + +import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; +import org.apache.sshd.common.config.keys.BuiltinIdentities; +import org.apache.sshd.common.config.keys.FilePasswordProvider; +import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; +import org.apache.sshd.common.config.keys.PublicKeyEntryResolver; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.Assume; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@Category({ NoIoTestCase.class }) +public class OpenSSHKeyPairResourceParserTest extends JUnitTestSupport { + private static final OpenSSHKeyPairResourceParser PARSER = OpenSSHKeyPairResourceParser.INSTANCE; + private final BuiltinIdentities identity; + + public OpenSSHKeyPairResourceParserTest(BuiltinIdentities identity) { + this.identity = identity; + } + + @Parameters(name = "type={0}") + public static List<Object[]> parameters() { + return parameterize(BuiltinIdentities.VALUES); + } + + @Test + public void testLoadKeyPairs() throws Exception { + Assume.assumeTrue(identity + " not supported", identity.isSupported()); + + String resourceKey = getClass().getSimpleName() + "-" + identity.getName().toUpperCase() + "-" + KeyPair.class.getSimpleName(); + URL urlKeyPair = getClass().getResource(resourceKey); + assertNotNull("Missing key-pair resource: " + resourceKey, urlKeyPair); + + Collection<KeyPair> pairs = PARSER.loadKeyPairs(urlKeyPair, FilePasswordProvider.EMPTY); + assertEquals("Mismatched pairs count", 1, GenericUtils.size(pairs)); + + URL urlPubKey = getClass().getResource(resourceKey + ".pub"); + assertNotNull("Missing public key resource: " + resourceKey, urlPubKey); + + List<AuthorizedKeyEntry> entries = AuthorizedKeyEntry.readAuthorizedKeys(urlPubKey); + assertEquals("Mismatched public keys count", 1, GenericUtils.size(entries)); + + AuthorizedKeyEntry entry = entries.get(0); + PublicKey pubEntry = entry.resolvePublicKey(PublicKeyEntryResolver.FAILING); + assertNotNull("Cannot retrieve public key", pubEntry); + + Class<? extends PublicKey> pubType = identity.getPublicKeyType(); + Class<? extends PrivateKey> prvType = identity.getPrivateKeyType(); + for (KeyPair kp : pairs) { + PublicKey pubKey = ValidateUtils.checkInstanceOf(kp.getPublic(), pubType, "Mismatched public key type"); + assertKeyEquals("Mismatched identity public key", pubEntry, pubKey); + + PrivateKey prvKey = ValidateUtils.checkInstanceOf(kp.getPrivate(), prvType, "Mismatched private key type"); + @SuppressWarnings("rawtypes") + PrivateKeyEntryDecoder decoder = + OpenSSHKeyPairResourceParser.getPrivateKeyEntryDecoder(prvKey); + assertNotNull("No private key decoder", decoder); + + if (decoder.isPublicKeyRecoverySupported()) { + @SuppressWarnings("unchecked") + PublicKey recKey = decoder.recoverPublicKey(prvKey); + assertKeyEquals("Mismatched recovered public key", pubKey, recKey); + } + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java new file mode 100644 index 0000000..406a273 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/loader/pem/PKCS8PEMResourceKeyPairParserTest.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sshd.common.config.keys.loader.pem; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.commons.ssl.PEMItem; +import org.apache.commons.ssl.PEMUtil; +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * TODO Add javadoc + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class PKCS8PEMResourceKeyPairParserTest extends JUnitTestSupport { + private final String algorithm; + private final int keySize; + + public PKCS8PEMResourceKeyPairParserTest(String algorithm, int keySize) { + this.algorithm = algorithm; + this.keySize = keySize; + } + + @Parameters(name = "{0} / {1}") + public static List<Object[]> parameters() { + List<Object[]> params = new ArrayList<>(); + for (Integer ks : RSA_SIZES) { + params.add(new Object[]{KeyUtils.RSA_ALGORITHM, ks}); + } + for (Integer ks : DSS_SIZES) { + params.add(new Object[]{KeyUtils.DSS_ALGORITHM, ks}); + } + return params; + } + + @Test // see SSHD-760 + public void testPkcs8() throws IOException, GeneralSecurityException { + KeyPairGenerator generator = SecurityUtils.getKeyPairGenerator(algorithm); + if (keySize > 0) { + generator.initialize(keySize); + } + KeyPair kp = generator.generateKeyPair(); + + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + Collection<Object> items = new ArrayList<>(); + PrivateKey prv1 = kp.getPrivate(); + items.add(new PEMItem(prv1.getEncoded(), "PRIVATE KEY")); + byte[] bytes = PEMUtil.encode(items); + os.write(bytes); + os.close(); + + try (ByteArrayInputStream bais = new ByteArrayInputStream(os.toByteArray())) { + KeyPair kp2 = SecurityUtils.loadKeyPairIdentity(getCurrentTestName(), bais, null); + + assertEquals("Mismatched public key", kp.getPublic(), kp2.getPublic()); + assertEquals("Mismatched private key", prv1, kp2.getPrivate()); + } + } + } + + @Override + public String toString() { + return getClass().getSimpleName() + "[" + algorithm + "/" + keySize + "]"; + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java new file mode 100644 index 0000000..9ec928b --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/digest/BuiltinDigestsTest.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.digest; + +import java.lang.reflect.Field; +import java.util.EnumSet; +import java.util.Set; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class BuiltinDigestsTest extends JUnitTestSupport { + public BuiltinDigestsTest() { + super(); + } + + @Test + public void testFromName() { + for (BuiltinDigests expected : BuiltinDigests.VALUES) { + String name = expected.getName(); + BuiltinDigests actual = BuiltinDigests.fromFactoryName(name); + assertSame(name, expected, actual); + } + } + + @Test + public void testAllConstantsCovered() throws Exception { + Set<BuiltinDigests> avail = EnumSet.noneOf(BuiltinDigests.class); + Field[] fields = BuiltinDigests.Constants.class.getFields(); + for (Field f : fields) { + String name = (String) f.get(null); + BuiltinDigests value = BuiltinDigests.fromFactoryName(name); + assertNotNull("No match found for " + name, value); + assertTrue(name + " re-specified", avail.add(value)); + } + + assertEquals("Incomplete coverage", BuiltinDigests.VALUES, avail); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java b/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java new file mode 100644 index 0000000..05e3df2 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/future/DefaultSshFutureTest.java @@ -0,0 +1,137 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sshd.common.future; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class DefaultSshFutureTest extends JUnitTestSupport { + public DefaultSshFutureTest() { + super(); + } + + @Test + @SuppressWarnings("rawtypes") + public void testAwaitUninterrupted() { + DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null); + Object expected = new Object(); + new Thread() { + @Override + public void run() { + try { + Thread.sleep(TimeUnit.SECONDS.toMillis(2L)); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + future.setValue(expected); + } + }.start(); + + future.awaitUninterruptibly(); + assertSame("Mismatched signalled value", expected, future.getValue()); + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testNotifyMultipleListeners() { + DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null); + AtomicInteger listenerCount = new AtomicInteger(0); + Object expected = new Object(); + SshFutureListener listener = f -> { + assertSame("Mismatched future instance", future, f); + assertSame("Mismatched value object", expected, future.getValue()); + listenerCount.incrementAndGet(); + }; + + int numListeners = Byte.SIZE; + for (int index = 0; index < numListeners; index++) { + future.addListener(listener); + } + + future.setValue(expected); + assertEquals("Mismatched listeners invocation count", numListeners, listenerCount.get()); + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testListenerInvokedDirectlyAfterResultSet() { + DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null); + AtomicInteger listenerCount = new AtomicInteger(0); + Object expected = new Object(); + SshFutureListener listener = f -> { + assertSame("Mismatched future instance", future, f); + assertSame("Mismatched value object", expected, future.getValue()); + listenerCount.incrementAndGet(); + }; + future.setValue(expected); + + future.addListener(listener); + assertEquals("Mismatched number of registered listeners", 0, future.getNumRegisteredListeners()); + assertEquals("Listener not invoked", 1, listenerCount.get()); + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testAddAndRemoveRegisteredListenersBeforeResultSet() { + DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null); + SshFutureListener listener = Mockito.mock(SshFutureListener.class); + for (int index = 1; index <= Byte.SIZE; index++) { + future.addListener(listener); + assertEquals("Mismatched number of added listeners", index, future.getNumRegisteredListeners()); + } + + for (int index = future.getNumRegisteredListeners() - 1; index >= 0; index--) { + future.removeListener(listener); + assertEquals("Mismatched number of remaining listeners", index, future.getNumRegisteredListeners()); + } + } + + @Test + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void testListenerNotRemovedIfResultSet() { + DefaultSshFuture future = new DefaultSshFuture(getCurrentTestName(), null); + AtomicInteger listenerCount = new AtomicInteger(0); + Object expected = new Object(); + SshFutureListener listener = f -> { + assertSame("Mismatched future instance", future, f); + assertSame("Mismatched value object", expected, future.getValue()); + listenerCount.incrementAndGet(); + }; + future.addListener(listener); + future.setValue(expected); + assertEquals("Mismatched number of registered listeners", 1, future.getNumRegisteredListeners()); + assertEquals("Listener not invoked", 1, listenerCount.get()); + + future.removeListener(listener); + assertEquals("Mismatched number of remaining listeners", 1, future.getNumRegisteredListeners()); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java new file mode 100644 index 0000000..021796b --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.keyprovider; + +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; + +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class KeyPairProviderTest extends JUnitTestSupport { + public KeyPairProviderTest() { + super(); + } + + @Test + public void testEmptyKeyProvider() { + KeyPairProvider provider = KeyPairProvider.EMPTY_KEYPAIR_PROVIDER; + assertTrue("Non empty loaded keys", GenericUtils.isEmpty(provider.loadKeys())); + assertTrue("Non empty key type", GenericUtils.isEmpty(provider.getKeyTypes())); + + for (String keyType : new String[]{null, "", getCurrentTestName()}) { + assertNull("Unexpected key-pair loaded for type='" + keyType + "'", provider.loadKey(keyType)); + } + } + + @Test + public void testMapToKeyPairProvider() { + PublicKey pubKey = Mockito.mock(PublicKey.class); + PrivateKey prvKey = Mockito.mock(PrivateKey.class); + String[] testKeys = {getCurrentTestName(), getClass().getSimpleName()}; + Map<String, KeyPair> pairsMap = GenericUtils.toSortedMap( + Arrays.asList(testKeys), + Function.identity(), + k -> new KeyPair(pubKey, prvKey), + String.CASE_INSENSITIVE_ORDER); + + KeyPairProvider provider = MappedKeyPairProvider.MAP_TO_KEY_PAIR_PROVIDER.apply(pairsMap); + assertEquals("Key types", pairsMap.keySet(), provider.getKeyTypes()); + assertEquals("Key pairs", pairsMap.values(), provider.loadKeys()); + + pairsMap.forEach((keyType, expected) -> { + KeyPair actual = provider.loadKey(keyType); + assertSame(keyType, expected, actual); + }); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java new file mode 100644 index 0000000..0d50c41 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/mac/BuiltinMacsTest.java @@ -0,0 +1,166 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.mac; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +import org.apache.sshd.common.NamedResource; +import org.apache.sshd.common.mac.BuiltinMacs.ParseResult; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; +import org.mockito.Mockito; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class BuiltinMacsTest extends JUnitTestSupport { + public BuiltinMacsTest() { + super(); + } + + @Test + public void testFromName() { + for (BuiltinMacs expected : BuiltinMacs.VALUES) { + String name = expected.getName(); + BuiltinMacs actual = BuiltinMacs.fromFactoryName(name); + assertSame(name, expected, actual); + } + } + + @Test + public void testAllConstantsCovered() throws Exception { + Set<BuiltinMacs> avail = EnumSet.noneOf(BuiltinMacs.class); + Field[] fields = BuiltinMacs.Constants.class.getFields(); + for (Field f : fields) { + String name = (String) f.get(null); + BuiltinMacs value = BuiltinMacs.fromFactoryName(name); + assertNotNull("No match found for " + name, value); + assertTrue(name + " re-specified", avail.add(value)); + } + + assertEquals("Incomplete coverage", BuiltinMacs.VALUES, avail); + } + + @Test + public void testParseMacsList() { + List<String> builtin = NamedResource.getNameList(BuiltinMacs.VALUES); + List<String> unknown = Arrays.asList(getClass().getPackage().getName(), getClass().getSimpleName(), getCurrentTestName()); + Random rnd = new Random(); + for (int index = 0; index < (builtin.size() + unknown.size()); index++) { + Collections.shuffle(builtin, rnd); + Collections.shuffle(unknown, rnd); + + List<String> weavedList = new ArrayList<>(builtin.size() + unknown.size()); + for (int bIndex = 0, uIndex = 0; (bIndex < builtin.size()) || (uIndex < unknown.size());) { + boolean useBuiltin = false; + if (bIndex < builtin.size()) { + useBuiltin = uIndex >= unknown.size() || rnd.nextBoolean(); + } + + if (useBuiltin) { + weavedList.add(builtin.get(bIndex)); + bIndex++; + } else if (uIndex < unknown.size()) { + weavedList.add(unknown.get(uIndex)); + uIndex++; + } + } + + String fullList = GenericUtils.join(weavedList, ','); + ParseResult result = BuiltinMacs.parseMacsList(fullList); + List<String> parsed = NamedResource.getNameList(result.getParsedFactories()); + List<String> missing = result.getUnsupportedFactories(); + + // makes sure not only that the contents are the same but also the order + assertListEquals(fullList + "[parsed]", builtin, parsed); + assertListEquals(fullList + "[unsupported]", unknown, missing); + } + } + + @Test + public void testResolveFactoryOnBuiltinValues() { + for (MacFactory expected : BuiltinMacs.VALUES) { + String name = expected.getName(); + MacFactory actual = BuiltinMacs.resolveFactory(name); + assertSame(name, expected, actual); + } + } + + @Test + public void testNotAllowedToRegisterBuiltinFactories() { + for (MacFactory expected : BuiltinMacs.VALUES) { + try { + BuiltinMacs.registerExtension(expected); + fail("Unexpected success for " + expected.getName()); + } catch (IllegalArgumentException e) { + // expected - ignored + } + } + } + + @Test(expected = IllegalArgumentException.class) + public void testNotAllowedToOverrideRegisteredFactories() { + MacFactory expected = Mockito.mock(MacFactory.class); + Mockito.when(expected.getName()).thenReturn(getCurrentTestName()); + + String name = expected.getName(); + try { + for (int index = 1; index <= Byte.SIZE; index++) { + BuiltinMacs.registerExtension(expected); + assertEquals("Unexpected success at attempt #" + index, 1, index); + } + } finally { + BuiltinMacs.unregisterExtension(name); + } + } + + @Test + public void testResolveFactoryOnRegisteredExtension() { + MacFactory expected = Mockito.mock(MacFactory.class); + Mockito.when(expected.getName()).thenReturn(getCurrentTestName()); + + String name = expected.getName(); + try { + assertNull("Extension already registered", BuiltinMacs.resolveFactory(name)); + BuiltinMacs.registerExtension(expected); + + MacFactory actual = BuiltinMacs.resolveFactory(name); + assertSame("Mismatched resolved instance", expected, actual); + } finally { + MacFactory actual = BuiltinMacs.unregisterExtension(name); + assertSame("Mismatched unregistered instance", expected, actual); + assertNull("Extension not un-registered", BuiltinMacs.resolveFactory(name)); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java new file mode 100644 index 0000000..f330d22 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/mac/MacVectorsTest.java @@ -0,0 +1,311 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.sshd.common.mac; + +import java.nio.charset.StandardCharsets; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.apache.sshd.common.Factory; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.buffer.BufferUtils; +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * @see <A HREF="https://tools.ietf.org/html/rfc4231">RFC 4321</A> + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@Category({ NoIoTestCase.class }) +public class MacVectorsTest extends JUnitTestSupport { + private final VectorSeed seed; + private final Factory<? extends Mac> macFactory; + private final byte[] expected; + + public MacVectorsTest(VectorSeed seed, String factoryName, String expected) { + this.seed = Objects.requireNonNull(seed, "No seed"); + this.macFactory = ValidateUtils.checkNotNull(BuiltinMacs.fromFactoryName(factoryName), "Unknown MAC: %s", factoryName); + this.expected = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, expected); + } + + @Parameters(name = "factory={1}, expected={2}, seed={0}") + public static Collection<Object[]> parameters() { + List<Object[]> ret = new ArrayList<>(); + for (VectorTestData vector : Collections.unmodifiableList( + Arrays.asList( + ///////////////// Test Cases for HMAC-MD5 /////////////////////// + // see https://tools.ietf.org/html/rfc2202 + new VectorTestData("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", false, "Hi There", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5, // test case 1 + "9294727a3638bb1c13f48ef8158bfc9d"))), + new VectorTestData("Jefe", "what do ya want for nothing?", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5, // test case 2 + "750c783e6ab0b503eaa86e310a5db738"))), + new VectorTestData("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false, repeat("dd", 50), false, + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5, // test case 3 + "56be34521d144c88dbb8c733f0e8b3f6"))), + /* TODO see why it fails + new VectorTestData("0102030405060708090a0b0c0d0e0f10111213141516171819", false, repeat("cd", 50), false, + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5, // test case 4 + "697eaf0aca3a3aea3a75164746ffaa79"))), + */ + new VectorTestData("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", false, "Test With Truncation", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5, // test case 5 + "56461ef2342edc00f9bab995690efd4c"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5_96, + "56461ef2342edc00f9bab995"))), + /* TODO see why it fails + new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key - Hash Key First", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5, // test case 6 + "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd"))), + */ + /* TODO see why it fails + new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_MD5, // test case 7 + "6f630fad67cda0ee1fb1f562db3aa53e"))), + */ + ///////////////// Test Cases for HMAC-SHA-1 /////////////////////// + // see https://tools.ietf.org/html/rfc2202 + new VectorTestData("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", false, "Hi There", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 1 + "b617318655057264e28bc0b6fb378c8ef146be00"))), + new VectorTestData("Jefe", "what do ya want for nothing?", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 2 + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79"))), + new VectorTestData("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", false, repeat("dd", 50), false, + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 3 + "125d7342b9ac11cd91a39af48aa17b4f63f175d3"))), + /* TODO see why it fails + new VectorTestData("0102030405060708090a0b0c0d0e0f10111213141516171819", false, repeat("cd", 50), false, + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 4 + "4c9007f4026250c6bc8414f9bf50c86c2d7235da"))), + */ + new VectorTestData("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", false, "Test With Truncation", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 5 + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1_96, + "4c1a03424b55e07fe7f27be1"))), + /* TODO see why this fails + new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key - Hash Key First", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 6 + "aa4ae5e15272d00e95705637ce8a3b55ed402112"))), + */ + + /* TODO see why it fails + new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 7 + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1_96, + "4c1a03424b55e07fe7f27be1"))), + */ + + /* TODO see why it fails + new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key - Hash Key First", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 8 + "aa4ae5e15272d00e95705637ce8a3b55ed402112"))), + */ + + /* TODO see why it fails + new VectorTestData(repeat("aa", 80), false, "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + Arrays.asList(new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA1, // test case 9 + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91"))), + */ + + ///////////////// Test Cases for HMAC-SHA-2 /////////////////////// + // see https://tools.ietf.org/html/rfc4231 + new VectorTestData(repeat("0b", 20), false, "Hi There", + // test case 1 + Arrays.asList( + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256, + "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512, + "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"))), + new VectorTestData("Jefe", "what do ya want for nothing?", + // test case 2 + Arrays.asList( + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256, + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512, + "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737"))), + new VectorTestData(repeat("aa", 20), false, repeat("dd", 50), false, + // test case 3 + Arrays.asList( + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256, + "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512, + "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb"))), + new VectorTestData("0102030405060708090a0b0c0d0e0f10111213141516171819", false, repeat("cd", 50), false, + // test case 4 + Arrays.asList( + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256, + "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512, + "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd"))), + + /* TODO see why it fails + new VectorTestData(repeat("0c", 20), false, "Test With Truncation", + Arrays.asList( // test case 5 + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256, + "a3b6167473100ee06e0c796c2955552b"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512, + "415fad6271580a531d4179bc891d87a6"))), + */ + + /* TODO see why it fails + new VectorTestData(repeat("aa", 131), false, "Test Using Larger Than Block-Size Key - Hash Key First", + Arrays.asList( // test case 6 + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256, + "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512, + "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598"))), + */ + + /* TODO see why it fails + new VectorTestData(repeat("aa", 131), false, "This is a test using a larger than block-size" + + " key and a larger than block-size data." + + " The key needs to be hashed before being used" + + " by the HMAC algorithm", + Arrays.asList( // test case 7 + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_256, + "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2"), + new SimpleImmutableEntry<>(BuiltinMacs.Constants.HMAC_SHA2_512, + "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58"))) + */ + + // mark end + new VectorTestData("", false, "", false, Collections.emptyList())))) { + for (Map.Entry<String, String> tc : vector.getResults()) { + ret.add(new Object[]{vector, tc.getKey(), tc.getValue()}); + } + } + + return ret; + } + + @Test + public void testStandardVectorMac() throws Exception { + Mac mac = macFactory.create(); + mac.init(seed.getKey()); + mac.update(seed.getData()); + + byte[] actual = new byte[mac.getBlockSize()]; + mac.doFinal(actual); + assertArrayEquals("Mismatched results for actual=" + BufferUtils.toHex(BufferUtils.EMPTY_HEX_SEPARATOR, actual), expected, actual); + } + + private static class VectorSeed { + private final byte[] key; + private final String keyString; + private final byte[] data; + private final String dataString; + + VectorSeed(String key, String data) { + this.key = key.getBytes(StandardCharsets.UTF_8); + this.keyString = key; + this.data = data.getBytes(StandardCharsets.UTF_8); + this.dataString = data; + } + + VectorSeed(String key, boolean useKeyString, String data) { + this.key = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, key); + this.keyString = useKeyString ? new String(this.key, StandardCharsets.UTF_8) : key; + this.data = data.getBytes(StandardCharsets.UTF_8); + this.dataString = data; + } + + VectorSeed(String key, boolean useKeyString, String data, boolean useDataString) { + this.key = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, key); + this.keyString = useKeyString ? new String(this.key, StandardCharsets.UTF_8) : key; + this.data = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, data); + this.dataString = useDataString ? new String(this.data, StandardCharsets.UTF_8) : data; + } + + public byte[] getKey() { + return key.clone(); // clone to avoid inadvertent change + } + + public String getKeyString() { + return keyString; + } + + public byte[] getData() { + return data.clone(); // clone to avoid inadvertent change + } + + public String getDataString() { + return dataString; + } + + @Override + public String toString() { + return "key=" + trimToLength(getKeyString(), 32) + ", data=" + trimToLength(getDataString(), 32); + } + + private static CharSequence trimToLength(CharSequence csq, int maxLen) { + if (GenericUtils.length(csq) <= maxLen) { + return csq; + } + + return csq.subSequence(0, maxLen) + "..."; + } + } + + private static class VectorTestData extends VectorSeed { + private final Collection<Map.Entry<String, String>> results; + + VectorTestData(String key, String data, Collection<Map.Entry<String, String>> results) { + super(key, data); + this.results = results; + } + + VectorTestData(String key, boolean useKeyString, String data, Collection<Map.Entry<String, String>> results) { + super(key, useKeyString, data); + this.results = results; + } + + VectorTestData(String key, boolean useKeyString, String data, boolean useDataString, Collection<Map.Entry<String, String>> results) { + super(key, useKeyString, data, useDataString); + this.results = results; + } + + public Collection<Map.Entry<String, String>> getResults() { + return results; + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java b/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java new file mode 100644 index 0000000..08872d9 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.sshd.common.random; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.Assume; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +import org.junit.runners.Parameterized.UseParametersRunnerFactory; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests +@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class) +@Category({ NoIoTestCase.class }) +public class RandomFactoryTest extends JUnitTestSupport { + private final RandomFactory factory; + + public RandomFactoryTest(RandomFactory factory) { + this.factory = factory; + } + + @Parameters(name = "type={0}") + public static Collection<Object[]> parameters() { + Collection<RandomFactory> testCases = new LinkedList<>(); + testCases.add(JceRandomFactory.INSTANCE); + if (SecurityUtils.isBouncyCastleRegistered()) { + testCases.add(SecurityUtils.getRandomFactory()); + } else { + System.out.println("Skip BouncyCastleRandomFactory - unsupported"); + } + + return parameterize(testCases); + } + + @Test + public void testRandomFactory() { + Assume.assumeTrue("Skip unsupported factory: " + factory.getName(), factory.isSupported()); + long t = testRandom(factory.create()); + System.out.println(factory.getName() + " duration: " + t + " " + TimeUnit.MICROSECONDS); + } + + // returns duration in microseconds + private static long testRandom(Random random) { + byte[] bytes = new byte[32]; + long l0 = System.nanoTime(); + for (int i = 0; i < 1000; i++) { + random.fill(bytes, 8, 16); + } + long l1 = System.nanoTime(); + return TimeUnit.NANOSECONDS.toMicros(l1 - l0); + } +}
