http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java new file mode 100644 index 0000000..a94811d --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/IoUtilsTest.java @@ -0,0 +1,61 @@ +/* + * 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.util.io; + +import java.nio.file.LinkOption; + +import org.apache.sshd.common.util.NumberUtils; +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 IoUtilsTest extends JUnitTestSupport { + public IoUtilsTest() { + super(); + } + + @Test + public void testFollowLinks() { + assertTrue("Null ?", IoUtils.followLinks((LinkOption[]) null)); + assertTrue("Empty ?", IoUtils.followLinks(IoUtils.EMPTY_LINK_OPTIONS)); + assertFalse("No-follow ?", IoUtils.followLinks(IoUtils.getLinkOptions(false))); + } + + @Test + public void testGetEOLBytes() { + byte[] expected = IoUtils.getEOLBytes(); + assertTrue("Empty bytes", NumberUtils.length(expected) > 0); + + for (int index = 1; index < Byte.SIZE; index++) { + byte[] actual = IoUtils.getEOLBytes(); + assertNotSame("Same bytes received at iteration " + index, expected, actual); + assertArrayEquals("Mismatched bytes at iteration " + index, expected, actual); + } + } + +}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java new file mode 100644 index 0000000..e009527 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/LimitInputStreamTest.java @@ -0,0 +1,118 @@ +/* + * 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.util.io; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +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 LimitInputStreamTest extends JUnitTestSupport { + public LimitInputStreamTest() { + super(); + } + + @Test + public void testReadLimit() throws IOException { + Path targetPath = detectTargetFolder(); + Path rootFolder = assertHierarchyTargetFolderExists(targetPath.resolve(getClass().getSimpleName())); + Path inputFile = rootFolder.resolve(getCurrentTestName() + ".bin"); + byte[] data = (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8); + Files.write(inputFile, data); + + try (InputStream in = Files.newInputStream(inputFile)) { + int maxLen = data.length / 2; + byte[] expected = new byte[maxLen]; + System.arraycopy(data, 0, expected, 0, expected.length); + + byte[] actual = new byte[expected.length]; + try (LimitInputStream limited = new LimitInputStream(in, expected.length)) { + assertTrue("Limited stream not marked as open", limited.isOpen()); + assertEquals("Mismatched initial available data size", expected.length, limited.available()); + + int readLen = limited.read(actual); + assertEquals("Incomplete actual data read", actual.length, readLen); + assertArrayEquals("Mismatched read data", expected, actual); + assertEquals("Mismatched remaining available data size", 0, limited.available()); + + readLen = limited.read(); + assertTrue("Unexpected success to read one more byte: " + readLen, readLen < 0); + + readLen = limited.read(actual); + assertTrue("Unexpected success to read extra buffer: " + readLen, readLen < 0); + + limited.close(); + assertFalse("Limited stream still marked as open", limited.isOpen()); + + try { + readLen = limited.read(); + fail("Unexpected one byte read success after close"); + } catch (IOException e) { + // expected + } + + try { + readLen = limited.read(actual); + fail("Unexpected buffer read success after close: " + readLen); + } catch (IOException e) { + // expected + } + + try { + readLen = limited.read(actual); + fail("Unexpected buffer read success after close: " + readLen); + } catch (IOException e) { + // expected + } + + try { + readLen = (int) limited.skip(Byte.SIZE); + fail("Unexpected skip success after close: " + readLen); + } catch (IOException e) { + // expected + } + + try { + readLen = limited.available(); + fail("Unexpected available success after close: " + readLen); + } catch (IOException e) { + // expected + } + } + + // make sure underlying stream not closed + int readLen = in.read(actual); + assertEquals("Incomplete extra data read", Math.min(actual.length, data.length - expected.length), readLen); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java new file mode 100644 index 0000000..05343af --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/ModifiableFileWatcherTest.java @@ -0,0 +1,82 @@ +/* + * 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.util.io; + +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.util.Collection; +import java.util.Date; +import java.util.Map; + +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.OsUtils; +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 ModifiableFileWatcherTest extends JUnitTestSupport { + public ModifiableFileWatcherTest() { + super(); + } + + @Test // see SSHD-606 + public void testValidateStrictConfigFilePermissions() 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, ModifiableFileWatcher.validateStrictConfigFilePermissions(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, ModifiableFileWatcher.validateStrictConfigFilePermissions(file)); + } else if (OsUtils.isUNIX()) { + Map.Entry<String, Object> violation = null; + for (PosixFilePermission p : ModifiableFileWatcher.STRICTLY_PROHIBITED_FILE_PERMISSION) { + if (perms.contains(p)) { + violation = ModifiableFileWatcher.validateStrictConfigFilePermissions(file); + assertNotNull("Unexpected success for permission=" + p + " of file " + file + " permissions=" + perms, violation); + break; + } + } + + if (violation == null) { // we do not expected a failure if no permissions have been violated + assertNull("Unexpected UNIX violation for file " + file + " permissions=" + perms, ModifiableFileWatcher.validateStrictConfigFilePermissions(file)); + } + } else { + assertNull("Unexpected Windows violation for file " + file + " permissions=" + perms, ModifiableFileWatcher.validateStrictConfigFilePermissions(file)); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java new file mode 100644 index 0000000..564dc42 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseInputStreamTest.java @@ -0,0 +1,89 @@ +/* + * 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.util.io; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Date; + +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 NoCloseInputStreamTest extends JUnitTestSupport { + public NoCloseInputStreamTest() { + super(); + } + + @Test + public void testCanKeepReadingAfterClose() throws IOException { + byte[] expected = (getClass().getName() + "#" + getCurrentTestName() + "@" + new Date()).getBytes(StandardCharsets.UTF_8); + Path dir = createTempClassFolder(); + Path file = Files.write(dir.resolve(getCurrentTestName() + ".txt"), expected); + try (InputStream fileStream = Files.newInputStream(file); + InputStream shielded = new NoCloseInputStream(fileStream)) { + int index = 0; + + for (; index < (expected.length / 2); index++) { + shielded.close(); + + int readValue = shielded.read(); + if (readValue == -1) { + fail("Premature EOF after shield read of " + index + " bytes"); + } + + byte expValue = expected[index]; + byte actValue = (byte) (readValue & 0xFF); + if (expValue != actValue) { + fail("Mismatched shielded read value after " + index + " bytes"); + } + } + + for (; index < expected.length; index++) { + int readValue = fileStream.read(); + if (readValue == -1) { + fail("Premature EOF after original read of " + index + " bytes"); + } + byte expValue = expected[index]; + byte actValue = (byte) (readValue & 0xFF); + if (expValue != actValue) { + fail("Mismatched original read value after " + index + " bytes"); + } + } + + int readValue = shielded.read(); + assertEquals("Shielded EOF not signalled", -1, readValue); + + readValue = fileStream.read(); + assertEquals("Original EOF not signalled", -1, readValue); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java new file mode 100644 index 0000000..f01f132 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseOutputStreamTest.java @@ -0,0 +1,69 @@ +/* + * 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.util.io; + +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.util.Date; + +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 NoCloseOutputStreamTest extends JUnitTestSupport { + public NoCloseOutputStreamTest() { + super(); + } + + @Test + public void testCanKeepWritingAfterClose() throws IOException { + Path dir = createTempClassFolder(); + Path file = dir.resolve(getCurrentTestName() + ".txt"); + Files.deleteIfExists(file); + + String expectedOutput = getClass().getName() + "#" + getCurrentTestName() + "@" + new Date(); + byte[] expected = expectedOutput.getBytes(StandardCharsets.UTF_8); + try (OutputStream fileStream = Files.newOutputStream(file); + OutputStream shielded = new NoCloseOutputStream(fileStream)) { + int index = 0; + for (; index < (expected.length / 2); index++) { + shielded.close(); + shielded.write(expected[index] & 0xFF); + } + + fileStream.write(expected, index, expected.length - index); + } + + byte[] actual = Files.readAllBytes(file); + String actualOutput = new String(actual, StandardCharsets.UTF_8); + assertEquals(expectedOutput, actualOutput); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java new file mode 100644 index 0000000..14a72fc --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseReaderTest.java @@ -0,0 +1,95 @@ +/* + * 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.util.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Date; + +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 NoCloseReaderTest extends JUnitTestSupport { + public NoCloseReaderTest() { + super(); + } + + @Test + public void testCanKeepReadingAfterClose() throws IOException { + String expected = getClass().getName() + "#" + getCurrentTestName() + "@" + new Date(); + Path dir = createTempClassFolder(); + Path file = Files.write(dir.resolve(getCurrentTestName() + ".txt"), expected.getBytes(StandardCharsets.UTF_8)); + try (InputStream fileStream = Files.newInputStream(file); + Reader rdr = new InputStreamReader(fileStream, StandardCharsets.UTF_8); + Reader shielded = new NoCloseReader(rdr)) { + int index = 0; + + int availLen = expected.length(); + for (; index < (availLen / 2); index++) { + shielded.close(); + + int readValue = shielded.read(); + if (readValue == -1) { + fail("Premature EOF after shield read of " + index + " bytes"); + } + + char expValue = expected.charAt(index); + char actValue = (char) (readValue & 0xFFFF); + if (expValue != actValue) { + fail("Mismatched shielded read value after " + index + " bytes"); + } + } + + for (; index < availLen; index++) { + int readValue = rdr.read(); + if (readValue == -1) { + fail("Premature EOF after original read of " + index + " bytes"); + } + + char expValue = expected.charAt(index); + char actValue = (char) (readValue & 0xFFFF); + if (expValue != actValue) { + fail("Mismatched original read value after " + index + " bytes"); + } + } + + int readValue = shielded.read(); + assertEquals("Shielded EOF not signalled", -1, readValue); + + readValue = rdr.read(); + assertEquals("Original EOF not signalled", -1, readValue); + } + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java new file mode 100644 index 0000000..b49678e --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NoCloseWriterTest.java @@ -0,0 +1,73 @@ +/* + * 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.util.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Date; + +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 NoCloseWriterTest extends JUnitTestSupport { + public NoCloseWriterTest() { + super(); + } + + @Test + public void testCanKeepWritingAfterClose() throws IOException { + Path dir = createTempClassFolder(); + Path file = dir.resolve(getCurrentTestName() + ".txt"); + Files.deleteIfExists(file); + + String expected = getClass().getName() + "#" + getCurrentTestName() + "@" + new Date(); + try (OutputStream fileStream = Files.newOutputStream(file); + Writer w = new OutputStreamWriter(fileStream, StandardCharsets.UTF_8); + Writer shielded = new NoCloseWriter(w)) { + int index = 0; + int availLen = expected.length(); + for (; index < (availLen / 2); index++) { + shielded.close(); + shielded.write(expected.charAt(index)); + } + + w.write(expected, index, availLen - index); + } + + byte[] actualBytes = Files.readAllBytes(file); + String actual = new String(actualBytes, StandardCharsets.UTF_8); + assertEquals(expected, actual); + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java new file mode 100644 index 0000000..31982da --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullInputStreamTest.java @@ -0,0 +1,118 @@ +/* + * 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.util.io; + +import java.io.EOFException; +import java.io.IOException; + +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 NullInputStreamTest extends JUnitTestSupport { + private static final NullInputStream INSTANCE = new NullInputStream(); + + public NullInputStreamTest() { + super(); + } + + @Test + public void testReadOneChar() throws IOException { + assertEquals(-1, INSTANCE.read()); + } + + @Test + public void testReadFullBuffer() throws IOException { + assertEquals(-1, INSTANCE.read(new byte[Byte.SIZE])); + } + + @Test + public void testReadPartialBuffer() throws IOException { + byte[] buf = new byte[Byte.SIZE]; + assertEquals(-1, INSTANCE.read(buf, buf.length / 2, (buf.length / 2) - 1)); + } + + @Test + public void testSkip() throws IOException { + assertEquals(0L, INSTANCE.skip(Long.SIZE)); + } + + @Test + public void testAvailable() throws IOException { + assertEquals(0, INSTANCE.available()); + } + + @Test + public void testNotAllowedToAccessAfterClose() throws IOException { + NullInputStream stream = new NullInputStream(); + stream.close(); + assertFalse("Stream not marked as closed", stream.isOpen()); + + try { + int nRead = stream.read(); + fail("Unexpected single byte read: " + nRead); + } catch (EOFException e) { + // expected + } + + byte[] buf = new byte[Byte.SIZE]; + try { + int nRead = stream.read(buf); + fail("Unexpected full buffer read: " + nRead); + } catch (EOFException e) { + // expected + } + + try { + int nRead = stream.read(buf, buf.length / 2, (buf.length / 2) - 1); + fail("Unexpected partial buffer read: " + nRead); + } catch (EOFException e) { + // expected + } + + try { + long skip = stream.skip(Long.SIZE); + fail("Unexpected skip result: " + skip); + } catch (EOFException e) { + // expected + } + + try { + int nRead = stream.available(); + fail("Unexpected available count: " + nRead); + } catch (IOException e) { + // expected + } + try { + stream.reset(); + fail("Unexpected reset success"); + } catch (EOFException e) { + // expected + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java new file mode 100644 index 0000000..0fe845f --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/NullOutputStreamTest.java @@ -0,0 +1,80 @@ +/* + * 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.util.io; + +import java.io.EOFException; +import java.io.IOException; +import java.util.Arrays; + +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 NullOutputStreamTest extends JUnitTestSupport { + public NullOutputStreamTest() { + super(); + } + + @Test + public void testNoAccessAllowedAfterClose() throws IOException { + NullOutputStream stream = new NullOutputStream(); + stream.close(); + assertFalse("Stream not marked as closed", stream.isOpen()); + + try { + stream.write('a'); + fail("Unexpected single value write success"); + } catch (EOFException e) { + // expected + } + + byte[] buf = new byte[Byte.SIZE]; + try { + Arrays.fill(buf, (byte) 0x41); + stream.write(buf); + fail("Unexpected full buffer write success"); + } catch (EOFException e) { + // expected + } + + try { + Arrays.fill(buf, (byte) 0x42); + stream.write(buf, buf.length / 2, (buf.length / 2) - 1); + fail("Unexpected partial buffer write success"); + } catch (EOFException e) { + // expected + } + + try { + stream.flush(); + fail("Unexpected flush success"); + } catch (EOFException e) { + // expected + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java new file mode 100644 index 0000000..5f30529 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1ClassTest.java @@ -0,0 +1,67 @@ +/* + * 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.util.io.der; + +import java.util.List; + +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 ASN1ClassTest extends JUnitTestSupport { + private final ASN1Class expected; + + public ASN1ClassTest(ASN1Class expected) { + this.expected = expected; + } + + @Parameters(name = "{0}") + public static List<Object[]> parameters() { + return parameterize(ASN1Class.VALUES); + } + + @Test + public void testFromName() { + String name = expected.name(); + for (int index = 1, count = name.length(); index <= count; index++) { + assertSame(name, expected, ASN1Class.fromName(name)); + name = shuffleCase(name); + } + } + + @Test // NOTE: this also tests "fromTypeValue" since "fromDERValue" invokes it + public void testFromDERValue() { + assertSame(expected, ASN1Class.fromDERValue((expected.getClassValue() << 6) & 0xFF)); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java new file mode 100644 index 0000000..06034e2 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/ASN1TypeTest.java @@ -0,0 +1,67 @@ +/* + * 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.util.io.der; + +import java.util.List; + +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 ASN1TypeTest extends JUnitTestSupport { + private final ASN1Type expected; + + public ASN1TypeTest(ASN1Type expected) { + this.expected = expected; + } + + @Parameters(name = "{0}") + public static List<Object[]> parameters() { + return parameterize(ASN1Type.VALUES); + } + + @Test + public void testFromName() { + String name = expected.name(); + for (int index = 1, count = name.length(); index <= count; index++) { + assertSame(name, expected, ASN1Type.fromName(name)); + name = shuffleCase(name); + } + } + + @Test + public void testFromTypeValue() { + assertSame(expected, ASN1Type.fromTypeValue(expected.getTypeValue())); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java new file mode 100644 index 0000000..ecc5b31 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERParserTest.java @@ -0,0 +1,61 @@ +/* + * 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.util.io.der; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StreamCorruptedException; + +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 DERParserTest extends JUnitTestSupport { + public DERParserTest() { + super(); + } + + @Test + public void testReadLengthConstraint() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + try (DERWriter w = new DERWriter(baos)) { + w.writeLength(DERParser.MAX_DER_VALUE_LENGTH + 1); + } + } finally { + baos.close(); + } + + try (DERParser parser = new DERParser(baos.toByteArray())) { + int len = parser.readLength(); + fail("Unexpected success: len=" + len); + } catch (StreamCorruptedException e) { + // expected ignored + } + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java new file mode 100644 index 0000000..3064caa --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/io/der/DERWriterTest.java @@ -0,0 +1,64 @@ +/* + * 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.util.io.der; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +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 DERWriterTest extends JUnitTestSupport { + public DERWriterTest() { + super(); + } + + @Test + public void testWriteStripLeadingZeroes() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + try (DERWriter w = new DERWriter(baos)) { + w.writeBigInteger(BigInteger.valueOf(-1)); + w.writeBigInteger(BigInteger.valueOf(129)); + w.writeBigInteger(new byte[] {0, 0}, 0, 2); + w.writeBigInteger(new byte[] {0, 1}, 0, 2); + } + } finally { + baos.close(); + } + + try (DERParser parser = new DERParser(baos.toByteArray())) { + assertEquals(BigInteger.valueOf(255), parser.readBigInteger()); + assertEquals(BigInteger.valueOf(129), parser.readBigInteger()); + assertEquals(BigInteger.valueOf(0), parser.readBigInteger()); + assertEquals(BigInteger.valueOf(1), parser.readBigInteger()); + } + } + +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java new file mode 100644 index 0000000..a38db34 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/net/SshdSocketIpv6AddressTest.java @@ -0,0 +1,88 @@ +/* + * 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.util.net; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +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> + */ +@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 SshdSocketIpv6AddressTest extends JUnitTestSupport { + public static final List<String> VALID_ADDRESSES = + Collections.unmodifiableList( + Arrays.asList( + "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:db8:85a3:0:0:8a2e:370:7334", + "2001:db8:85a3::8a2e:370:7334", + "2001:0db8::0001", "2001:db8::1", + "2001:db8:0:0:0:0:2:1", "2001:db8::2:1", + "2001:db8:0000:1:1:1:1:1", "2001:db8:0:1:1:1:1:1", + "2001:db8:85a3:8d3:1319:8a2e:370:7348", + "fe80::1ff:fe23:4567:890a", "fe80::1ff:fe23:4567:890a%eth2", + "fe80::1ff:fe23:4567:890a%3", "fe80:3::1ff:fe23:4567:890a", + "::ffff:c000:0280", "::ffff:192.0.2.128")); + + private final String address; + private final boolean matches; + + public SshdSocketIpv6AddressTest(String address, boolean matches) { + this.address = address; + this.matches = matches; + } + + @Parameters(name = "{0}") + public static List<Object[]> parameters() { + return Stream + .concat(SshdSocketAddress.WELL_KNOWN_IPV6_ADDRESSES.stream(), VALID_ADDRESSES.stream()) + .map(address -> new Object[] {address, Boolean.TRUE}) + .collect(Collectors.toList()); + } + + @Test + public void testIPv6AddressValidity() { + assertEquals(address, matches, SshdSocketAddress.isIPv6Address(address)); + } + + @Override + public String toString() { + return getClass().getSimpleName() + + "[address=" + address + + " , matches=" + matches + + "]"; + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java new file mode 100644 index 0000000..5d40c59 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarCipherNameTest.java @@ -0,0 +1,75 @@ +/* + * 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.util.security; + +import java.util.ArrayList; +import java.util.List; + +import javax.crypto.Cipher; + +import org.apache.sshd.common.cipher.BuiltinCiphers; +import org.apache.sshd.common.cipher.CipherInformation; +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 SecurityProviderRegistrarCipherNameTest extends JUnitTestSupport { + private final CipherInformation cipherInfo; + + public SecurityProviderRegistrarCipherNameTest(CipherInformation cipherInfo) { + this.cipherInfo = cipherInfo; + } + + @Parameters(name = "{0}") + public static List<Object[]> parameters() { + List<Object[]> params = new ArrayList<>(); + for (CipherInformation cipherInfo : BuiltinCiphers.VALUES) { + String algorithm = cipherInfo.getAlgorithm(); + String xform = cipherInfo.getTransformation(); + if (!xform.startsWith(algorithm)) { + continue; + } + + params.add(new Object[]{cipherInfo}); + } + return params; + } + + @Test + public void testGetEffectiveSecurityEntityName() { + String expected = cipherInfo.getAlgorithm(); + String actual = SecurityProviderRegistrar.getEffectiveSecurityEntityName(Cipher.class, cipherInfo.getTransformation()); + assertEquals("Mismatched pure cipher name", expected, actual); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.java new file mode 100644 index 0000000..9958916 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityProviderRegistrarTestSupport.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.util.security; + +import java.security.Provider; +import java.util.Arrays; +import java.util.Collection; + +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.experimental.categories.Category; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@Category({ NoIoTestCase.class }) +public abstract class SecurityProviderRegistrarTestSupport extends JUnitTestSupport { + protected SecurityProviderRegistrarTestSupport() { + super(); + } + + public static Provider testGetSecurityProviderCaching(String prefix, SecurityProviderRegistrar registrar) { + return testGetSecurityProviderCaching(prefix, registrar, registrar.getSecurityProvider()); + } + + public static <P extends Provider> P testGetSecurityProviderCaching(String prefix, SecurityProviderRegistrar registrar, P expected) { + for (int index = 1; index <= Byte.SIZE; index++) { + Provider actual = registrar.getSecurityProvider(); + assertSame(prefix + ": Mismatched provider instance at invocation #" + index, expected, actual); + } + + return expected; + } + + public static void assertSecurityEntitySupportState( + String prefix, SecurityProviderRegistrar registrar, boolean expected, String name, Class<?>... entities) { + assertSecurityEntitySupportState(prefix, registrar, expected, name, Arrays.asList(entities)); + } + + public static void assertSecurityEntitySupportState( + String prefix, SecurityProviderRegistrar registrar, boolean expected, String name, Collection<Class<?>> entities) { + for (Class<?> entity : entities) { + assertEquals(prefix + "[" + entity.getSimpleName() + "]", expected, registrar.isSecurityEntitySupported(entity, name)); + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java new file mode 100644 index 0000000..46ca075 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/SecurityUtilsTest.java @@ -0,0 +1,231 @@ +/* + * 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.util.security; + +import java.io.IOException; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.sshd.common.cipher.BuiltinCiphers; +import org.apache.sshd.common.cipher.ECCurves; +import org.apache.sshd.common.config.keys.FilePasswordProvider; +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.loader.KeyPairResourceLoader; +import org.apache.sshd.common.keyprovider.AbstractResourceKeyPairProvider; +import org.apache.sshd.common.keyprovider.ClassLoadableResourceKeyPairProvider; +import org.apache.sshd.common.keyprovider.FileKeyPairProvider; +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.AfterClass; +import org.junit.Assume; +import org.junit.BeforeClass; +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 }) +@SuppressWarnings("checkstyle:MethodCount") +public class SecurityUtilsTest extends JUnitTestSupport { + public static final String BC_NAMED_USAGE_PROP = + SecurityProviderRegistrar.CONFIG_PROP_BASE + + "." + SecurityUtils.BOUNCY_CASTLE + + "." + SecurityProviderRegistrar.NAMED_PROVIDER_PROPERTY; + + private static final String DEFAULT_PASSWORD = "super secret passphrase"; + private static final FilePasswordProvider TEST_PASSWORD_PROVIDER = file -> DEFAULT_PASSWORD; + + public SecurityUtilsTest() { + super(); + } + + // NOTE: Using the BouncyCastle provider instead of the name does not work as expected so we take no chances + @BeforeClass + public static void useNamedBouncyCastleProvider() { + System.setProperty(BC_NAMED_USAGE_PROP, Boolean.TRUE.toString()); + } + + @AfterClass + public static void unsetBouncyCastleProviderUsagePreference() { + System.clearProperty(BC_NAMED_USAGE_PROP); + } + + @Test + public void testLoadEncryptedDESPrivateKey() throws Exception { + testLoadEncryptedRSAPrivateKey("DES-EDE3"); + } + + @Test + public void testLoadEncryptedAESPrivateKey() { + for (BuiltinCiphers c : new BuiltinCiphers[]{ + BuiltinCiphers.aes128cbc, BuiltinCiphers.aes192cbc, BuiltinCiphers.aes256cbc + }) { + if (!c.isSupported()) { + System.out.println("Skip unsupported encryption scheme: " + c.getName()); + continue; + } + + try { + testLoadEncryptedRSAPrivateKey("AES-" + c.getKeySize()); + } catch (Exception e) { + fail("Failed (" + e.getClass().getSimpleName() + " to load key for " + c.getName() + ": " + e.getMessage()); + } + } + } + + private KeyPair testLoadEncryptedRSAPrivateKey(String algorithm) throws IOException, GeneralSecurityException { + return testLoadRSAPrivateKey(DEFAULT_PASSWORD.replace(' ', '-') + "-RSA-" + algorithm.toUpperCase() + "-key"); + } + + @Test + public void testLoadUnencryptedRSAPrivateKey() throws Exception { + testLoadRSAPrivateKey(getClass().getSimpleName() + "-RSA-KeyPair"); + } + + @Test + public void testLoadUnencryptedDSSPrivateKey() throws Exception { + testLoadDSSPrivateKey(getClass().getSimpleName() + "-DSA-KeyPair"); + } + + private KeyPair testLoadDSSPrivateKey(String name) throws Exception { + return testLoadPrivateKey(name, DSAPublicKey.class, DSAPrivateKey.class); + } + + @Test + public void testLoadUnencryptedECPrivateKey() throws Exception { + Assume.assumeTrue("EC not supported", SecurityUtils.isECCSupported()); + for (ECCurves c : ECCurves.VALUES) { + if (!c.isSupported()) { + System.out.println("Skip unsupported curve: " + c.getName()); + continue; + } + + testLoadECPrivateKey(getClass().getSimpleName() + "-EC-" + c.getKeySize() + "-KeyPair"); + } + } + + private KeyPair testLoadECPrivateKey(String name) throws IOException, GeneralSecurityException { + return testLoadPrivateKey(name, ECPublicKey.class, ECPrivateKey.class); + } + + private KeyPair testLoadRSAPrivateKey(String name) throws IOException, GeneralSecurityException { + return testLoadPrivateKey(name, RSAPublicKey.class, RSAPrivateKey.class); + } + + private KeyPair testLoadPrivateKey(String name, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) + throws IOException, GeneralSecurityException { + Path folder = getTestResourcesFolder(); + Path file = folder.resolve(name); + KeyPair kpFile = testLoadPrivateKeyFile(file, pubType, prvType); + if (SecurityUtils.isBouncyCastleRegistered()) { + KeyPairResourceLoader bcLoader = SecurityUtils.getBouncycastleKeyPairResourceParser(); + Collection<KeyPair> kpList = bcLoader.loadKeyPairs(file, TEST_PASSWORD_PROVIDER); + assertEquals(name + ": Mismatched loaded BouncyCastle keys count", 1, GenericUtils.size(kpList)); + + KeyPair kpBC = kpList.iterator().next(); + assertTrue(name + ": Mismatched BouncyCastle vs. file values", KeyUtils.compareKeyPairs(kpFile, kpBC)); + } + + Class<?> clazz = getClass(); + Package pkg = clazz.getPackage(); + KeyPair kpResource = testLoadPrivateKeyResource(pkg.getName().replace('.', '/') + "/" + name, pubType, prvType); + assertTrue(name + ": Mismatched key file vs. resource values", KeyUtils.compareKeyPairs(kpFile, kpResource)); + return kpResource; + } + + private static KeyPair testLoadPrivateKeyResource(String name, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) { + return testLoadPrivateKey(name, new ClassLoadableResourceKeyPairProvider(name), pubType, prvType); + } + + private static KeyPair testLoadPrivateKeyFile(Path file, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) { + return testLoadPrivateKey(file.toString(), new FileKeyPairProvider(file), pubType, prvType); + } + + private static KeyPair testLoadPrivateKey(String resourceKey, AbstractResourceKeyPairProvider<?> provider, + Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) { + provider.setPasswordFinder(TEST_PASSWORD_PROVIDER); + Iterable<KeyPair> iterator = provider.loadKeys(); + List<KeyPair> pairs = new ArrayList<>(); + for (KeyPair kp : iterator) { + pairs.add(kp); + } + + assertEquals("Mismatched loaded pairs count for " + resourceKey, 1, pairs.size()); + + KeyPair kp = pairs.get(0); + PublicKey pub = kp.getPublic(); + assertNotNull("No public key extracted", pub); + assertTrue("Not an " + pubType.getSimpleName() + " public key for " + resourceKey, pubType.isAssignableFrom(pub.getClass())); + + PrivateKey prv = kp.getPrivate(); + assertNotNull("No private key extracted", prv); + assertTrue("Not an " + prvType.getSimpleName() + " private key for " + resourceKey, prvType.isAssignableFrom(prv.getClass())); + + return kp; + } + + @Test + public void testSetMaxDHGroupExchangeKeySizeByProperty() { + try { + for (int expected = SecurityUtils.MIN_DHGEX_KEY_SIZE; expected <= SecurityUtils.MAX_DHGEX_KEY_SIZE; expected += 1024) { + SecurityUtils.setMaxDHGroupExchangeKeySize(0); // force detection + try { + System.setProperty(SecurityUtils.MAX_DHGEX_KEY_SIZE_PROP, Integer.toString(expected)); + assertTrue("DH group not supported for key size=" + expected, SecurityUtils.isDHGroupExchangeSupported()); + assertEquals("Mismatched values", expected, SecurityUtils.getMaxDHGroupExchangeKeySize()); + } finally { + System.clearProperty(SecurityUtils.MAX_DHGEX_KEY_SIZE_PROP); + } + } + } finally { + SecurityUtils.setMaxDHGroupExchangeKeySize(0); // force detection + } + } + + @Test + public void testSetMaxDHGroupExchangeKeySizeProgrammatically() { + try { + for (int expected = SecurityUtils.MIN_DHGEX_KEY_SIZE; expected <= SecurityUtils.MAX_DHGEX_KEY_SIZE; expected += 1024) { + SecurityUtils.setMaxDHGroupExchangeKeySize(expected); + assertTrue("DH group not supported for key size=" + expected, SecurityUtils.isDHGroupExchangeSupported()); + assertEquals("Mismatched values", expected, SecurityUtils.getMaxDHGroupExchangeKeySize()); + } + } finally { + SecurityUtils.setMaxDHGroupExchangeKeySize(0); // force detection + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java new file mode 100644 index 0000000..7da51c5 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/EDDSAProviderTest.java @@ -0,0 +1,126 @@ +/* + * 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.util.security.eddsa; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Signature; + +import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; +import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.util.buffer.Buffer; +import org.apache.sshd.common.util.buffer.ByteArrayBuffer; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.util.test.JUnitTestSupport; +import org.apache.sshd.util.test.NoIoTestCase; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.MethodSorters; + +import net.i2p.crypto.eddsa.EdDSAEngine; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@Category({ NoIoTestCase.class }) +public class EDDSAProviderTest extends JUnitTestSupport { + private static KeyPair keyPair; + + public EDDSAProviderTest() { + super(); + } + + @BeforeClass + public static void checkProviderSupported() throws GeneralSecurityException { + Assume.assumeTrue(SecurityUtils.EDDSA + " not supported", SecurityUtils.isEDDSACurveSupported()); + KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA); + assertNotNull("No generator instance", g); + + keyPair = g.generateKeyPair(); + assertNotNull("No key pair generated", keyPair); + + PublicKey pubKey = keyPair.getPublic(); + assertNotNull("No public key", pubKey); + assertEquals("Mismatched public key algorithm", SecurityUtils.EDDSA, pubKey.getAlgorithm()); + assertEquals("Mismatched public key type", KeyPairProvider.SSH_ED25519, KeyUtils.getKeyType(pubKey)); + + PrivateKey prvKey = keyPair.getPrivate(); + assertNotNull("No private key", prvKey); + assertEquals("Mismatched key-pair algorithm", pubKey.getAlgorithm(), prvKey.getAlgorithm()); + assertEquals("Mismatched private key type", KeyPairProvider.SSH_ED25519, KeyUtils.getKeyType(prvKey)); + } + + @Test + public void testSignature() throws GeneralSecurityException { + Signature s = SecurityUtils.getSignature(EdDSAEngine.SIGNATURE_ALGORITHM); + assertNotNull("No signature instance", s); + s.initSign(keyPair.getPrivate()); + + byte[] data = (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8); + s.update(data); + byte[] signed = s.sign(); + + s = SecurityUtils.getSignature(EdDSAEngine.SIGNATURE_ALGORITHM); + s.initVerify(keyPair.getPublic()); + s.update(data); + assertTrue("Failed to verify", s.verify(signed)); + } + + @Test + public void testPublicKeyEntryDecoder() throws IOException, GeneralSecurityException { + String comment = getCurrentTestName() + "@" + getClass().getSimpleName(); + String expected = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGPKSUTyz1HwHReFVvD5obVsALAgJRNarH4TRpNePnAS " + comment; + AuthorizedKeyEntry keyEntry = AuthorizedKeyEntry.parseAuthorizedKeyEntry(expected); + assertNotNull("No extracted key entry", keyEntry); + + assertEquals("Mismatched key type", KeyPairProvider.SSH_ED25519, keyEntry.getKeyType()); + assertEquals("Mismatched comment", comment, keyEntry.getComment()); + + StringBuilder sb = new StringBuilder(expected.length()); + PublicKey pubKey = keyEntry.appendPublicKey(sb, null); + assertEquals("Mismatched encoded result", expected, sb.toString()); + + testPublicKeyRecovery(pubKey); + } + + @Test + public void testGeneratedPublicKeyRecovery() throws IOException, GeneralSecurityException { + testPublicKeyRecovery(keyPair.getPublic()); + } + + private void testPublicKeyRecovery(PublicKey pubKey) throws IOException, GeneralSecurityException { + assertNotNull("No public key generated", pubKey); + assertEquals("Mismatched public key algorithm", SecurityUtils.EDDSA, pubKey.getAlgorithm()); + + Buffer buf = SecurityUtils.putRawEDDSAPublicKey(new ByteArrayBuffer(), pubKey); + PublicKey actual = buf.getRawPublicKey(); + assertEquals("Mismatched key algorithm", pubKey.getAlgorithm(), actual.getAlgorithm()); + assertEquals("Mismatched recovered key", pubKey, actual); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/10de190e/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java ---------------------------------------------------------------------- diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java new file mode 100644 index 0000000..cfebb85 --- /dev/null +++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/eddsa/Ed25519VectorsTest.java @@ -0,0 +1,238 @@ +/* + * 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.util.security.eddsa; + +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.sshd.common.signature.Signature; +import org.apache.sshd.common.util.buffer.BufferUtils; +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.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; + +import net.i2p.crypto.eddsa.EdDSAPrivateKey; +import net.i2p.crypto.eddsa.EdDSAPublicKey; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + * @see <A HREF="https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-02#section-6"> + * EdDSA and Ed25519 draft-josefsson-eddsa-ed25519-02 - section 6 - Test Vectors for Ed25519</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 Ed25519VectorsTest extends JUnitTestSupport { + private final byte[] prvBytes; + private final PrivateKey privateKey; + private final byte[] pubBytes; + private final PublicKey publicKey; + private final byte[] msgBytes; + private final byte[] expSignature; + + public Ed25519VectorsTest(String name, String prvKey, String pubKey, String msg, String signature) + throws GeneralSecurityException { + prvBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, prvKey); + privateKey = EdDSASecurityProviderUtils.generateEDDSAPrivateKey(prvBytes.clone()); + pubBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, pubKey); + publicKey = EdDSASecurityProviderUtils.generateEDDSAPublicKey(pubBytes.clone()); + msgBytes = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, msg); + expSignature = BufferUtils.decodeHex(BufferUtils.EMPTY_HEX_SEPARATOR, signature); + } + + @Parameters(name = "{0}") + @SuppressWarnings("checkstyle:anoninnerlength") + public static List<Object[]> parameters() { + return new ArrayList<>(Arrays.asList( + new Object[]{ + "TEST1 - empty message", + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", + "", + "e5564300c360ac729086e2cc806e828a" + + "84877f1eb8e5d974d873e06522490155" + + "5fb8821590a33bacc61e39701cf9b46b" + + "d25bf5f0595bbe24655141438e7a100b" + }, + new Object[]{ + "TEST2 - one byte", + "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", + "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", + "72", + "92a009a9f0d4cab8720e820b5f642540" + + "a2b27b5416503f8fb3762223ebdb69da" + + "085ac1e43e15996e458f3613d0f11d8c" + + "387b2eaeb4302aeeb00d291612bb0c00" + }, + new Object[]{ + "TEST3 - 2 bytes", + "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", + "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", + "af82", + "6291d657deec24024827e69c3abe01a3" + + "0ce548a284743a445e3680d7db5ac3ac" + + "18ff9b538d16f290ae67f760984dc659" + + "4a7c15e9716ed28dc027beceea1ec40a" + }, + new Object[]{ + "TEST1024 - large message", + "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5", + "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e", + "08b8b2b733424243760fe426a4b54908" + + "632110a66c2f6591eabd3345e3e4eb98" + + "fa6e264bf09efe12ee50f8f54e9f77b1" + + "e355f6c50544e23fb1433ddf73be84d8" + + "79de7c0046dc4996d9e773f4bc9efe57" + + "38829adb26c81b37c93a1b270b20329d" + + "658675fc6ea534e0810a4432826bf58c" + + "941efb65d57a338bbd2e26640f89ffbc" + + "1a858efcb8550ee3a5e1998bd177e93a" + + "7363c344fe6b199ee5d02e82d522c4fe" + + "ba15452f80288a821a579116ec6dad2b" + + "3b310da903401aa62100ab5d1a36553e" + + "06203b33890cc9b832f79ef80560ccb9" + + "a39ce767967ed628c6ad573cb116dbef" + + "efd75499da96bd68a8a97b928a8bbc10" + + "3b6621fcde2beca1231d206be6cd9ec7" + + "aff6f6c94fcd7204ed3455c68c83f4a4" + + "1da4af2b74ef5c53f1d8ac70bdcb7ed1" + + "85ce81bd84359d44254d95629e9855a9" + + "4a7c1958d1f8ada5d0532ed8a5aa3fb2" + + "d17ba70eb6248e594e1a2297acbbb39d" + + "502f1a8c6eb6f1ce22b3de1a1f40cc24" + + "554119a831a9aad6079cad88425de6bd" + + "e1a9187ebb6092cf67bf2b13fd65f270" + + "88d78b7e883c8759d2c4f5c65adb7553" + + "878ad575f9fad878e80a0c9ba63bcbcc" + + "2732e69485bbc9c90bfbd62481d9089b" + + "eccf80cfe2df16a2cf65bd92dd597b07" + + "07e0917af48bbb75fed413d238f5555a" + + "7a569d80c3414a8d0859dc65a46128ba" + + "b27af87a71314f318c782b23ebfe808b" + + "82b0ce26401d2e22f04d83d1255dc51a" + + "ddd3b75a2b1ae0784504df543af8969b" + + "e3ea7082ff7fc9888c144da2af58429e" + + "c96031dbcad3dad9af0dcbaaaf268cb8" + + "fcffead94f3c7ca495e056a9b47acdb7" + + "51fb73e666c6c655ade8297297d07ad1" + + "ba5e43f1bca32301651339e22904cc8c" + + "42f58c30c04aafdb038dda0847dd988d" + + "cda6f3bfd15c4b4c4525004aa06eeff8" + + "ca61783aacec57fb3d1f92b0fe2fd1a8" + + "5f6724517b65e614ad6808d6f6ee34df" + + "f7310fdc82aebfd904b01e1dc54b2927" + + "094b2db68d6f903b68401adebf5a7e08" + + "d78ff4ef5d63653a65040cf9bfd4aca7" + + "984a74d37145986780fc0b16ac451649" + + "de6188a7dbdf191f64b5fc5e2ab47b57" + + "f7f7276cd419c17a3ca8e1b939ae49e4" + + "88acba6b965610b5480109c8b17b80e1" + + "b7b750dfc7598d5d5011fd2dcc5600a3" + + "2ef5b52a1ecc820e308aa342721aac09" + + "43bf6686b64b2579376504ccc493d97e" + + "6aed3fb0f9cd71a43dd497f01f17c0e2" + + "cb3797aa2a2f256656168e6c496afc5f" + + "b93246f6b1116398a346f1a641f3b041" + + "e989f7914f90cc2c7fff357876e506b5" + + "0d334ba77c225bc307ba537152f3f161" + + "0e4eafe595f6d9d90d11faa933a15ef1" + + "369546868a7f3a45a96768d40fd9d034" + + "12c091c6315cf4fde7cb68606937380d" + + "b2eaaa707b4c4185c32eddcdd306705e" + + "4dc1ffc872eeee475a64dfac86aba41c" + + "0618983f8741c5ef68d3a101e8a3b8ca" + + "c60c905c15fc910840b94c00a0b9d0", + "0aab4c900501b3e24d7cdf4663326a3a" + + "87df5e4843b2cbdb67cbf6e460fec350" + + "aa5371b1508f9f4528ecea23c436d94b" + + "5e8fcd4f681e30a6ac00a9704a188a03" + })); + } + + @BeforeClass + public static void checkEDDSASupported() { + Assume.assumeTrue("EDDSA N/A", SecurityUtils.isEDDSACurveSupported()); + } + + @Test + public void testPublicKeyBytes() { + byte[] publicSeed = Ed25519PublicKeyDecoder.getSeedValue((EdDSAPublicKey) publicKey); + assertArrayEquals("Mismatched public seed value", pubBytes, publicSeed); + } + + @Test + public void testPrivateKeyBytes() { + assertArrayEquals("Mismatched private seed value", prvBytes, ((EdDSAPrivateKey) privateKey).getSeed()); + } + + @Test + public void testSignature() throws Exception { + Signature signer = EdDSASecurityProviderUtils.getEDDSASignature(); + signer.initSigner(privateKey); + signer.update(msgBytes.clone()); + + byte[] actSignature = signer.sign(); + assertArrayEquals("Mismatched signature", expSignature, actSignature); + + Signature verifier = EdDSASecurityProviderUtils.getEDDSASignature(); + verifier.initVerifier(publicKey); + verifier.update(msgBytes.clone()); + assertTrue("Verification failed", verifier.verify(expSignature)); + } + + @Test + public void testPartialBufferSignature() throws Exception { + byte[] extraData = getCurrentTestName().getBytes(StandardCharsets.UTF_8); + byte[] dataBuf = new byte[msgBytes.length + extraData.length]; + int offset = extraData.length / 2; + System.arraycopy(extraData, 0, dataBuf, 0, offset); + System.arraycopy(msgBytes, 0, dataBuf, offset, msgBytes.length); + System.arraycopy(extraData, offset, dataBuf, offset + msgBytes.length, extraData.length - offset); + + Signature signer = EdDSASecurityProviderUtils.getEDDSASignature(); + signer.initSigner(privateKey); + signer.update(dataBuf.clone(), offset, msgBytes.length); + + byte[] actSignature = signer.sign(); + assertArrayEquals("Mismatched signature", expSignature, actSignature); + + Signature verifier = EdDSASecurityProviderUtils.getEDDSASignature(); + verifier.initVerifier(publicKey); + verifier.update(dataBuf.clone(), offset, msgBytes.length); + assertTrue("Verification failed", verifier.verify(expSignature)); + } +}
