You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/06/09 15:53:21 UTC
[6/6] mina-sshd git commit: [SSHD-488] Implement (a naive) ssh-keyscan
[SSHD-488] Implement (a naive) ssh-keyscan
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/6432a7af
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/6432a7af
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/6432a7af
Branch: refs/heads/master
Commit: 6432a7af36c3053af17cdd51a6dda4ff14af318d
Parents: ff6a4b0
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Tue Jun 9 16:53:02 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Tue Jun 9 16:53:02 2015 +0300
----------------------------------------------------------------------
.../sshd/agent/common/AbstractAgentClient.java | 2 +-
.../sshd/agent/common/AbstractAgentProxy.java | 2 +-
.../sshd/agent/local/AgentServerProxy.java | 2 +-
.../org/apache/sshd/agent/unix/AgentServer.java | 2 +-
.../sshd/agent/unix/AgentServerProxy.java | 2 +-
.../org/apache/sshd/client/ClientBuilder.java | 2 +-
.../java/org/apache/sshd/client/SshKeyScan.java | 508 ++++++++++
.../auth/UserAuthKeyboardInteractive.java | 2 +-
.../sshd/client/auth/UserAuthPassword.java | 2 +-
.../sshd/client/auth/UserAuthPublicKey.java | 2 +-
.../client/channel/AbstractClientChannel.java | 2 +-
.../DelegatingServerKeyVerifier.java | 2 +-
.../keyverifier/RequiredServerKeyVerifier.java | 2 +-
.../keyverifier/StaticServerKeyVerifier.java | 2 +-
.../sshd/client/scp/AbstractScpClient.java | 4 +-
.../sshd/client/session/ClientSession.java | 23 +
.../sshd/client/session/ClientSessionImpl.java | 99 +-
.../client/session/ClientUserAuthService.java | 2 +-
.../sshd/client/sftp/AbstractSftpClient.java | 2 +-
.../client/sftp/SftpFileSystemProvider.java | 2 +-
.../org/apache/sshd/common/NamedFactory.java | 1 +
.../org/apache/sshd/common/NamedResource.java | 1 +
.../org/apache/sshd/common/SshConstants.java | 29 +-
.../org/apache/sshd/common/Transformer.java | 58 --
.../org/apache/sshd/common/channel/Window.java | 2 +-
.../sshd/common/cipher/CipherFactory.java | 2 +-
.../org/apache/sshd/common/cipher/ECCurves.java | 83 +-
.../common/compression/CompressionFactory.java | 2 +-
.../sshd/common/config/SshConfigFileReader.java | 2 +-
.../keys/AbstractPublicKeyEntryDecoder.java | 90 +-
.../config/keys/DSSPublicKeyEntryDecoder.java | 41 +-
.../config/keys/ECDSAPublicKeyEntryDecoder.java | 75 +-
.../sshd/common/config/keys/KeyUtils.java | 194 +++-
.../sshd/common/config/keys/PublicKeyEntry.java | 4 +-
.../config/keys/PublicKeyEntryDecoder.java | 67 +-
.../common/config/keys/RSAPublicKeyDecoder.java | 46 +-
.../file/nativefs/NativeFileSystemFactory.java | 2 +-
.../file/root/RootedFileSystemProvider.java | 2 +-
.../sshd/common/future/DefaultSshFuture.java | 2 +-
.../io/AbstractIoServiceFactoryFactory.java | 2 +-
.../common/kex/dh/AbstractDHKeyExchange.java | 2 +-
.../keyprovider/AbstractKeyPairProvider.java | 2 +-
.../keyprovider/MappedKeyPairProvider.java | 2 +-
.../org/apache/sshd/common/mac/MacFactory.java | 2 +-
.../scp/LocalFileScpSourceStreamResolver.java | 4 +-
.../scp/LocalFileScpTargetStreamResolver.java | 4 +-
.../org/apache/sshd/common/scp/ScpHelper.java | 4 +-
.../sshd/common/session/AbstractSession.java | 6 +-
.../common/session/SessionTimeoutListener.java | 2 +-
.../sshd/common/signature/SignatureFactory.java | 2 +-
.../sshd/common/util/AbstractLoggingBean.java | 49 -
.../apache/sshd/common/util/CloseableUtils.java | 11 +-
.../sshd/common/util/EventListenerUtils.java | 6 +-
.../apache/sshd/common/util/GenericUtils.java | 29 +-
.../org/apache/sshd/common/util/IoUtils.java | 291 ------
.../org/apache/sshd/common/util/OsUtils.java | 2 +-
.../apache/sshd/common/util/SecurityUtils.java | 5 +-
.../apache/sshd/common/util/Transformer.java | 58 ++
.../apache/sshd/common/util/ValidateUtils.java | 6 +-
.../apache/sshd/common/util/buffer/Buffer.java | 61 +-
.../util/io/CloseableEmptyInputStream.java | 94 ++
.../sshd/common/util/io/EmptyInputStream.java | 65 ++
.../org/apache/sshd/common/util/io/IoUtils.java | 293 ++++++
.../common/util/io/ModifiableFileWatcher.java | 3 +-
.../util/logging/AbstractLoggingBean.java | 49 +
.../util/logging/AbstractSimplifiedLog.java | 36 +
.../sshd/common/util/logging/LoggingUtils.java | 144 +++
.../sshd/common/util/logging/SimplifiedLog.java | 53 +
.../sshd/server/PasswordAuthenticator.java | 2 +-
.../sshd/server/PublickeyAuthenticator.java | 2 +-
.../org/apache/sshd/server/ServerBuilder.java | 2 +-
.../sshd/server/auth/AbstractUserAuth.java | 2 +-
.../sshd/server/channel/ChannelSession.java | 2 +-
.../sshd/server/channel/PipeDataReceiver.java | 2 +-
.../server/channel/PuttyRequestHandler.java | 2 +-
.../apache/sshd/server/command/ScpCommand.java | 2 +-
.../server/config/keys/AuthorizedKeyEntry.java | 2 +-
.../keys/AuthorizedKeysAuthenticator.java | 2 +-
.../DefaultAuthorizedKeysAuthenticator.java | 2 +-
.../sshd/server/forward/ForwardingFilter.java | 2 +-
.../global/CancelTcpipForwardHandler.java | 2 +-
.../sshd/server/global/TcpipForwardHandler.java | 2 +-
.../server/jaas/JaasPasswordAuthenticator.java | 2 +-
.../apache/sshd/server/sftp/SftpSubsystem.java | 4 +-
.../sshd/server/shell/ProcessShellFactory.java | 2 +-
.../org/apache/sshd/AbstractSessionTest.java | 147 ---
.../test/java/org/apache/sshd/AgentTest.java | 212 ----
.../test/java/org/apache/sshd/CipherTest.java | 181 ----
.../test/java/org/apache/sshd/ClientTest.java | 958 -------------------
.../src/test/java/org/apache/sshd/MacTest.java | 188 ----
.../test/java/org/apache/sshd/RandomTest.java | 58 --
.../test/java/org/apache/sshd/ServerMain.java | 34 -
.../test/java/org/apache/sshd/ServerTest.java | 561 -----------
.../java/org/apache/sshd/SshBuilderTest.java | 136 ---
.../java/org/apache/sshd/SshServerMain.java | 35 -
.../java/org/apache/sshd/SshServerTest.java | 99 --
.../java/org/apache/sshd/agent/AgentTest.java | 212 ++++
.../java/org/apache/sshd/client/ClientTest.java | 958 +++++++++++++++++++
.../client/session/ClientSessionImplTest.java | 103 ++
.../sshd/client/sftp/SftpFileSystemTest.java | 2 +-
.../org/apache/sshd/client/sftp/SftpTest.java | 2 +-
.../org/apache/sshd/common/SshBuilderTest.java | 136 +++
.../apache/sshd/common/cipher/CipherTest.java | 181 ++++
.../common/config/SshConfigFileReaderTest.java | 2 +-
.../sshd/common/config/keys/KeyUtilsTest.java | 138 +++
.../org/apache/sshd/common/mac/MacTest.java | 188 ++++
.../apache/sshd/common/random/RandomTest.java | 58 ++
.../common/session/AbstractSessionTest.java | 147 +++
.../sshd/common/util/GenericUtilsTest.java | 27 +
.../common/util/io/EmptyInputStreamTest.java | 117 +++
.../sshd/deprecated/AbstractUserAuth.java | 2 +-
.../java/org/apache/sshd/server/ServerMain.java | 34 +
.../java/org/apache/sshd/server/ServerTest.java | 561 +++++++++++
.../org/apache/sshd/server/SshServerMain.java | 35 +
.../org/apache/sshd/server/SshServerTest.java | 99 ++
.../config/keys/AuthorizedKeyEntryTest.java | 2 +-
.../DefaultAuthorizedKeysAuthenticatorTest.java | 2 +-
.../apache/sshd/util/BogusInvertedShell.java | 2 +-
.../sshd/util/BogusPasswordAuthenticator.java | 2 +-
119 files changed, 5113 insertions(+), 3198 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
index 20510ec..c99977b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentClient.java
@@ -34,10 +34,10 @@ import java.util.List;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
public abstract class AbstractAgentClient extends AbstractLoggingBean {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
index 61df6ae..9ec0adf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/common/AbstractAgentProxy.java
@@ -37,11 +37,11 @@ import java.util.concurrent.ExecutorService;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.common.SshException;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.BufferUtils;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceConfigurer;
public abstract class AbstractAgentProxy extends AbstractLoggingBean implements SshAgent, ExecutorServiceConfigurer {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
index 7df3f2b..7a6d5a6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/local/AgentServerProxy.java
@@ -26,9 +26,9 @@ import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.SshAgentServer;
import org.apache.sshd.client.future.OpenFuture;
import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* The server side fake agent, acting as an agent, but actually forwarding the requests to the auth channel on the client side.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
index f176790..ca9ecdc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServer.java
@@ -27,10 +27,10 @@ import java.util.concurrent.Future;
import org.apache.sshd.agent.SshAgent;
import org.apache.sshd.agent.common.AbstractAgentClient;
import org.apache.sshd.agent.local.AgentImpl;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.tomcat.jni.Local;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
index 0907b63..1b02795 100644
--- a/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
+++ b/sshd-core/src/main/java/org/apache/sshd/agent/unix/AgentServerProxy.java
@@ -29,9 +29,9 @@ import org.apache.sshd.agent.SshAgentServer;
import org.apache.sshd.client.future.OpenFuture;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.session.ConnectionService;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.OsUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
import org.apache.sshd.common.util.threads.ThreadUtils;
import org.apache.tomcat.jni.Local;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
index ccea2d6..1ab0d28 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/ClientBuilder.java
@@ -27,11 +27,11 @@ import org.apache.sshd.client.kex.DHGEXClient;
import org.apache.sshd.client.keyverifier.AcceptAllServerKeyVerifier;
import org.apache.sshd.common.BaseBuilder;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Transformer;
import org.apache.sshd.common.channel.Channel;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.DHFactory;
import org.apache.sshd.common.kex.KeyExchange;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.server.forward.TcpipServerChannel;
/**
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java b/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
new file mode 100644
index 0000000..e6b7cfa
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/client/SshKeyScan.java
@@ -0,0 +1,508 @@
+/*
+ * 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.client;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.Writer;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+
+import org.apache.sshd.client.future.ConnectFuture;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.SshConstants;
+import org.apache.sshd.common.SshdSocketAddress;
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.SshConfigFileReader;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.PublicKeyEntry;
+import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.session.SessionListener;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.NoCloseInputStream;
+import org.apache.sshd.common.util.logging.AbstractSimplifiedLog;
+import org.apache.sshd.common.util.logging.LoggingUtils;
+
+/**
+ * A naive implementation of <A HREF="https://www.freebsd.org/cgi/man.cgi?query=ssh-keyscan&sektion=1">ssh-keyscan(1)</A>
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class SshKeyScan extends AbstractSimplifiedLog
+ implements Closeable, Callable<Void>, ServerKeyVerifier, SessionListener {
+ /**
+ * Default key types if not overridden from the command line
+ */
+ public static final List<String> DEFAULT_KEY_TYPES =
+ Collections.unmodifiableList(Arrays.asList("rsa", "ecdsa"));
+ public static final long DEFAULT_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
+ public static final Level DEFAULT_LEVEL = Level.INFO;
+
+ private int port;
+ private long timeout;
+ private List<String> keyTypes;
+ private InputStream input;
+ private Level level;
+ private final Map<String,String> currentHostFingerprints = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+
+ public SshKeyScan() {
+ super();
+ }
+
+ public int getPort() {
+ return port;
+ }
+
+ public void setPort(int port) {
+ this.port = port;
+ }
+
+ public InputStream getInputStream() {
+ return input;
+ }
+
+ public void setInputStream(InputStream input) {
+ this.input = input;
+ }
+
+ public List<String> getKeyTypes() {
+ return keyTypes;
+ }
+
+ public void setKeyTypes(List<String> keyTypes) {
+ this.keyTypes = keyTypes;
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+
+ public Level getLogLevel() {
+ return level;
+ }
+
+ public void setLogLevel(Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public void log(Level level, Object message, Throwable t) {
+ if (isEnabled(level)) {
+ PrintStream ps = System.out;
+ if ((t != null) || Level.SEVERE.equals(level) || Level.WARNING.equals(level)) {
+ ps = System.err;
+ }
+
+ ps.append('\t').println(message);
+ if (t != null) {
+ ps.append("\t\t").append(t.getClass().getSimpleName()).append(": ").println(t.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public boolean isEnabled(Level level) {
+ return LoggingUtils.isLoggable(level, getLogLevel());
+ }
+
+ @Override
+ public Void call() throws Exception {
+ Exception err = null;
+ try(SshClient client = SshClient.setUpDefaultClient()) {
+ Collection<String> typeNames = getKeyTypes();
+ Map<String,KeyPair> pairsMap = createKeyPairs(typeNames);
+ client.setServerKeyVerifier(this);
+
+ try(BufferedReader rdr = new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8))) {
+ client.start();
+
+ for (String line = rdr.readLine(); line != null; line = rdr.readLine()) {
+ line = GenericUtils.trimToEmpty(line);
+ if (GenericUtils.isEmpty(line)) {
+ continue;
+ }
+
+ try {
+ resolveServerKeys(client, line, pairsMap);
+ } catch(Exception e) {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Failed to retrieve keys from " + line, e);
+ }
+ err = GenericUtils.accumulateException(err, e);
+ } finally {
+ currentHostFingerprints.clear();
+ }
+ }
+ } finally {
+ client.stop();
+ }
+ }
+
+ if (err != null) {
+ throw err;
+ }
+
+ return null;
+ }
+
+ protected void resolveServerKeys(SshClient client, String host, Map<String,KeyPair> pairsMap) {
+ for (Map.Entry<String,KeyPair> pe : pairsMap.entrySet()) {
+ String kt = pe.getKey();
+ try {
+ resolveServerKeys(client, host, kt, pe.getValue());
+ } catch(Exception e) {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Failed to resolve key=" + kt + " for " + host);
+ }
+
+ if (e instanceof ConnectException) {
+ return; // makes no sense to try again with another key type...
+ }
+ }
+ }
+ }
+
+ protected void resolveServerKeys(SshClient client, String host, String kt, KeyPair kp) throws Exception {
+ int connectPort = getPort();
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Connecting to " + host + ":" + connectPort);
+ }
+
+ ConnectFuture future = client.connect(UUID.randomUUID().toString(), host, connectPort);
+ long waitTime = getTimeout();
+ if (!future.await(waitTime)) {
+ throw new ConnectException("Failed to connect to " + host + ":" + connectPort + " within " + waitTime + " msec.");
+ }
+
+ try(ClientSession session = future.getSession()) {
+ IoSession ioSession = session.getIoSession();
+ SocketAddress remoteAddress = ioSession.getRemoteAddress();
+ String remoteLocation = toString(remoteAddress);
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Connected to " + remoteLocation);
+ }
+
+ try {
+ session.addListener(this);
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "Authenticating with " + kt + " to " + remoteLocation);
+ }
+
+ // shouldn't really succeed, but do it since key exchange occurs only on auth attempt
+ session.addPublicKeyIdentity(kp);
+ try {
+ session.auth().verify(waitTime);
+ log(Level.WARNING, "Unexpected authentication success using key type=" + kt + " with " + remoteLocation);
+ } catch(Exception e) {
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "Failed to authenticate using key type=" + kt + " with " + remoteLocation);
+ }
+ }
+ } finally {
+ session.removeListener(this);
+ }
+ }
+ }
+
+ @Override
+ public void sessionCreated(Session session) {
+ logSessionEvent(session, "Created");
+ }
+
+ @Override
+ public void sessionEvent(Session session, Event event) {
+ logSessionEvent(session, event);
+ if (isEnabled(Level.FINEST) && Event.KexCompleted.equals(event)) {
+ IoSession ioSession = session.getIoSession();
+ SocketAddress remoteAddress = ioSession.getRemoteAddress();
+ String remoteLocation = toString(remoteAddress);
+ for (int paramType = 0; paramType < SshConstants.PROPOSAL_KEX_NAMES.size(); paramType++) {
+ String paramName = SshConstants.PROPOSAL_KEX_NAMES.get(paramType);
+ String paramValue = session.getNegotiatedKexParameter(paramType);
+ log(Level.FINEST, remoteLocation + "[" + paramName + "]: " + paramValue);
+ }
+ }
+ }
+
+ @Override
+ public void sessionClosed(Session session) {
+ logSessionEvent(session, "Closed");
+ }
+
+ protected void logSessionEvent(Session session, Object event) {
+ if (isEnabled(Level.FINEST)) {
+ IoSession ioSession = session.getIoSession();
+ SocketAddress remoteAddress = ioSession.getRemoteAddress();
+ log(Level.FINEST, "Session " + toString(remoteAddress) + " event: " + event);
+ }
+ }
+
+ @Override
+ public boolean verifyServerKey(ClientSession sshClientSession, SocketAddress remoteAddress, PublicKey serverKey) {
+ String remoteLocation = toString(remoteAddress);
+ try {
+ String extra = KeyUtils.getFingerPrint(serverKey);
+ String keyType = KeyUtils.getKeyType(serverKey);
+ String current = GenericUtils.isEmpty(keyType) ? null : currentHostFingerprints.get(keyType);
+ if (Objects.equals(current, extra)) {
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "verifyServerKey(" + remoteLocation + ")[" + keyType + "] skip existing key: " + extra);
+ }
+ } else {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "verifyServerKey(" + remoteLocation + ")[" + keyType + "] found new key: " + extra);
+ }
+
+ StringBuilder sb = new StringBuilder(256).append(remoteLocation).append(' ');
+ PublicKeyEntry.appendPublicKeyEntry(sb, serverKey);
+ log(Level.INFO, sb);
+
+ if (!GenericUtils.isEmpty(keyType)) {
+ currentHostFingerprints.put(keyType, extra);
+ }
+ }
+ } catch(Exception e) {
+ log(Level.SEVERE, "Failed to output the public key from " + remoteLocation, e);
+ }
+
+ return true;
+ }
+
+ private static final String toString(SocketAddress addr) {
+ if (addr == null) {
+ return null;
+ } else if (addr instanceof InetSocketAddress) {
+ return ((InetSocketAddress) addr).getHostString();
+ } else if (addr instanceof SshdSocketAddress) {
+ return ((SshdSocketAddress) addr).getHostName();
+ } else {
+ return addr.toString();
+ }
+ }
+
+ protected Map<String,KeyPair> createKeyPairs(Collection<String> typeNames) throws GeneralSecurityException {
+ if (GenericUtils.isEmpty(typeNames)) {
+ return Collections.emptyMap();
+ }
+
+ Map<String,KeyPair> pairsMap = new TreeMap<String, KeyPair>(String.CASE_INSENSITIVE_ORDER);
+ for (String kt : typeNames) {
+ if (isEnabled(Level.FINE)) {
+ log(Level.FINE, "Generate key pair for " + kt);
+ }
+
+ if ("rsa".equalsIgnoreCase(kt)) {
+ pairsMap.put(KeyPairProvider.SSH_RSA, KeyUtils.generateKeyPair(KeyPairProvider.SSH_RSA, 1024));
+ } else if ("dsa".equalsIgnoreCase(kt)) {
+ pairsMap.put(KeyPairProvider.SSH_DSS, KeyUtils.generateKeyPair(KeyPairProvider.SSH_DSS, 512));
+ } else if ("ecdsa".equalsIgnoreCase(kt)) {
+ if (!SecurityUtils.hasEcc()) {
+ throw new InvalidKeySpecException("ECC not supported");
+ }
+
+ for (String curveName : ECCurves.NAMES) {
+ Integer keySize = ECCurves.getCurveSize(curveName);
+ if (keySize == null) {
+ throw new InvalidKeySpecException("Unknown curve: " + curveName);
+ }
+
+ if (isEnabled(Level.FINER)) {
+ log(Level.FINER, "Generate key pair for curve=" + curveName);
+ }
+
+ String keyName = ECCurves.ECDSA_SHA2_PREFIX + curveName;
+ pairsMap.put(keyName, KeyUtils.generateKeyPair(keyName, keySize.intValue()));
+ }
+ }
+ }
+
+ return pairsMap;
+ }
+
+ @Override
+ public void close() throws IOException {
+ IOException err = null;
+ if (input != null) {
+ try {
+ input.close();
+ } catch(IOException e) {
+ err = GenericUtils.accumulateException(err, e);
+ } finally {
+ input = null;
+ }
+ }
+ }
+
+ //////////////////////////////////////////////////////////////////////////
+
+ // returns a List of the hosts to be contacted
+ public static final List<String> parseCommandLineArguments(SshKeyScan scanner, String ... args) throws IOException {
+ int numArgs = GenericUtils.length(args);
+ for (int index=0; index < numArgs; index++) {
+ String optName = args[index];
+ if ("-f".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(scanner.getInputStream() == null, "%s option re-specified", optName);
+
+ String filePath = args[index];
+ if ("-".equals(filePath)) {
+ scanner.setInputStream(new NoCloseInputStream(System.in));
+ } else {
+ scanner.setInputStream(new FileInputStream(filePath));
+ }
+ } else if ("-t".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(GenericUtils.isEmpty(scanner.getKeyTypes()), "%s option re-specified", optName);
+
+ String typeList = args[index];
+ String[] types = GenericUtils.split(typeList, ',');
+ ValidateUtils.checkTrue(GenericUtils.length(types) > 0, "No types specified for %s", optName);
+ } else if ("-p".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(scanner.getPort() <= 0, "%s option re-specified", optName);
+
+ String portValue = args[index];
+ int port = Integer.parseInt(portValue);
+ ValidateUtils.checkTrue((port > 0) && (port <= 0xFFFF), "Bad port: %s", portValue);
+ scanner.setPort(port);
+ } else if ("-T".equals(optName)) {
+ index++;
+ ValidateUtils.checkTrue(index < numArgs, "Missing %s option argument", optName);
+ ValidateUtils.checkTrue(scanner.getTimeout() <= 0, "%s option re-specified", optName);
+
+ String timeoutValue = args[index];
+ long timeout = Long.parseLong(timeoutValue);
+ ValidateUtils.checkTrue(timeout > 0L, "Bad timeout: %s", timeoutValue);
+ scanner.setTimeout(timeout);
+ } else if ("-v".equals(optName)) {
+ ValidateUtils.checkTrue(scanner.getLogLevel() == null, "%s option re-specified", optName);
+ scanner.setLogLevel(Level.FINEST);
+ } else { // stop at first non-option - assume the rest are host names/addresses
+ ValidateUtils.checkTrue((optName.charAt(0) != '-'), "Unknown option: %s", optName);
+
+ int remaining = numArgs - index;
+ if (remaining == 1) {
+ return Collections.singletonList(optName);
+ }
+
+ List<String> hosts = new ArrayList<String>(remaining);
+ for ( ; index < numArgs; index++) {
+ hosts.add(args[index]);
+ }
+
+ return hosts;
+ }
+ }
+
+ return Collections.emptyList();
+ }
+
+ /* -------------------------------------------------------------------- */
+
+ public static final <S extends SshKeyScan> S setInputStream(S scanner, Collection<String> hosts) throws IOException {
+ if (GenericUtils.isEmpty(hosts)) {
+ ValidateUtils.checkNotNull(scanner.getInputStream(), "No hosts or file specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+ } else {
+ ValidateUtils.checkTrue(scanner.getInputStream() == null, "Both hosts and file specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+
+ // convert the hosts from the arguments into a "file" - one host per line
+ try(ByteArrayOutputStream baos = new ByteArrayOutputStream(hosts.size() * 32)) {
+ try(Writer w = new OutputStreamWriter(baos, StandardCharsets.UTF_8)) {
+ String EOL = System.getProperty("line.separator");
+ for (String h : hosts) {
+ w.append(h).append(EOL);
+ }
+ }
+
+ byte[] data = baos.toByteArray();
+ scanner.setInputStream(new ByteArrayInputStream(data));
+ }
+ }
+
+ return scanner;
+ }
+
+ public static final <S extends SshKeyScan> S initializeScanner(S scanner, Collection<String> hosts) throws IOException {
+ setInputStream(scanner, hosts);
+ if (scanner.getPort() <= 0) {
+ scanner.setPort(SshConfigFileReader.DEFAULT_PORT);
+ }
+
+ if (scanner.getTimeout() <= 0L) {
+ scanner.setTimeout(DEFAULT_TIMEOUT);
+ }
+
+ if (GenericUtils.isEmpty(scanner.getKeyTypes())) {
+ scanner.setKeyTypes(DEFAULT_KEY_TYPES);
+ }
+
+ if (scanner.getLogLevel() == null) {
+ scanner.setLogLevel(DEFAULT_LEVEL);
+ }
+
+ return scanner;
+ }
+
+ /* -------------------------------------------------------------------- */
+
+ public static void main(String[] args) throws Exception {
+ try(SshKeyScan scanner = new SshKeyScan()) {
+ Collection<String> hosts = parseCommandLineArguments(scanner, args);
+ initializeScanner(scanner, hosts);
+ scanner.call();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
index af17b13..6adc678 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthKeyboardInteractive.java
@@ -33,9 +33,9 @@ import org.apache.sshd.client.UserInteraction;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
index ea3cb8a..b9e885b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPassword.java
@@ -27,8 +27,8 @@ import org.apache.sshd.client.UserAuth;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
index 6bc90bf..2d2c95a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/auth/UserAuthPublicKey.java
@@ -38,9 +38,9 @@ import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
index ddb16e3..b444c16 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/channel/AbstractClientChannel.java
@@ -35,9 +35,9 @@ import org.apache.sshd.common.channel.ChannelAsyncOutputStream;
import org.apache.sshd.common.channel.RequestHandler;
import org.apache.sshd.common.io.IoInputStream;
import org.apache.sshd.common.io.IoOutputStream;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.buffer.Buffer;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.common.util.io.IoUtils;
/**
* TODO Add javadoc
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
index 6c58647..73ba903 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/DelegatingServerKeyVerifier.java
@@ -24,7 +24,7 @@ import java.util.Map;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/*
* A ServerKeyVerifier that delegates verification to the ServerKeyVerifier found in the ClientSession metadata
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
index 8342eb9..6cd5dbc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/RequiredServerKeyVerifier.java
@@ -23,8 +23,8 @@ import java.security.PublicKey;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.buffer.BufferUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* A ServerKeyVerifier that accepts one server key (specified in the constructor)
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
index f80e82b..18bb93a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/keyverifier/StaticServerKeyVerifier.java
@@ -25,7 +25,7 @@ import java.security.PublicKey;
import org.apache.sshd.client.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.config.keys.KeyUtils;
-import org.apache.sshd.common.util.AbstractLoggingBean;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* Returns the same constant answer {@code true/false} regardless
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
index d59000d..fcefa3e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/scp/AbstractScpClient.java
@@ -36,10 +36,10 @@ import java.util.EnumSet;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.scp.ScpHelper;
import org.apache.sshd.common.scp.ScpTimestamp;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
index d4bd108..6a885d4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSession.java
@@ -68,9 +68,32 @@ public interface ClientSession extends Session {
int WAIT_AUTH = 0x0004;
int AUTHED = 0x0008;
+ /**
+ * @param password Password to be added - may not be {@code null}/empty
+ */
void addPasswordIdentity(String password);
+
+ /**
+ * @param password The password to remove - ignored if {@code null}/empty
+ * @return The removed password - same one that was added via
+ * {@link #addPasswordIdentity(String)} - or {@code null} if no
+ * match found
+ */
+ String removePasswordIdentity(String password);
+
+ /**
+ * @param key The {@link KeyPair} to add - may not be {@code null}
+ */
void addPublicKeyIdentity(KeyPair key);
+ /**
+ * @param kp The {@link KeyPair} to remove - ignored if {@code null}
+ * @return The removed {@link KeyPair} - same one that was added via
+ * {@link #addPublicKeyIdentity(KeyPair)} - or {@code null} if no
+ * match found
+ */
+ KeyPair removePublicKeyIdentity(KeyPair kp);
+
UserInteraction getUserInteraction();
void setUserInteraction(UserInteraction userInteraction);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
index d29b350..eaf1901 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientSessionImpl.java
@@ -23,6 +23,7 @@ import java.net.SocketAddress;
import java.nio.file.FileSystem;
import java.security.KeyPair;
import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -50,6 +51,7 @@ import org.apache.sshd.common.SshConstants;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.SshdSocketAddress;
import org.apache.sshd.common.cipher.CipherNone;
+import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.future.DefaultSshFuture;
import org.apache.sshd.common.future.SshFuture;
import org.apache.sshd.common.io.IoSession;
@@ -58,6 +60,8 @@ import org.apache.sshd.common.session.AbstractConnectionService;
import org.apache.sshd.common.session.AbstractSession;
import org.apache.sshd.common.session.ConnectionService;
import org.apache.sshd.common.session.SessionListener;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.buffer.Buffer;
/**
@@ -66,6 +70,37 @@ import org.apache.sshd.common.util.buffer.Buffer;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public class ClientSessionImpl extends AbstractSession implements ClientSession {
+ /**
+ * Compares 2 password identities - returns zero ONLY if <U>both</U> compared
+ * objects are {@link String}s and equal to each other
+ */
+ public static final Comparator<Object> PASSWORD_IDENTITY_COMPARATOR = new Comparator<Object>() {
+ @Override
+ public int compare(Object o1, Object o2) {
+ if ((!(o1 instanceof String)) || (!(o2 instanceof String))) {
+ return (-1);
+ } else {
+ return ((String) o1).compareTo((String) o2);
+ }
+ }
+ };
+
+ /**
+ * Compares 2 {@link KeyPair} identities - returns zero ONLY if <U>both</U> compared
+ * objects are {@link KeyPair}s and equal to each other
+ */
+ public static final Comparator<Object> KEYPAIR_IDENTITY_COMPARATOR = new Comparator<Object>() {
+ @Override
+ public int compare(Object o1, Object o2) {
+ if ((!(o1 instanceof KeyPair)) || (!(o2 instanceof KeyPair))) {
+ return (-1);
+ } else if (KeyUtils.compareKeyPairs((KeyPair) o1, (KeyPair) o2)) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+ };
/**
* For clients to store their own metadata
@@ -85,12 +120,12 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
public ClientSessionImpl(ClientFactoryManager client, IoSession session) throws Exception {
super(false, client, session);
- log.info("Client session created: {}", session);
+ log.debug("Client session created: {}", session);
// Need to set the initial service early as calling code likes to start trying to
// manipulate it before the connection has even been established. For instance, to
// set the authPassword.
List<ServiceFactory> factories = client.getServiceFactories();
- if (factories == null || factories.isEmpty() || factories.size() > 2) {
+ if (GenericUtils.isEmpty(factories) || factories.size() > 2) {
throw new IllegalArgumentException("One or two services must be configured");
}
currentServiceFactory = factories.get(0);
@@ -128,12 +163,62 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
@Override
public void addPasswordIdentity(String password) {
- identities.add(password);
+ identities.add(ValidateUtils.checkNotNullAndNotEmpty(password, "No password provided", GenericUtils.EMPTY_OBJECT_ARRAY));
+ if (log.isDebugEnabled()) { // don't show the password in the log
+ log.debug("addPasswordIdentity(" + KeyUtils.getFingerPrint(password) + ")");
+ }
+ }
+
+ @Override
+ public String removePasswordIdentity(String password) {
+ if (GenericUtils.isEmpty(password)) {
+ return null;
+ }
+
+ int index = findIdentityIndex(PASSWORD_IDENTITY_COMPARATOR, password);
+ if (index >= 0) {
+ return (String) identities.remove(index);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void addPublicKeyIdentity(KeyPair kp) {
+ ValidateUtils.checkNotNull(kp, "No key-pair to add", GenericUtils.EMPTY_OBJECT_ARRAY);
+ ValidateUtils.checkNotNull(kp.getPublic(), "No public key", GenericUtils.EMPTY_OBJECT_ARRAY);
+ ValidateUtils.checkNotNull(kp.getPrivate(), "No private key", GenericUtils.EMPTY_OBJECT_ARRAY);
+
+ identities.add(kp);
+
+ if (log.isDebugEnabled()) {
+ log.debug("addPublicKeyIdentity(" + KeyUtils.getFingerPrint(kp.getPublic()) + ")");
+ }
}
@Override
- public void addPublicKeyIdentity(KeyPair key) {
- identities.add(key);
+ public KeyPair removePublicKeyIdentity(KeyPair kp) {
+ if (kp == null) {
+ return null;
+ }
+
+ int index = findIdentityIndex(KEYPAIR_IDENTITY_COMPARATOR, kp);
+ if (index >= 0) {
+ return (KeyPair) identities.remove(index);
+ } else {
+ return null;
+ }
+ }
+
+ protected int findIdentityIndex(Comparator<? super Object> comp, Object target) {
+ for (int index = 0; index < identities.size(); index++) {
+ Object value = identities.get(index);
+ if (comp.compare(value, target) == 0) {
+ return index;
+ }
+ }
+
+ return (-1);
}
@Override
@@ -382,7 +467,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
if (serverVersion == null) {
return false;
}
- log.info("Server version string: {}", serverVersion);
+ log.debug("Server version string: {}", serverVersion);
if (!(serverVersion.startsWith("SSH-2.0-") || serverVersion.startsWith("SSH-1.99-"))) {
throw new SshException(SshConstants.SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED,
"Unsupported protocol version: " + serverVersion);
@@ -390,7 +475,7 @@ public class ClientSessionImpl extends AbstractSession implements ClientSession
return true;
}
- private void sendClientIdentification() {
+ protected void sendClientIdentification() {
clientVersion = "SSH-2.0-" + getFactoryManager().getVersion();
sendIdentification(clientVersion);
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
index 1bb5b58..72d8601 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/session/ClientUserAuthService.java
@@ -169,7 +169,7 @@ public class ClientUserAuthService extends CloseableUtils.AbstractCloseable impl
return;
}
if (cmd == SshConstants.SSH_MSG_USERAUTH_FAILURE) {
- log.info("Received SSH_MSG_USERAUTH_FAILURE");
+ log.debug("Received SSH_MSG_USERAUTH_FAILURE");
String mths = buffer.getString();
boolean partial = buffer.getBoolean();
if (partial || serverMethods == null) {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
index b532b9d..2bcb9ef 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/AbstractSftpClient.java
@@ -26,8 +26,8 @@ import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
index d4c171a..4f7b693 100644
--- a/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
+++ b/sshd-core/src/main/java/org/apache/sshd/client/sftp/SftpFileSystemProvider.java
@@ -82,8 +82,8 @@ import org.apache.sshd.common.SshException;
import org.apache.sshd.common.config.SshConfigFileReader;
import org.apache.sshd.common.sftp.SftpConstants;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
index 3337e46..76c1e0c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedFactory.java
@@ -23,6 +23,7 @@ import java.util.Collection;
import java.util.List;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
/**
* A named factory is a factory identified by a name.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
index d57f433..b38670f 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/NamedResource.java
@@ -26,6 +26,7 @@ import java.util.Comparator;
import java.util.List;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java b/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
index eebd1b1..d6a41be 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/SshConstants.java
@@ -18,6 +18,10 @@
*/
package org.apache.sshd.common;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
/**
* This interface defines constants for the SSH protocol.
*
@@ -100,18 +104,19 @@ public interface SshConstants {
* list index matches the {@code PROPOSAL_XXX} constant
* @see <A HREF="http://tools.ietf.org/html/rfc4253#section-7.1">RFC-4253 - section 7.1</A>
*/
- static final String[] PROPOSAL_KEX_NAMES = {
- "kex algorithms",
- "server host key algorithms",
- "encryption algorithms (client to server)",
- "encryption algorithms (server to client)",
- "mac algorithms (client to server)",
- "mac algorithms (server to client)",
- "compression algorithms (client to server)",
- "compression algorithms (server to client)",
- "languages (client to server)",
- "languages (server to client)"
- };
+ static final List<String> PROPOSAL_KEX_NAMES =
+ Collections.unmodifiableList(Arrays.asList(
+ "kex algorithms",
+ "server host key algorithms",
+ "encryption algorithms (client to server)",
+ "encryption algorithms (server to client)",
+ "mac algorithms (client to server)",
+ "mac algorithms (server to client)",
+ "compression algorithms (client to server)",
+ "compression algorithms (server to client)",
+ "languages (client to server)",
+ "languages (server to client)"
+ ));
//
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java b/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java
deleted file mode 100644
index 952b2c0..0000000
--- a/sshd-core/src/main/java/org/apache/sshd/common/Transformer.java
+++ /dev/null
@@ -1,58 +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;
-
-import java.util.Objects;
-
-/**
- * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
- */
-public interface Transformer<I, O> {
- // TODO in JDK-8 replace this with Function
- /**
- * @param input Input value
- * @return Transformed output value
- */
- O transform(I input);
-
- /**
- * Invokes {@link Objects#toString(Object)} on the argument
- */
- Transformer<Object,String> TOSTRING=new Transformer<Object,String>() {
- @Override
- public String transform(Object input) {
- return Objects.toString(input);
- }
- };
-
- /**
- * Returns {@link Enum#name()} or {@code null} if argument is {@code null}
- */
- Transformer<Enum<?>,String> ENUM_NAME_EXTRACTOR=new Transformer<Enum<?>,String>() {
- @Override
- public String transform(Enum<?> input) {
- if (input == null) {
- return null;
- } else {
- return input.name();
- }
- }
- };
-}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
index bf2a91a..d72395e 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
@@ -25,9 +25,9 @@ import java.util.Map;
import org.apache.sshd.common.FactoryManager;
import org.apache.sshd.common.FactoryManagerUtils;
import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.util.AbstractLoggingBean;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.logging.AbstractLoggingBean;
/**
* A Window for a given channel.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
index 6f4963f..94834b4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/CipherFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.cipher;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
index 0c0c66f..d3f0b34 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/cipher/ECCurves.java
@@ -24,7 +24,9 @@ import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
+import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -58,16 +60,89 @@ public class ECCurves {
}
/**
+ * Key=curve name, value=num. of bits
+ */
+ private static final Map<String,Integer> CURVENAME2SIZE =
+ Collections.unmodifiableMap(new TreeMap<String,Integer>(String.CASE_INSENSITIVE_ORDER) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ put(NISTP256, Integer.valueOf(256));
+ put(NISTP384, Integer.valueOf(384));
+ put(NISTP521, Integer.valueOf(521));
+ }
+
+ });
+
+ /**
+ * An un-modifiable {@link List} of all the known curve names
+ */
+ @SuppressWarnings("synthetic-access")
+ public static final List<String> NAMES =
+ Collections.unmodifiableList(new ArrayList<String>(CURVENAME2SIZE.size()) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ addAll(CURVENAME2SIZE.keySet());
+ Collections.sort(this); // as a courtesy
+ }
+ });
+
+ /**
+ * An un-modifiable {@link List} of all the known curve types according to {@code OpenSSH}
+ */
+ public static final List<String> TYPES =
+ Collections.unmodifiableList(new ArrayList<String>(CURVENAME2SIZE.size()) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ for (String n : NAMES) {
+ add(ECDSA_SHA2_PREFIX + n);
+ }
+
+ Collections.sort(this); // as a courtesy
+ }
+ });
+ /**
+ * An un-modifiable {@link List} of all the known curve sizes
+ */
+ @SuppressWarnings("synthetic-access")
+ public static final List<Integer> SIZES =
+ Collections.unmodifiableList(new ArrayList<Integer>(CURVENAME2SIZE.size()) {
+ private static final long serialVersionUID = 1L; // we're not serializing it
+
+ {
+ addAll(CURVENAME2SIZE.values());
+ Collections.sort(this); // as a courtesy
+ }
+ });
+
+ /**
+ * @param name The curve name - ignored if {@code null}/empty
+ * @return The curve size - {@code null} if unknown curve
+ */
+ public static Integer getCurveSize(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ } else {
+ return CURVENAME2SIZE.get(name);
+ }
+ }
+
+ /**
* Key=num. of bits, value=curve name
*/
+ @SuppressWarnings("synthetic-access")
private static final Map<Integer, String> SIZE2CURVENAME =
Collections.unmodifiableMap(new TreeMap<Integer, String>() {
private static final long serialVersionUID = 1L; // we're not serializing it
{
- put(Integer.valueOf(256), NISTP256);
- put(Integer.valueOf(384), NISTP384);
- put(Integer.valueOf(521), NISTP521);
+ for (Map.Entry<String,Integer> e : CURVENAME2SIZE.entrySet()) {
+ String name = e.getKey();
+ Integer size = e.getValue();
+ put(size, name);
+ }
}
});
@@ -234,7 +309,7 @@ public class ECCurves {
private static final class LazySpecsMapHolder {
private static final Map<String,ECParameterSpec> specsMap =
- Collections.unmodifiableMap(new TreeMap<String, ECParameterSpec>(String.CASE_INSENSITIVE_ORDER) {
+ Collections.unmodifiableMap(new TreeMap<String,ECParameterSpec>(String.CASE_INSENSITIVE_ORDER) {
private static final long serialVersionUID = 1L; // we're not serializing it
{
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
index 3af29d7..9895922 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/compression/CompressionFactory.java
@@ -21,7 +21,7 @@ package org.apache.sshd.common.compression;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.OptionalFeature;
-import org.apache.sshd.common.Transformer;
+import org.apache.sshd.common.util.Transformer;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
index e15d16f..92587a3 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/SshConfigFileReader.java
@@ -39,7 +39,6 @@ import org.apache.sshd.client.ClientBuilder;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.common.AbstractFactoryManager;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.Transformer;
import org.apache.sshd.common.cipher.BuiltinCiphers;
import org.apache.sshd.common.cipher.Cipher;
import org.apache.sshd.common.cipher.CipherFactory;
@@ -57,6 +56,7 @@ import org.apache.sshd.common.signature.BuiltinSignatures;
import org.apache.sshd.common.signature.Signature;
import org.apache.sshd.common.signature.SignatureFactory;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Transformer;
import org.apache.sshd.common.util.ValidateUtils;
import org.apache.sshd.common.util.io.NoCloseInputStream;
import org.apache.sshd.common.util.io.NoCloseReader;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
index 763a8ce..8c701a7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/AbstractPublicKeyEntryDecoder.java
@@ -28,31 +28,80 @@ import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Collection;
import org.apache.sshd.common.util.GenericUtils;
-import org.apache.sshd.common.util.IoUtils;
import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.common.util.io.IoUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> implements PublicKeyEntryDecoder<K> {
- private final Class<K> keyType;
+public abstract class AbstractPublicKeyEntryDecoder<PUB extends PublicKey,PRV extends PrivateKey>
+ implements PublicKeyEntryDecoder<PUB,PRV> {
+ private final Class<PUB> pubType;
+ private final Class<PRV> prvType;
private final Collection<String> names;
- protected AbstractPublicKeyEntryDecoder(Class<K> keyType, Collection<String> names) {
- this.keyType = ValidateUtils.checkNotNull(keyType, "No key type specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+ protected AbstractPublicKeyEntryDecoder(Class<PUB> pubType, Class<PRV> prvType, Collection<String> names) {
+ this.pubType = ValidateUtils.checkNotNull(pubType, "No public key type specified", GenericUtils.EMPTY_OBJECT_ARRAY);
+ this.prvType = ValidateUtils.checkNotNull(prvType, "No private key type specified", GenericUtils.EMPTY_OBJECT_ARRAY);
this.names = ValidateUtils.checkNotNullAndNotEmpty(names, "No type names provided", GenericUtils.EMPTY_OBJECT_ARRAY);
}
@Override
- public final Class<K> getKeyType() {
- return keyType;
+ public final Class<PUB> getPublicKeyType() {
+ return pubType;
+ }
+
+ @Override
+ public final Class<PRV> getPrivateKeyType() {
+ return prvType;
+ }
+
+ @Override
+ public KeyPair cloneKeyPair(KeyPair kp) throws GeneralSecurityException {
+ if (kp == null) {
+ return null;
+ }
+
+ PUB pubCloned = null;
+ {
+ PublicKey pubOriginal = kp.getPublic();
+ Class<PUB> pubExpected = getPublicKeyType();
+ if (pubOriginal != null) {
+ Class<?> orgType = pubOriginal.getClass();
+ if (!pubExpected.isAssignableFrom(orgType)) {
+ throw new InvalidKeyException("Mismatched public key types: expected=" + pubExpected.getSimpleName() + ", actual=" + orgType.getSimpleName());
+ }
+
+ pubCloned = clonePublicKey(pubExpected.cast(pubOriginal));
+ }
+ }
+
+ PRV prvCloned = null;
+ {
+ PrivateKey prvOriginal = kp.getPrivate();
+ Class<PRV> prvExpected = getPrivateKeyType();
+ if (prvOriginal != null) {
+ Class<?> orgType = prvOriginal.getClass();
+ if (!prvExpected.isAssignableFrom(orgType)) {
+ throw new InvalidKeyException("Mismatched private key types: expected=" + prvExpected.getSimpleName() + ", actual=" + orgType.getSimpleName());
+ }
+
+ prvCloned = clonePrivateKey(prvExpected.cast(prvOriginal));
+ }
+ }
+
+ return new KeyPair(pubCloned, prvCloned);
}
@Override
@@ -61,12 +110,12 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
}
@Override
- public K decodePublicKey(byte... keyData) throws IOException, GeneralSecurityException {
+ public PUB decodePublicKey(byte... keyData) throws IOException, GeneralSecurityException {
return decodePublicKey(keyData, 0, GenericUtils.length(keyData));
}
@Override
- public K decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException {
+ public PUB decodePublicKey(byte[] keyData, int offset, int length) throws IOException, GeneralSecurityException {
if (length <= 0) {
return null;
}
@@ -77,7 +126,7 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
}
@Override
- public K decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException {
+ public PUB decodePublicKey(InputStream keyData) throws IOException, GeneralSecurityException {
// the actual data is preceded by a string that repeats the key type
String type = decodeString(keyData);
if (GenericUtils.isEmpty(type)) {
@@ -92,13 +141,17 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
return decodePublicKey(type, keyData);
}
- public K generatePublicKey(KeySpec keySpec) throws GeneralSecurityException {
+ public PUB generatePublicKey(KeySpec keySpec) throws GeneralSecurityException {
KeyFactory factory = getKeyFactoryInstance();
- Class<K> keyType = getKeyType();
+ Class<PUB> keyType = getPublicKeyType();
return keyType.cast(factory.generatePublic(keySpec));
}
- public abstract KeyFactory getKeyFactoryInstance() throws GeneralSecurityException;
+ public PRV generatePrivateKey(KeySpec keySpec) throws GeneralSecurityException {
+ KeyFactory factory = getKeyFactoryInstance();
+ Class<PRV> keyType = getPrivateKeyType();
+ return keyType.cast(factory.generatePrivate(keySpec));
+ }
/**
* @param keyType The reported / encode key type
@@ -108,11 +161,18 @@ public abstract class AbstractPublicKeyEntryDecoder<K extends PublicKey> impleme
* @throws IOException If failed to read from the data stream
* @throws GeneralSecurityException If failed to generate the key
*/
- public abstract K decodePublicKey(String keyType, InputStream keyData) throws IOException, GeneralSecurityException;
+ public abstract PUB decodePublicKey(String keyType, InputStream keyData) throws IOException, GeneralSecurityException;
+
+ @Override
+ public KeyPair generateKeyPair(int keySize) throws GeneralSecurityException {
+ KeyPairGenerator gen=getKeyPairGenerator();
+ gen.initialize(keySize);
+ return gen.generateKeyPair();
+ }
@Override
public String toString() {
- return getKeyType().getSimpleName() + ": " + getSupportedTypeNames();
+ return getPublicKeyType().getSimpleName() + ": " + getSupportedTypeNames();
}
public static final int encodeString(OutputStream s, String v) throws IOException {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
index 05af8ba..b48d3cf 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/DSSPublicKeyEntryDecoder.java
@@ -24,9 +24,13 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
import java.security.spec.DSAPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.util.Collections;
@@ -39,11 +43,11 @@ import org.apache.sshd.common.util.ValidateUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAPublicKey> {
+public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAPublicKey,DSAPrivateKey> {
public static final DSSPublicKeyEntryDecoder INSTANCE = new DSSPublicKeyEntryDecoder();
public DSSPublicKeyEntryDecoder() {
- super(DSAPublicKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
+ super(DSAPublicKey.class, DSAPrivateKey.class, Collections.unmodifiableList(Collections.singletonList(KeyPairProvider.SSH_DSS)));
}
@Override
@@ -75,6 +79,39 @@ public class DSSPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<DSAP
}
@Override
+ public DSAPublicKey clonePublicKey(DSAPublicKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ }
+
+ DSAParams params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePublicKey(new DSAPublicKeySpec(key.getY(), params.getP(), params.getQ(), params.getG()));
+ }
+
+ @Override
+ public DSAPrivateKey clonePrivateKey(DSAPrivateKey key) throws GeneralSecurityException {
+ if (key == null) {
+ return null;
+ }
+
+ DSAParams params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePrivateKey(new DSAPrivateKeySpec(key.getX(), params.getP(), params.getQ(), params.getG()));
+ }
+
+ @Override
+ public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException {
+ return SecurityUtils.getKeyPairGenerator("DSA");
+ }
+
+ @Override
public KeyFactory getKeyFactoryInstance() throws GeneralSecurityException {
return SecurityUtils.getKeyFactory("DSA");
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/6432a7af/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
index 3325a26..feba09c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/config/keys/ECDSAPublicKeyEntryDecoder.java
@@ -26,20 +26,23 @@ import java.io.OutputStream;
import java.io.StreamCorruptedException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.NoSuchProviderException;
+import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
+import java.security.spec.ECPrivateKeySpec;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
-import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import org.apache.sshd.common.cipher.ECCurves;
-import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.GenericUtils;
import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.common.util.ValidateUtils;
@@ -48,13 +51,11 @@ import org.apache.sshd.common.util.buffer.BufferUtils;
/**
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<ECPublicKey> {
+public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<ECPublicKey,ECPrivateKey> {
public static final ECDSAPublicKeyEntryDecoder INSTANCE = new ECDSAPublicKeyEntryDecoder();
public ECDSAPublicKeyEntryDecoder() {
- super(ECPublicKey.class,
- Collections.unmodifiableList(
- Arrays.asList(KeyPairProvider.ECDSA_SHA2_NISTP256, KeyPairProvider.ECDSA_SHA2_NISTP384, KeyPairProvider.ECDSA_SHA2_NISTP521)));
+ super(ECPublicKey.class, ECPrivateKey.class, ECCurves.TYPES);
}
@Override
@@ -96,6 +97,42 @@ public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<EC
}
@Override
+ public ECPublicKey clonePublicKey(ECPublicKey key) throws GeneralSecurityException {
+ if (!SecurityUtils.hasEcc()) {
+ throw new NoSuchProviderException("ECC not supported");
+ }
+
+ if (key == null) {
+ return null;
+ }
+
+ ECParameterSpec params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePublicKey(new ECPublicKeySpec(key.getW(), params));
+ }
+
+ @Override
+ public ECPrivateKey clonePrivateKey(ECPrivateKey key) throws GeneralSecurityException {
+ if (!SecurityUtils.hasEcc()) {
+ throw new NoSuchProviderException("ECC not supported");
+ }
+
+ if (key == null) {
+ return null;
+ }
+
+ ECParameterSpec params = key.getParams();
+ if (params == null) {
+ throw new InvalidKeyException("Missing parameters in key");
+ }
+
+ return generatePrivateKey(new ECPrivateKeySpec(key.getS(), params));
+ }
+
+ @Override
public String encodePublicKey(OutputStream s, ECPublicKey key) throws IOException {
ValidateUtils.checkNotNull(key, "No public key provided", GenericUtils.EMPTY_OBJECT_ARRAY);
@@ -118,6 +155,32 @@ public class ECDSAPublicKeyEntryDecoder extends AbstractPublicKeyEntryDecoder<EC
}
}
+ @Override
+ public KeyPair generateKeyPair(int keySize) throws GeneralSecurityException {
+ String curveName = ECCurves.getCurveName(keySize);
+ if (GenericUtils.isEmpty(curveName)) {
+ throw new InvalidKeySpecException("Unknown curve for key size=" + keySize);
+ }
+
+ ECParameterSpec params = ECCurves.getECParameterSpec(curveName);
+ if (params == null) {
+ throw new InvalidKeySpecException("No curve parameters available for " + curveName);
+ }
+
+ KeyPairGenerator gen = getKeyPairGenerator();
+ gen.initialize(params);
+ return gen.generateKeyPair();
+ }
+
+ @Override
+ public KeyPairGenerator getKeyPairGenerator() throws GeneralSecurityException {
+ if (SecurityUtils.hasEcc()) {
+ return SecurityUtils.getKeyPairGenerator("EC");
+ } else {
+ throw new NoSuchProviderException("ECC not supported");
+ }
+ }
+
// see rfc5480 section 2.2
public static final byte ECPOINT_UNCOMPRESSED_FORM_INDICATOR=0x04;
public static final byte ECPOINT_COMPRESSED_VARIANT_2=0x02;