http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.java deleted file mode 100644 index 967f03b..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractClassLoadableResourceKeyPairProvider.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.StreamCorruptedException; -import java.security.KeyPair; -import java.util.Collection; -import java.util.Collections; - -import org.apache.sshd.common.util.threads.ThreadUtils; - -/** - * This provider loads private keys from the specified resources that - * are accessible via {@link ClassLoader#getResourceAsStream(String)}. - * If no loader configured via {@link #setResourceLoader(ClassLoader)}, then - * {@link ThreadUtils#resolveDefaultClassLoader(Class)} is used - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public abstract class AbstractClassLoadableResourceKeyPairProvider extends AbstractResourceKeyPairProvider<String> { - private ClassLoader classLoader; - private Collection<String> resources; - - protected AbstractClassLoadableResourceKeyPairProvider() { - classLoader = ThreadUtils.resolveDefaultClassLoader(getClass()); - } - - public Collection<String> getResources() { - return resources; - } - - public void setResources(Collection<String> resources) { - this.resources = (resources == null) ? Collections.emptyList() : resources; - } - - public ClassLoader getResourceLoader() { - return classLoader; - } - - public void setResourceLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - @Override - public Iterable<KeyPair> loadKeys() { - return loadKeys(getResources()); - } - - @Override - protected InputStream openKeyPairResource(String resourceKey, String resource) throws IOException { - ClassLoader cl = resolveClassLoader(); - if (cl == null) { - throw new StreamCorruptedException("No resource loader for " + resource); - } - - InputStream input = cl.getResourceAsStream(resource); - if (input == null) { - throw new FileNotFoundException("Cannot find resource " + resource); - } - - return input; - } - - protected ClassLoader resolveClassLoader() { - ClassLoader cl = getResourceLoader(); - if (cl == null) { - cl = ThreadUtils.resolveDefaultClassLoader(getClass()); - } - return cl; - } -} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java deleted file mode 100644 index 8d36508..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractFileKeyPairProvider.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.GeneralSecurityException; -import java.security.KeyPair; -import java.util.Collection; - -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.io.IoUtils; - -/** - * This host key provider loads private keys from the specified files. The - * loading is <U>lazy</U> - i.e., a file is not loaded until it is actually - * required. Once required though, its loaded {@link KeyPair} result is - * <U>cached</U> and not re-loaded. - * - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public abstract class AbstractFileKeyPairProvider extends AbstractResourceKeyPairProvider<Path> { - private Collection<? extends Path> files; - - protected AbstractFileKeyPairProvider() { - super(); - } - - public Collection<? extends Path> getPaths() { - return files; - } - - public void setFiles(Collection<File> files) { - setPaths(GenericUtils.map(files, File::toPath)); - } - - public void setPaths(Collection<? extends Path> paths) { - // use absolute path in order to have unique cache keys - Collection<Path> resolved = GenericUtils.map(paths, Path::toAbsolutePath); - resetCacheMap(resolved); - files = resolved; - } - - @Override - public Iterable<KeyPair> loadKeys() { - return loadKeys(getPaths()); - } - - @Override - protected KeyPair doLoadKey(Path resource) throws IOException, GeneralSecurityException { - return super.doLoadKey((resource == null) ? null : resource.toAbsolutePath()); - } - - @Override - protected InputStream openKeyPairResource(String resourceKey, Path resource) throws IOException { - return Files.newInputStream(resource, IoUtils.EMPTY_OPEN_OPTIONS); - } -} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java index d007c07..ac09bb0 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/AbstractResourceKeyPairProvider.java @@ -37,6 +37,7 @@ import org.apache.sshd.common.config.keys.FilePasswordProvider; import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.security.SecurityUtils; /** * @param <R> Type of resource from which the {@link KeyPair} is generated @@ -170,7 +171,10 @@ public abstract class AbstractResourceKeyPairProvider<R> extends AbstractKeyPair protected abstract InputStream openKeyPairResource(String resourceKey, R resource) throws IOException; - protected abstract KeyPair doLoadKey(String resourceKey, InputStream inputStream, FilePasswordProvider provider) throws IOException, GeneralSecurityException; + protected KeyPair doLoadKey(String resourceKey, InputStream inputStream, FilePasswordProvider provider) + throws IOException, GeneralSecurityException { + return SecurityUtils.loadKeyPairIdentity(resourceKey, inputStream, provider); + } protected class KeyPairIterator implements Iterator<KeyPair> { private final Iterator<? extends R> iterator; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java new file mode 100644 index 0000000..6e8da54 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/ClassLoadableResourceKeyPairProvider.java @@ -0,0 +1,113 @@ +/* + * 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.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.StreamCorruptedException; +import java.security.KeyPair; +import java.util.Collection; +import java.util.Collections; + +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.threads.ThreadUtils; + +/** + * This provider loads private keys from the specified resources that + * are accessible via {@link ClassLoader#getResourceAsStream(String)}. + * If no loader configured via {@link #setResourceLoader(ClassLoader)}, then + * {@link ThreadUtils#resolveDefaultClassLoader(Class)} is used + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class ClassLoadableResourceKeyPairProvider extends AbstractResourceKeyPairProvider<String> { + private ClassLoader classLoader; + private Collection<String> resources; + + public ClassLoadableResourceKeyPairProvider() { + this(Collections.emptyList()); + } + + public ClassLoadableResourceKeyPairProvider(ClassLoader cl) { + this(cl, Collections.emptyList()); + } + + public ClassLoadableResourceKeyPairProvider(String res) { + this(Collections.singletonList(ValidateUtils.checkNotNullAndNotEmpty(res, "No resource specified"))); + } + + public ClassLoadableResourceKeyPairProvider(ClassLoader cl, String res) { + this(cl, Collections.singletonList(ValidateUtils.checkNotNullAndNotEmpty(res, "No resource specified"))); + } + + public ClassLoadableResourceKeyPairProvider(Collection<String> resources) { + this.classLoader = ThreadUtils.resolveDefaultClassLoader(getClass()); + this.resources = (resources == null) ? Collections.emptyList() : resources; + } + + public ClassLoadableResourceKeyPairProvider(ClassLoader cl, Collection<String> resources) { + this.classLoader = cl; + this.resources = (resources == null) ? Collections.emptyList() : resources; + } + + public Collection<String> getResources() { + return resources; + } + + public void setResources(Collection<String> resources) { + this.resources = (resources == null) ? Collections.emptyList() : resources; + } + + public ClassLoader getResourceLoader() { + return classLoader; + } + + public void setResourceLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + @Override + public Iterable<KeyPair> loadKeys() { + return loadKeys(getResources()); + } + + @Override + protected InputStream openKeyPairResource(String resourceKey, String resource) throws IOException { + ClassLoader cl = resolveClassLoader(); + if (cl == null) { + throw new StreamCorruptedException("No resource loader for " + resource); + } + + InputStream input = cl.getResourceAsStream(resource); + if (input == null) { + throw new FileNotFoundException("Cannot find resource " + resource); + } + + return input; + } + + protected ClassLoader resolveClassLoader() { + ClassLoader cl = getResourceLoader(); + if (cl == null) { + cl = ThreadUtils.resolveDefaultClassLoader(getClass()); + } + return cl; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java new file mode 100644 index 0000000..9d3ac50 --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/keyprovider/FileKeyPairProvider.java @@ -0,0 +1,92 @@ +/* + * 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.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; + +import org.apache.sshd.common.util.GenericUtils; +import org.apache.sshd.common.util.io.IoUtils; + +/** + * This host key provider loads private keys from the specified files. The + * loading is <U>lazy</U> - i.e., a file is not loaded until it is actually + * required. Once required though, its loaded {@link KeyPair} result is + * <U>cached</U> and not re-loaded. + * + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class FileKeyPairProvider extends AbstractResourceKeyPairProvider<Path> { + private Collection<? extends Path> files; + + public FileKeyPairProvider() { + super(); + } + + public FileKeyPairProvider(Path path) { + this(Collections.singletonList(Objects.requireNonNull(path, "No path provided"))); + } + + public FileKeyPairProvider(Path ... files) { + this(Arrays.asList(files)); + } + + public FileKeyPairProvider(Collection<? extends Path> files) { + this.files = files; + } + + public Collection<? extends Path> getPaths() { + return files; + } + + public void setFiles(Collection<File> files) { + setPaths(GenericUtils.map(files, File::toPath)); + } + + public void setPaths(Collection<? extends Path> paths) { + // use absolute path in order to have unique cache keys + Collection<Path> resolved = GenericUtils.map(paths, Path::toAbsolutePath); + resetCacheMap(resolved); + files = resolved; + } + + @Override + public Iterable<KeyPair> loadKeys() { + return loadKeys(getPaths()); + } + + @Override + protected KeyPair doLoadKey(Path resource) throws IOException, GeneralSecurityException { + return super.doLoadKey((resource == null) ? null : resource.toAbsolutePath()); + } + + @Override + protected InputStream openKeyPairResource(String resourceKey, Path resource) throws IOException { + return Files.newInputStream(resource, IoUtils.EMPTY_OPEN_OPTIONS); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java index 7fcedff..f55f854 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java @@ -55,8 +55,8 @@ import java.util.logging.Level; import org.apache.sshd.common.PropertyResolver; import org.apache.sshd.common.SshException; import org.apache.sshd.common.cipher.ECCurves; -import org.apache.sshd.common.config.keys.ECDSAPublicKeyEntryDecoder; import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.impl.ECDSAPublicKeyEntryDecoder; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.Int2IntFunction; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java index 65c37ce..58a0759 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/BufferUtils.java @@ -100,6 +100,24 @@ public final class BufferUtils { sb.append(e.getClass().getSimpleName()).append(": ").append(e.getMessage()); } + // Pad the last (incomplete) line to align its data view + for (int index = dumpSize; index < chunkSize; index++) { + if (sep != EMPTY_HEX_SEPARATOR) { + sb.append(' '); + } + sb.append(" "); + } + + sb.append(" "); + for (int pos = curOffset, l = 0; l < dumpSize; pos++, l++) { + int b = data[pos] & 0xFF; + if ((b > ' ') && (b < 0x7E)) { + sb.append((char) b); + } else { + sb.append('.'); + } + } + logger.log(level, sb.toString()); remainLen -= dumpSize; curOffset += dumpSize; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/keys/ECBufferPublicKeyParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/keys/ECBufferPublicKeyParser.java b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/keys/ECBufferPublicKeyParser.java index 84cf4a4..2e6891e 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/keys/ECBufferPublicKeyParser.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/buffer/keys/ECBufferPublicKeyParser.java @@ -28,8 +28,8 @@ import java.security.spec.ECPublicKeySpec; import java.security.spec.InvalidKeySpecException; import org.apache.sshd.common.cipher.ECCurves; -import org.apache.sshd.common.config.keys.ECDSAPublicKeyEntryDecoder; import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.impl.ECDSAPublicKeyEntryDecoder; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.buffer.Buffer; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java index e8b7dd8..fae069d 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/io/IoUtils.java @@ -18,13 +18,17 @@ */ package org.apache.sshd.common.util.io; +import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.EOFException; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.Reader; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.CopyOption; import java.nio.file.FileSystem; @@ -35,11 +39,13 @@ import java.nio.file.Path; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.UserPrincipal; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.List; +import java.util.Objects; import java.util.Set; import org.apache.sshd.common.util.GenericUtils; @@ -468,4 +474,69 @@ public final class IoUtils { return baos.toByteArray(); } } + + /** + * Reads all lines until no more available + * + * @param url The {@link URL} to read from + * @return The {@link List} of lines in the same <U>order</U> as it was read + * @throws IOException If failed to read the lines + * @see #readAllLines(InputStream) + */ + public static List<String> readAllLines(URL url) throws IOException { + try (InputStream stream = Objects.requireNonNull(url, "No URL").openStream()) { + return readAllLines(stream); + } + } + + /** + * Reads all lines until no more available + * + * @param stream The {@link InputStream} - <B>Note:</B> assumed to + * contain {@code UTF-8} encoded data + * @return The {@link List} of lines in the same <U>order</U> as it was read + * @throws IOException If failed to read the lines + * @see #readAllLines(Reader) + */ + public static List<String> readAllLines(InputStream stream) throws IOException { + try (Reader reader = new InputStreamReader(Objects.requireNonNull(stream, "No stream instance"), StandardCharsets.UTF_8)) { + return readAllLines(reader); + } + } + + public static List<String> readAllLines(Reader reader) throws IOException { + try (BufferedReader br = new BufferedReader(Objects.requireNonNull(reader, "No reader instance"), DEFAULT_COPY_SIZE)) { + return readAllLines(br); + } + } + + /** + * Reads all lines until no more available + * + * @param reader The {@link BufferedReader} to read all lines + * @return The {@link List} of lines in the same <U>order</U> as it was read + * @throws IOException If failed to read the lines + * @see #readAllLines(BufferedReader, int) + */ + public static List<String> readAllLines(BufferedReader reader) throws IOException { + return readAllLines(reader, -1); + } + + /** + * Reads all lines until no more available + * + * @param reader The {@link BufferedReader} to read all lines + * @param lineCountHint A hint as to the expected number of lines - non-positive + * means unknown - in which case some initial default value will be used to + * initialize the list used to accumulate the lines. + * @return The {@link List} of lines in the same <U>order</U> as it was read + * @throws IOException If failed to read the lines + */ + public static List<String> readAllLines(BufferedReader reader, int lineCountHint) throws IOException { + List<String> result = new ArrayList<>(Math.max(lineCountHint, Short.SIZE)); + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + result.add(line); + } + return result; + } } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java index 85222ef..b94ee4c 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/SecurityUtils.java @@ -36,6 +36,9 @@ import java.security.Provider; import java.security.PublicKey; import java.security.Signature; import java.security.cert.CertificateFactory; +import java.security.spec.InvalidKeySpecException; +import java.util.Collection; +import java.util.LinkedList; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -43,6 +46,7 @@ import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; import javax.crypto.Cipher; import javax.crypto.KeyAgreement; @@ -51,9 +55,10 @@ import javax.crypto.spec.DHParameterSpec; import org.apache.sshd.common.config.keys.FilePasswordProvider; import org.apache.sshd.common.config.keys.KeyUtils; +import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; -import org.apache.sshd.common.keyprovider.AbstractClassLoadableResourceKeyPairProvider; -import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider; +import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser; +import org.apache.sshd.common.config.keys.loader.openssh.OpenSSHKeyPairResourceParser; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.random.JceRandomFactory; import org.apache.sshd.common.random.RandomFactory; @@ -61,10 +66,8 @@ import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.ReflectionUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.buffer.Buffer; -import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleClassLoadableResourceKeyPairProvider; -import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleFileKeyPairProvider; import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleGeneratorHostKeyProvider; -import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleInputStreamLoader; +import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleKeyPairResourceParser; import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleRandomFactory; import org.apache.sshd.common.util.security.eddsa.EdDSASecurityProvider; import org.apache.sshd.common.util.threads.ThreadUtils; @@ -134,6 +137,7 @@ public final class SecurityUtils { private static final AtomicInteger MAX_DHG_KEY_SIZE_HOLDER = new AtomicInteger(0); private static final Map<String, Provider> REGISTERED_PROVIDERS = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + private static final AtomicReference<KeyPairResourceParser> KEYPAIRS_PARSER_HODLER = new AtomicReference<>(); private static String defaultProvider; private static Boolean registerBouncyCastle; @@ -375,29 +379,25 @@ public final class SecurityUtils { * if the loaded key is <U>guaranteed</U> not to be encrypted * @return The loaded {@link KeyPair} * @throws IOException If failed to read/parse the input stream - * @throws GeneralSecurityException If failed to generate the keys - specifically, - * {@link NoSuchProviderException} is thrown also if {@link #isBouncyCastleRegistered()} - * is {@code false} + * @throws GeneralSecurityException If failed to generate the keys */ public static KeyPair loadKeyPairIdentity(String resourceKey, InputStream inputStream, FilePasswordProvider provider) throws IOException, GeneralSecurityException { - if (!isBouncyCastleRegistered()) { - throw new NoSuchProviderException("BouncyCastle not registered"); + KeyPairResourceParser parser = getKeyPairResourceParser(); + if (parser == null) { + throw new NoSuchProviderException("No registered key-pair resource parser"); } - return BouncyCastleInputStreamLoader.loadKeyPair(resourceKey, inputStream, provider); - } - - /* -------------------------------------------------------------------- */ - - public static AbstractFileKeyPairProvider createFileKeyPairProvider() { - ValidateUtils.checkTrue(isBouncyCastleRegistered(), "BouncyCastle not registered"); - return new BouncyCastleFileKeyPairProvider(); - } + Collection<KeyPair> ids = parser.loadKeyPairs(resourceKey, provider, inputStream); + int numLoaded = GenericUtils.size(ids); + if (numLoaded <= 0) { + throw new InvalidKeyException("Unsupported private key file format: " + resourceKey); + } + if (numLoaded != 1) { + throw new InvalidKeySpecException("Multiple private key pairs N/A: " + resourceKey); + } - public static AbstractClassLoadableResourceKeyPairProvider createClassLoadableResourceKeyPairProvider() { - ValidateUtils.checkTrue(isBouncyCastleRegistered(), "BouncyCastle not registered"); - return new BouncyCastleClassLoadableResourceKeyPairProvider(); + return ids.iterator().next(); } /* -------------------------------------------------------------------- */ @@ -481,6 +481,14 @@ public final class SecurityUtils { return EdDSASecurityProvider.getEDDSAPublicKeyEntryDecoder(); } + public static PrivateKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getOpenSSHEDDSAPrivateKeyEntryDecoder() { + if (!isEDDSACurveSupported()) { + throw new UnsupportedOperationException(EDDSA + " provider N/A"); + } + + return EdDSASecurityProvider.getOpenSSHEDDSAPrivateKeyEntryDecoder(); + } + public static org.apache.sshd.common.signature.Signature getEDDSASigner() { if (isEDDSACurveSupported()) { return EdDSASecurityProvider.getEDDSASignature(); @@ -555,6 +563,33 @@ public final class SecurityUtils { ////////////////////////////////////////////////////////////////////////// + public static KeyPairResourceParser getKeyPairResourceParser() { + KeyPairResourceParser parser; + synchronized (KEYPAIRS_PARSER_HODLER) { + parser = KEYPAIRS_PARSER_HODLER.get(); + if (parser != null) { + return parser; + } + + Collection<KeyPairResourceParser> available = new LinkedList<>(); + available.add(OpenSSHKeyPairResourceParser.INSTANCE); + if (isBouncyCastleRegistered()) { + available.add(BouncyCastleKeyPairResourceParser.INSTANCE); + } + + parser = KeyPairResourceParser.aggregate(available); + KEYPAIRS_PARSER_HODLER.set(parser); + } + + return parser; + } + + public static void setKeyPairResourceParser(KeyPairResourceParser parser) { + synchronized (KEYPAIRS_PARSER_HODLER) { + KEYPAIRS_PARSER_HODLER.set(parser); + } + } + public static synchronized KeyFactory getKeyFactory(String algorithm) throws GeneralSecurityException { register(); http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleClassLoadableResourceKeyPairProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleClassLoadableResourceKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleClassLoadableResourceKeyPairProvider.java deleted file mode 100644 index 7626e13..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleClassLoadableResourceKeyPairProvider.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.bouncycastle; - -import java.io.IOException; -import java.io.InputStream; -import java.security.GeneralSecurityException; -import java.security.KeyPair; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.keyprovider.AbstractClassLoadableResourceKeyPairProvider; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class BouncyCastleClassLoadableResourceKeyPairProvider extends AbstractClassLoadableResourceKeyPairProvider { - public BouncyCastleClassLoadableResourceKeyPairProvider() { - super(); - } - - @Override - protected KeyPair doLoadKey(String resourceKey, InputStream inputStream, FilePasswordProvider provider) - throws IOException, GeneralSecurityException { - return BouncyCastleInputStreamLoader.loadKeyPair(resourceKey, inputStream, provider); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleFileKeyPairProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleFileKeyPairProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleFileKeyPairProvider.java deleted file mode 100644 index a078644..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleFileKeyPairProvider.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.bouncycastle; - -import java.io.IOException; -import java.io.InputStream; -import java.security.GeneralSecurityException; -import java.security.KeyPair; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public class BouncyCastleFileKeyPairProvider extends AbstractFileKeyPairProvider { - public BouncyCastleFileKeyPairProvider() { - super(); - } - - @Override - protected KeyPair doLoadKey(String resourceKey, InputStream inputStream, FilePasswordProvider provider) - throws IOException, GeneralSecurityException { - return BouncyCastleInputStreamLoader.loadKeyPair(resourceKey, inputStream, provider); - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java index 2eb874c..3716719 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java @@ -19,7 +19,6 @@ package org.apache.sshd.common.util.security.bouncycastle; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; @@ -37,11 +36,6 @@ public class BouncyCastleGeneratorHostKeyProvider extends AbstractGeneratorHostK setPath(path); } - @Override - protected KeyPair doReadKeyPair(String resourceKey, InputStream inputStream) throws IOException, GeneralSecurityException { - return BouncyCastleInputStreamLoader.loadKeyPair(resourceKey, inputStream, null); - } - @SuppressWarnings("deprecation") @Override protected void doWriteKeyPair(String resourceKey, KeyPair kp, OutputStream outputStream) throws IOException, GeneralSecurityException { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleInputStreamLoader.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleInputStreamLoader.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleInputStreamLoader.java deleted file mode 100644 index 214802c..0000000 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleInputStreamLoader.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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.bouncycastle; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.security.GeneralSecurityException; -import java.security.KeyPair; - -import org.apache.sshd.common.config.keys.FilePasswordProvider; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.security.SecurityUtils; -import org.bouncycastle.openssl.PEMDecryptorProvider; -import org.bouncycastle.openssl.PEMEncryptedKeyPair; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; - -/** - * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> - */ -public interface BouncyCastleInputStreamLoader { - static KeyPair loadKeyPair(String resourceKey, InputStream inputStream, FilePasswordProvider provider) - throws IOException, GeneralSecurityException { - try (PEMParser r = new PEMParser(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { - Object o = r.readObject(); - - JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter(); - pemConverter.setProvider(SecurityUtils.BOUNCY_CASTLE); - if (o instanceof PEMEncryptedKeyPair) { - ValidateUtils.checkNotNull(provider, "No password provider for resource=%s", resourceKey); - - String password = ValidateUtils.checkNotNullAndNotEmpty(provider.getPassword(resourceKey), "No password provided for resource=%s", resourceKey); - JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder(); - PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(password.toCharArray()); - o = ((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor); - } - - if (o instanceof PEMKeyPair) { - return pemConverter.getKeyPair((PEMKeyPair) o); - } else if (o instanceof KeyPair) { - return (KeyPair) o; - } else { - throw new IOException("Failed to read " + resourceKey + " - unknown result object: " + o); - } - } - } -} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java new file mode 100644 index 0000000..467720f --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleKeyPairResourceParser.java @@ -0,0 +1,119 @@ +/* + * 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.bouncycastle; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import org.apache.sshd.common.config.keys.FilePasswordProvider; +import org.apache.sshd.common.config.keys.loader.AbstractKeyPairResourceParser; +import org.apache.sshd.common.util.ValidateUtils; +import org.apache.sshd.common.util.io.IoUtils; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.bouncycastle.openssl.PEMDecryptorProvider; +import org.bouncycastle.openssl.PEMEncryptedKeyPair; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class BouncyCastleKeyPairResourceParser extends AbstractKeyPairResourceParser { + public static final List<String> BEGINNERS = + Collections.unmodifiableList( + Arrays.asList( + "BEGIN RSA PRIVATE KEY", + "BEGIN DSA PRIVATE KEY", + "BEGIN EC PRIVATE KEY")); + + public static final List<String> ENDERS = + Collections.unmodifiableList( + Arrays.asList( + "END RSA PRIVATE KEY", + "END DSA PRIVATE KEY", + "END EC PRIVATE KEY")); + + public static final BouncyCastleKeyPairResourceParser INSTANCE = new BouncyCastleKeyPairResourceParser(); + + public BouncyCastleKeyPairResourceParser() { + super(BEGINNERS, ENDERS); + } + + @Override + public Collection<KeyPair> extractKeyPairs( + String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, List<String> lines) + throws IOException, GeneralSecurityException { + StringBuilder writer = new StringBuilder(beginMarker.length() + endMarker.length() + lines.size() * 80); + writer.append(beginMarker).append(IoUtils.EOL); + lines.forEach(l -> writer.append(l).append(IoUtils.EOL)); + writer.append(endMarker).append(IoUtils.EOL); + + String data = writer.toString(); + byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8); + try (InputStream bais = new ByteArrayInputStream(dataBytes)) { + return extractKeyPairs(resourceKey, beginMarker, endMarker, passwordProvider, bais); + } + } + + @Override + public Collection<KeyPair> extractKeyPairs( + String resourceKey, String beginMarker, String endMarker, FilePasswordProvider passwordProvider, InputStream stream) + throws IOException, GeneralSecurityException { + KeyPair kp = loadKeyPair(resourceKey, stream, passwordProvider); + return (kp == null) ? Collections.emptyList() : Collections.singletonList(kp); + } + + public static KeyPair loadKeyPair(String resourceKey, InputStream inputStream, FilePasswordProvider provider) + throws IOException, GeneralSecurityException { + try (PEMParser r = new PEMParser(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + Object o = r.readObject(); + + JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter(); + pemConverter.setProvider(SecurityUtils.BOUNCY_CASTLE); + if (o instanceof PEMEncryptedKeyPair) { + ValidateUtils.checkNotNull(provider, "No password provider for resource=%s", resourceKey); + + String password = ValidateUtils.checkNotNullAndNotEmpty(provider.getPassword(resourceKey), "No password provided for resource=%s", resourceKey); + JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder(); + PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(password.toCharArray()); + o = ((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor); + } + + if (o instanceof PEMKeyPair) { + return pemConverter.getKeyPair((PEMKeyPair) o); + } else if (o instanceof KeyPair) { + return (KeyPair) o; + } else { + throw new IOException("Failed to read " + resourceKey + " - unknown result object: " + o); + } + } + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java index a482bbe..c896e0e 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/Ed25519PublicKeyDecoder.java @@ -32,8 +32,8 @@ import net.i2p.crypto.eddsa.EdDSAPublicKey; import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; -import org.apache.sshd.common.config.keys.AbstractPublicKeyEntryDecoder; -import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; +import org.apache.sshd.common.config.keys.KeyEntryResolver; +import org.apache.sshd.common.config.keys.impl.AbstractPublicKeyEntryDecoder; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.util.security.SecurityUtils; @@ -73,9 +73,9 @@ public final class Ed25519PublicKeyDecoder extends AbstractPublicKeyEntryDecoder @Override public String encodePublicKey(OutputStream s, EdDSAPublicKey key) throws IOException { Objects.requireNonNull(key, "No public key provided"); - PublicKeyEntryDecoder.encodeString(s, KeyPairProvider.SSH_ED25519); + KeyEntryResolver.encodeString(s, KeyPairProvider.SSH_ED25519); byte[] seed = getSeedValue(key); - PublicKeyEntryDecoder.writeRLEBytes(s, seed); + KeyEntryResolver.writeRLEBytes(s, seed); return KeyPairProvider.SSH_ED25519; } @@ -86,7 +86,7 @@ public final class Ed25519PublicKeyDecoder extends AbstractPublicKeyEntryDecoder @Override public EdDSAPublicKey decodePublicKey(String keyType, InputStream keyData) throws IOException, GeneralSecurityException { - byte[] seed = PublicKeyEntryDecoder.readRLEBytes(keyData); + byte[] seed = KeyEntryResolver.readRLEBytes(keyData); return EdDSAPublicKey.class.cast(SecurityUtils.generateEDDSAPublicKey(keyType, seed)); } @@ -94,14 +94,4 @@ public final class Ed25519PublicKeyDecoder extends AbstractPublicKeyEntryDecoder // a bit of reverse-engineering on the EdDSAPublicKeySpec return (key == null) ? null : key.getAbyte(); } - - public static EdDSAPublicKey fromPrivateKey(EdDSAPrivateKey prvKey) throws GeneralSecurityException { - if (prvKey == null) { - return null; - } - - EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getSeed(), prvKey.getParams()); - KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); - return EdDSAPublicKey.class.cast(factory.generatePublic(keySpec)); - } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProvider.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProvider.java index daaac49..ba73878 100644 --- a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProvider.java +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/EdDSASecurityProvider.java @@ -35,6 +35,7 @@ import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; +import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder; import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.util.ValidateUtils; @@ -111,6 +112,11 @@ public class EdDSASecurityProvider extends Provider { return Ed25519PublicKeyDecoder.INSTANCE; } + public static PrivateKeyEntryDecoder<? extends PublicKey, ? extends PrivateKey> getOpenSSHEDDSAPrivateKeyEntryDecoder() { + ValidateUtils.checkTrue(SecurityUtils.isEDDSACurveSupported(), SecurityUtils.EDDSA + " not supported"); + return OpenSSHEd25519PrivateKeyEntryDecoder.INSTANCE; + } + public static boolean compareEDDSAPrivateKeys(PrivateKey k1, PrivateKey k2) { if (!SecurityUtils.isEDDSACurveSupported()) { return false; http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java new file mode 100644 index 0000000..3046eed --- /dev/null +++ b/sshd-core/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.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.util.security.eddsa; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.Collections; +import java.util.Objects; + +import net.i2p.crypto.eddsa.EdDSAPrivateKey; +import net.i2p.crypto.eddsa.EdDSAPublicKey; +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; +import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec; +import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; +import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; + +import org.apache.sshd.common.config.keys.FilePasswordProvider; +import org.apache.sshd.common.config.keys.KeyEntryResolver; +import org.apache.sshd.common.config.keys.impl.AbstractPrivateKeyEntryDecoder; +import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.util.security.SecurityUtils; + +/** + * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> + */ +public class OpenSSHEd25519PrivateKeyEntryDecoder extends AbstractPrivateKeyEntryDecoder<EdDSAPublicKey, EdDSAPrivateKey> { + public static final OpenSSHEd25519PrivateKeyEntryDecoder INSTANCE = new OpenSSHEd25519PrivateKeyEntryDecoder(); + + public OpenSSHEd25519PrivateKeyEntryDecoder() { + super(EdDSAPublicKey.class, EdDSAPrivateKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_ED25519))); + } + + @Override + public EdDSAPrivateKey decodePrivateKey(String keyType, FilePasswordProvider passwordProvider, InputStream keyData) + throws IOException, GeneralSecurityException { + if (!KeyPairProvider.SSH_ED25519.equals(keyType)) { + throw new InvalidKeyException("Unsupported key type: " + keyType); + } + + if (!SecurityUtils.isEDDSACurveSupported()) { + throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " provider not supported"); + } + + byte[] seed = KeyEntryResolver.readRLEBytes(keyData); // a.k.a pk in OpenSSH C code + byte[] signature = KeyEntryResolver.readRLEBytes(keyData); // a.k.a sk in OpenSSH C code + if (signature.length != seed.length * 2) { + throw new InvalidKeyException("Mismatched signature (" + signature.length + ") vs. seed (" + seed.length + ") length"); + } + + EdDSAParameterSpec params = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.CURVE_ED25519_SHA512); + EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(seed, params); + return generatePrivateKey(keySpec); + } + + @Override + public String encodePrivateKey(OutputStream s, EdDSAPrivateKey key) throws IOException { + Objects.requireNonNull(key, "No private key provided"); + + // how + byte[] seed = key.getSeed(); + Objects.requireNonNull(seed, "No ssed"); + /* TODO see https://svn.nmap.org/ncrack/opensshlib/ed25519.c + byte[] signature = signEd25519KeyPair(seed); + KeyEntryResolver.writeRLEBytes(s, seed); + KeyEntryResolver.writeRLEBytes(s, signature); + return KeyPairProvider.SSH_ED25519; + */ + return null; + } + + @Override + public boolean isPublicKeyRecoverySupported() { + return true; + } + + @Override + public EdDSAPublicKey recoverPublicKey(EdDSAPrivateKey prvKey) throws GeneralSecurityException { + if (!SecurityUtils.isEDDSACurveSupported()) { + throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " provider not supported"); + } + + EdDSAPublicKeySpec keySpec = new EdDSAPublicKeySpec(prvKey.getSeed(), prvKey.getParams()); + KeyFactory factory = SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); + return EdDSAPublicKey.class.cast(factory.generatePublic(keySpec)); + } + + @Override + public EdDSAPublicKey clonePublicKey(EdDSAPublicKey key) throws GeneralSecurityException { + if (key == null) { + return null; + } else { + return generatePublicKey(new EdDSAPublicKeySpec(key.getA(), key.getParams())); + } + } + + @Override + public EdDSAPrivateKey clonePrivateKey(EdDSAPrivateKey key) throws GeneralSecurityException { + if (key == null) { + return null; + } else { + return generatePrivateKey(new EdDSAPrivateKeySpec(key.getSeed(), key.getParams())); + } + } + + @Override + public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException { + return SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA); + } + + @Override + public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException { + return SecurityUtils.getKeyFactory(SecurityUtils.EDDSA); + } +} http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java index 8799a8a..e382942 100644 --- a/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java +++ b/sshd-core/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java @@ -250,7 +250,9 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr } } - protected abstract KeyPair doReadKeyPair(String resourceKey, InputStream inputStream) throws IOException, GeneralSecurityException; + protected KeyPair doReadKeyPair(String resourceKey, InputStream inputStream) throws IOException, GeneralSecurityException { + return SecurityUtils.loadKeyPairIdentity(resourceKey, inputStream, null); + } protected void writeKeyPair(KeyPair kp, Path keyPath, OpenOption... options) throws IOException, GeneralSecurityException { if ((!Files.exists(keyPath)) || isOverwriteAllowed()) { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java new file mode 100644 index 0000000..9c54638 --- /dev/null +++ b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java @@ -0,0 +1,102 @@ +/* + * 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.BaseTestSupport; +import org.junit.Assume; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** + * @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 +public class OpenSSHKeyPairResourceParserTest extends BaseTestSupport { + 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/0d7af8c8/sshd-core/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java b/sshd-core/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java index 254bc8e..af471e4 100644 --- a/sshd-core/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/common/random/RandomFactoryTest.java @@ -33,8 +33,6 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; /** - * TODO Add javadoc - * * @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a> */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java index d85b7f9..deb29ec 100644 --- a/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/common/signature/SignatureFactoriesTest.java @@ -31,12 +31,13 @@ import org.apache.sshd.client.SshClient; import org.apache.sshd.client.session.ClientSession; import org.apache.sshd.common.Factory; import org.apache.sshd.common.NamedFactory; +import org.apache.sshd.common.OptionalFeature; import org.apache.sshd.common.RuntimeSshException; import org.apache.sshd.common.cipher.ECCurves; -import org.apache.sshd.common.config.keys.DSSPublicKeyEntryDecoder; -import org.apache.sshd.common.config.keys.ECDSAPublicKeyEntryDecoder; import org.apache.sshd.common.config.keys.PublicKeyEntryDecoder; -import org.apache.sshd.common.config.keys.RSAPublicKeyDecoder; +import org.apache.sshd.common.config.keys.impl.DSSPublicKeyEntryDecoder; +import org.apache.sshd.common.config.keys.impl.ECDSAPublicKeyEntryDecoder; +import org.apache.sshd.common.config.keys.impl.RSAPublicKeyDecoder; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.security.SecurityUtils; @@ -44,6 +45,7 @@ import org.apache.sshd.server.SshServer; import org.apache.sshd.util.test.BaseTestSupport; import org.apache.sshd.util.test.Utils; import org.junit.AfterClass; +import org.junit.Assume; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; @@ -57,22 +59,32 @@ import org.junit.runners.Parameterized.Parameters; */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) @RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests -public class SignatureFactoriesTest extends BaseTestSupport { +public class SignatureFactoriesTest extends BaseTestSupport implements OptionalFeature { private static SshServer sshd; private static SshClient client; private static int port; private final String keyType; private final int keySize; + private final boolean supported; private final NamedFactory<Signature> factory; private final PublicKeyEntryDecoder<?, ?> pubKeyDecoder; - public SignatureFactoriesTest(String keyType, NamedFactory<Signature> factory, int keySize, PublicKeyEntryDecoder<?, ?> decoder) { + public SignatureFactoriesTest( + String keyType, NamedFactory<Signature> factory, int keySize, boolean supported, PublicKeyEntryDecoder<?, ?> decoder) { this.keyType = ValidateUtils.checkNotNullAndNotEmpty(keyType, "No key type specified"); - this.factory = Objects.requireNonNull(factory, "No signature factory provided"); - ValidateUtils.checkTrue(keySize > 0, "Invalid key size: %d", keySize); + this.factory = supported ? Objects.requireNonNull(factory, "No signature factory provided") : factory; + if (supported) { + ValidateUtils.checkTrue(keySize > 0, "Invalid key size: %d", keySize); + } this.keySize = keySize; - this.pubKeyDecoder = Objects.requireNonNull(decoder, "No public key decoder provided"); + this.supported = supported; + this.pubKeyDecoder = supported ? Objects.requireNonNull(decoder, "No public key decoder provided") : null; + } + + @Override + public boolean isSupported() { + return supported; } @Parameters(name = "type={0}, size={2}") @@ -80,24 +92,28 @@ public class SignatureFactoriesTest extends BaseTestSupport { List<Object[]> list = new ArrayList<>(); addTests(list, KeyPairProvider.SSH_DSS, BuiltinSignatures.dsa, DSS_SIZES, DSSPublicKeyEntryDecoder.INSTANCE); addTests(list, KeyPairProvider.SSH_RSA, BuiltinSignatures.rsa, RSA_SIZES, RSAPublicKeyDecoder.INSTANCE); + if (SecurityUtils.hasEcc()) { for (ECCurves curve : ECCurves.VALUES) { - if (!curve.isSupported()) { - continue; - } BuiltinSignatures factory = BuiltinSignatures.fromFactoryName(curve.getKeyType()); - addTests(list, curve.getName(), factory, Collections.singletonList(curve.getKeySize()), ECDSAPublicKeyEntryDecoder.INSTANCE); + addTests(list, curve.getName(), factory, + curve.isSupported() ? Collections.singletonList(curve.getKeySize()) : Collections.singletonList(-1), + curve.isSupported() ? ECDSAPublicKeyEntryDecoder.INSTANCE : null); + } + } else { + for (String name : ECCurves.NAMES) { + addTests(list, name, null, Collections.singletonList(-1), null); } } - if (SecurityUtils.isEDDSACurveSupported()) { - addTests(list, KeyPairProvider.SSH_ED25519, BuiltinSignatures.ed25519, ED25519_SIZES, SecurityUtils.getEDDSAPublicKeyEntryDecoder()); - } + addTests(list, KeyPairProvider.SSH_ED25519, BuiltinSignatures.ed25519, ED25519_SIZES, + SecurityUtils.isEDDSACurveSupported() ? SecurityUtils.getEDDSAPublicKeyEntryDecoder() : null); return Collections.unmodifiableList(list); } - private static void addTests(List<Object[]> list, String keyType, NamedFactory<Signature> factory, Collection<Integer> sizes, PublicKeyEntryDecoder<?, ?> decoder) { + private static void addTests( + List<Object[]> list, String keyType, NamedFactory<Signature> factory, Collection<Integer> sizes, PublicKeyEntryDecoder<?, ?> decoder) { for (Integer keySize : sizes) { - list.add(new Object[]{keyType, factory, keySize, decoder}); + list.add(new Object[]{keyType, factory, keySize, decoder != null, decoder}); } } @@ -140,6 +156,7 @@ public class SignatureFactoriesTest extends BaseTestSupport { @Test public void testPublicKeyAuth() throws Exception { + Assume.assumeTrue(isSupported()); testKeyPairProvider(getKeyType(), getKeySize(), pubKeyDecoder, Collections.singletonList(factory)); } http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java index 3fbfc3d..2e44d83 100644 --- a/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java +++ b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java @@ -33,16 +33,15 @@ import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; -import java.util.Collections; 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.keyprovider.AbstractClassLoadableResourceKeyPairProvider; -import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider; 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.security.SecurityUtils; import org.apache.sshd.util.test.BaseTestSupport; import org.junit.Assume; @@ -137,15 +136,11 @@ public class SecurityUtilsTest extends BaseTestSupport { } private static KeyPair testLoadPrivateKeyResource(String name, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) { - AbstractClassLoadableResourceKeyPairProvider provider = SecurityUtils.createClassLoadableResourceKeyPairProvider(); - provider.setResources(Collections.singletonList(name)); - return testLoadPrivateKey(name, provider, pubType, prvType); + return testLoadPrivateKey(name, new ClassLoadableResourceKeyPairProvider(name), pubType, prvType); } private static KeyPair testLoadPrivateKeyFile(Path file, Class<? extends PublicKey> pubType, Class<? extends PrivateKey> prvType) { - AbstractFileKeyPairProvider provider = SecurityUtils.createFileKeyPairProvider(); - provider.setPaths(Collections.singletonList(file)); - return testLoadPrivateKey(file.toString(), provider, pubType, prvType); + return testLoadPrivateKey(file.toString(), new FileKeyPairProvider(file), pubType, prvType); } private static KeyPair testLoadPrivateKey(String resourceKey, AbstractResourceKeyPairProvider<?> provider, http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java b/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java index d5439fe..73e8f7c 100644 --- a/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java +++ b/sshd-core/src/test/java/org/apache/sshd/util/test/Utils.java @@ -55,7 +55,7 @@ import org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier; import org.apache.sshd.common.Factory; import org.apache.sshd.common.cipher.ECCurves; import org.apache.sshd.common.config.keys.KeyUtils; -import org.apache.sshd.common.keyprovider.AbstractFileKeyPairProvider; +import org.apache.sshd.common.keyprovider.FileKeyPairProvider; import org.apache.sshd.common.keyprovider.KeyIdentityProvider; import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.keyprovider.KeyPairProviderHolder; @@ -112,7 +112,7 @@ public final class Utils { // uses a cached instance to avoid re-creating the keys as it is a time-consuming effort private static final AtomicReference<KeyPairProvider> KEYPAIR_PROVIDER_HOLDER = new AtomicReference<>(); // uses a cached instance to avoid re-creating the keys as it is a time-consuming effort - private static final Map<String, AbstractFileKeyPairProvider> PROVIDERS_MAP = new ConcurrentHashMap<>(); + private static final Map<String, FileKeyPairProvider> PROVIDERS_MAP = new ConcurrentHashMap<>(); private Utils() { throw new UnsupportedOperationException("No instance"); @@ -174,19 +174,19 @@ public final class Utils { return gen.generateKeyPair(); } - public static AbstractFileKeyPairProvider createTestKeyPairProvider(String resource) { + public static FileKeyPairProvider createTestKeyPairProvider(String resource) { File file = getFile(resource); String filePath = file.getAbsolutePath(); - AbstractFileKeyPairProvider provider = PROVIDERS_MAP.get(filePath); + FileKeyPairProvider provider = PROVIDERS_MAP.get(filePath); if (provider != null) { return provider; } - provider = SecurityUtils.createFileKeyPairProvider(); + provider = new FileKeyPairProvider(); provider.setFiles(Collections.singletonList(file)); provider = validateKeyPairProvider(provider); - AbstractFileKeyPairProvider prev = PROVIDERS_MAP.put(filePath, provider); + FileKeyPairProvider prev = PROVIDERS_MAP.put(filePath, provider); if (prev != null) { // check if somebody else beat us to it return prev; } else { http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair new file mode 100644 index 0000000..217d508 --- /dev/null +++ b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair @@ -0,0 +1,21 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH +NzAAAAgQD3axy1MBdh4TJC+T22DKKDe7sXnDrgJRs1jBcDl/qPdQDoLlvvTd8oHggXkIzI +6Tx2ldiJ3KADMkDg1sBSU5zenIr9wisfEQOLNqfIOOirR9Z8jULGVlDO+pPwps0P9bcOka +JCAfABNth6Oaz3NJjfFD8ZmmWDVaN2rSi1J3mjnwAAABUA5be00MaSti06Hor265V8Ggtj +i/0AAACAa9MU8kBJ4Z1+UsrWruVr72eckEwjOPcRFeA6MoSM70GGdYVkLyQ78MMjKAFZcb +seYT3lsja+c4LQ7yErROHSGFo+ImQnYGY3Cos2mS8tRBHtZ4YmKsBmS3Zrb4lEfauA1pgD +pcGrUAavniKIAB/C9cpvj+IpZ36+rHpap4JKJ7kAAACAQP4NRzjtauzrDJvs73c0DPczAk +LAan+90ouvIuI0CmMxFrSqLIIEaX3cB/P4dkKtBsMh0CxwJpoXfn+TO+1j7i08GuMONeqB +3lOHn1/MB2qUAZh/kdU8RUsxWkrG80JMeP1kew1sHaoRfOUZ8+Xw/RL7nNmhhmHJR3rkgR +8EoWEAAAHoMgIkejICJHoAAAAHc3NoLWRzcwAAAIEA92sctTAXYeEyQvk9tgyig3u7F5w6 +4CUbNYwXA5f6j3UA6C5b703fKB4IF5CMyOk8dpXYidygAzJA4NbAUlOc3pyK/cIrHxEDiz +anyDjoq0fWfI1CxlZQzvqT8KbND/W3DpGiQgHwATbYejms9zSY3xQ/GZplg1Wjdq0otSd5 +o58AAAAVAOW3tNDGkrYtOh6K9uuVfBoLY4v9AAAAgGvTFPJASeGdflLK1q7la+9nnJBMIz +j3ERXgOjKEjO9BhnWFZC8kO/DDIygBWXG7HmE95bI2vnOC0O8hK0Th0hhaPiJkJ2BmNwqL +NpkvLUQR7WeGJirAZkt2a2+JRH2rgNaYA6XBq1AGr54iiAAfwvXKb4/iKWd+vqx6WqeCSi +e5AAAAgED+DUc47Wrs6wyb7O93NAz3MwJCwGp/vdKLryLiNApjMRa0qiyCBGl93Afz+HZC +rQbDIdAscCaaF35/kzvtY+4tPBrjDjXqgd5Th59fzAdqlAGYf5HVPEVLMVpKxvNCTHj9ZH +sNbB2qEXzlGfPl8P0S+5zZoYZhyUd65IEfBKFhAAAAFGL9BNpShiQnNZ1noW8Woxyq1GuH +AAAADnJvb3RAdWJ1bnR1LTE1AQIDBAU= +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair.pub ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair.pub new file mode 100644 index 0000000..c3feece --- /dev/null +++ b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-DSA-KeyPair.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAPdrHLUwF2HhMkL5PbYMooN7uxecOuAlGzWMFwOX+o91AOguW+9N3ygeCBeQjMjpPHaV2IncoAMyQODWwFJTnN6civ3CKx8RA4s2p8g46KtH1nyNQsZWUM76k/CmzQ/1tw6RokIB8AE22Ho5rPc0mN8UPxmaZYNVo3atKLUneaOfAAAAFQDlt7TQxpK2LToeivbrlXwaC2OL/QAAAIBr0xTyQEnhnX5Sytau5WvvZ5yQTCM49xEV4DoyhIzvQYZ1hWQvJDvwwyMoAVlxux5hPeWyNr5zgtDvIStE4dIYWj4iZCdgZjcKizaZLy1EEe1nhiYqwGZLdmtviUR9q4DWmAOlwatQBq+eIogAH8L1ym+P4ilnfr6selqngkonuQAAAIBA/g1HOO1q7OsMm+zvdzQM9zMCQsBqf73Si68i4jQKYzEWtKosggRpfdwH8/h2Qq0GwyHQLHAmmhd+f5M77WPuLTwa4w416oHeU4efX8wHapQBmH+R1TxFSzFaSsbzQkx4/WR7DWwdqhF85Rnz5fD9Evuc2aGGYclHeuSBHwShYQ== root@ubuntu-15 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair new file mode 100644 index 0000000..403ff40 --- /dev/null +++ b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair @@ -0,0 +1,12 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS +1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAGRPv5eCmd3jFTCWrioWVHgQhHn/d +ir8nriiEonZDPP+hEjX1AiYyahfvFWoqKI4lKRzoEmF5Wk6ct+9LM0JFGcEAck7Z3J/NXt +CnHeEvnusHMoANjhKLExBURROOOTGziyHMuGBMBIgRFnf4rBhiTzduexJnaMglyqxIrDpG +hOxwhQAAAAEQxPcsaMT3LGgAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ +AAAIUEABkT7+Xgpnd4xUwlq4qFlR4EIR5/3Yq/J64ohKJ2Qzz/oRI19QImMmoX7xVqKiiO +JSkc6BJheVpOnLfvSzNCRRnBAHJO2dyfzV7Qpx3hL57rBzKADY4SixMQVEUTjjkxs4shzL +hgTASIERZ3+KwYYk83bnsSZ2jIJcqsSKw6RoTscIUAAAAAQQ+HCwVtvFlnRydGXZ+xpyKM +KxDp5h7YMg5/dpRFrp3qNonm5/RHoT2Hw9i5GZtrXT2xPiR69wLOzTb4pnIWlENfAAAADn +Jvb3RAdWJ1bnR1LTE1AQIDBAU= +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair.pub ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair.pub new file mode 100644 index 0000000..bd43737 --- /dev/null +++ b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ECDSA-KeyPair.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAZE+/l4KZ3eMVMJauKhZUeBCEef92KvyeuKISidkM8/6ESNfUCJjJqF+8VaioojiUpHOgSYXlaTpy370szQkUZwQByTtncn81e0Kcd4S+e6wcygA2OEosTEFRFE445MbOLIcy4YEwEiBEWd/isGGJPN257EmdoyCXKrEisOkaE7HCFAA== root@ubuntu-15 http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair new file mode 100644 index 0000000..3176f3b --- /dev/null +++ b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACB0Tsaj0scs8fYKMlnz2Mncky545NoICP9eGMGIpo5G3QAAAJjCVtyJwlbc +iQAAAAtzc2gtZWQyNTUxOQAAACB0Tsaj0scs8fYKMlnz2Mncky545NoICP9eGMGIpo5G3Q +AAAEDjQpuV2OWHZVy7R09w6bw2DnBa1UdZrsAmQ7dPyxasx3ROxqPSxyzx9goyWfPYydyT +Lnjk2ggI/14YwYimjkbdAAAADnJvb3RAdWJ1bnR1LTE1AQIDBAUGBw== +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/0d7af8c8/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair.pub ---------------------------------------------------------------------- diff --git a/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair.pub b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair.pub new file mode 100644 index 0000000..128e883 --- /dev/null +++ b/sshd-core/src/test/resources/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest-ED25519-KeyPair.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHROxqPSxyzx9goyWfPYydyTLnjk2ggI/14YwYimjkbd root@ubuntu-15 \ No newline at end of file
