This is an automated email from the ASF dual-hosted git repository.

lgoldstein pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit c85261df4e0db3f8015461ec5705a5008e251a9b
Author: Lyor Goldstein <lgoldst...@apache.org>
AuthorDate: Fri Nov 20 20:00:54 2020 +0200

    [SSHD-1104] Added RSA signature variants tests
---
 .../common/config/keys/OpenSshCertificate.java     |   6 +
 .../common/config/keys/OpenSshCertificateImpl.java |   3 +
 .../FileHostKeyCertificateProvider.java            |  27 ++--
 .../keyprovider/HostKeyCertificateProvider.java    |  15 +-
 .../org/apache/sshd/common/util/buffer/Buffer.java |   8 +-
 .../auth/pubkey/RSAVariantsAuthPublicKeyTest.java  | 154 +++++++++++++++++++++
 .../org/apache/sshd/util/test/BaseTestSupport.java |  26 +++-
 .../sshd/scp/client/AbstractScpTestSupport.java    |   4 +-
 8 files changed, 215 insertions(+), 28 deletions(-)

diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificate.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificate.java
index d51db78..90406e4 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificate.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificate.java
@@ -25,6 +25,12 @@ import java.util.Date;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+/**
+ * Represents and OpenSSH certificate key as specified in
+ * <A 
HREF="https://cvsweb.openbsd.org/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD";>PROTOCOL.certkeys</A>
+ *
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
 public interface OpenSshCertificate extends PublicKey, PrivateKey {
     int SSH_CERT_TYPE_USER = 1;
     int SSH_CERT_TYPE_HOST = 2;
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificateImpl.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificateImpl.java
index fb16082..94742f8 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificateImpl.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/config/keys/OpenSshCertificateImpl.java
@@ -26,6 +26,9 @@ import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.NumberUtils;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
 public class OpenSshCertificateImpl implements OpenSshCertificate {
 
     private static final long serialVersionUID = -3592634724148744943L;
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileHostKeyCertificateProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileHostKeyCertificateProvider.java
index c5467f5..05c3ae8 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileHostKeyCertificateProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/FileHostKeyCertificateProvider.java
@@ -30,8 +30,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
-import java.util.stream.StreamSupport;
 
 import org.apache.sshd.common.config.keys.OpenSshCertificate;
 import org.apache.sshd.common.config.keys.PublicKeyEntry;
@@ -62,12 +60,18 @@ public class FileHostKeyCertificateProvider extends 
AbstractLoggingBean implemen
     @Override
     public Iterable<OpenSshCertificate> loadCertificates(SessionContext 
session)
             throws IOException, GeneralSecurityException {
+        Collection<? extends Path> keyPaths = getPaths();
         List<OpenSshCertificate> certificates = new ArrayList<>();
-        for (Path file : getPaths()) {
-            List<String> lines = Files.readAllLines(file, 
StandardCharsets.UTF_8);
+        boolean debugEnabled = log.isDebugEnabled();
+        for (Path file : keyPaths) {
+            if (debugEnabled) {
+                log.debug("loadCertificates({}) loading file {}", session, 
file);
+            }
+
+            Collection<String> lines = Files.readAllLines(file, 
StandardCharsets.UTF_8);
             for (String line : lines) {
                 line = GenericUtils.replaceWhitespaceAndTrim(line);
-                if (GenericUtils.isEmpty(line) || line.startsWith("#")) {
+                if (GenericUtils.isEmpty(line) || (line.charAt(0) == '#')) {
                     continue;
                 }
 
@@ -75,27 +79,20 @@ public class FileHostKeyCertificateProvider extends 
AbstractLoggingBean implemen
                 if (publicKeyEntry == null) {
                     continue;
                 }
+
                 PublicKey publicKey = publicKeyEntry.resolvePublicKey(session, 
null, null);
                 if (publicKey == null) {
                     continue;
                 }
+
                 if (!(publicKey instanceof OpenSshCertificate)) {
                     throw new InvalidKeyException("Got unexpected key type in 
" + file + ". Expected OpenSSHCertificate.");
                 }
+
                 certificates.add((OpenSshCertificate) publicKey);
             }
         }
 
         return certificates;
     }
-
-    @Override
-    public OpenSshCertificate loadCertificate(SessionContext session, String 
keyType)
-            throws IOException, GeneralSecurityException {
-        Iterable<OpenSshCertificate> certificates = loadCertificates(session);
-        return StreamSupport.stream(certificates.spliterator(), false)
-                .filter(pubKey -> Objects.equals(pubKey.getKeyType(), keyType))
-                .findFirst()
-                .orElse(null);
-    }
 }
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/HostKeyCertificateProvider.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/HostKeyCertificateProvider.java
index ab8eba0..0f2ee56 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/HostKeyCertificateProvider.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/keyprovider/HostKeyCertificateProvider.java
@@ -20,13 +20,26 @@ package org.apache.sshd.common.keyprovider;
 
 import java.io.IOException;
 import java.security.GeneralSecurityException;
+import java.util.Objects;
+import java.util.stream.StreamSupport;
 
 import org.apache.sshd.common.config.keys.OpenSshCertificate;
 import org.apache.sshd.common.session.SessionContext;
 
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+@FunctionalInterface
 public interface HostKeyCertificateProvider {
 
     Iterable<OpenSshCertificate> loadCertificates(SessionContext session) 
throws IOException, GeneralSecurityException;
 
-    OpenSshCertificate loadCertificate(SessionContext session, String keyType) 
throws IOException, GeneralSecurityException;
+    default OpenSshCertificate loadCertificate(SessionContext session, String 
keyType)
+            throws IOException, GeneralSecurityException {
+        Iterable<OpenSshCertificate> certificates = loadCertificates(session);
+        return StreamSupport.stream(certificates.spliterator(), false)
+                .filter(pubKey -> Objects.equals(pubKey.getKeyType(), keyType))
+                .findFirst()
+                .orElse(null);
+    }
 }
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java 
b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
index 4a1bfeb..a691a8f 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/buffer/Buffer.java
@@ -764,7 +764,7 @@ public abstract class Buffer implements Readable {
      *      A name-list is represented as a uint32 containing its length 
(number of bytes
      *      that follow) followed by a comma-separated list of zero or more 
names.
      * </CODE>
-     * 
+     *
      * @param names The name list to put
      */
     public void putNameList(Collection<String> names) {
@@ -925,17 +925,21 @@ public abstract class Buffer implements Readable {
             putLong(cert.getSerial());
             putInt(cert.getType());
             putString(cert.getId());
+
             ByteArrayBuffer tmpBuffer = new ByteArrayBuffer();
             tmpBuffer.putStringList(cert.getPrincipals(), false);
             putBytes(tmpBuffer.getCompactData());
+
             putLong(cert.getValidAfter());
             putLong(cert.getValidBefore());
             putNameList(cert.getCriticalOptions());
             putNameList(cert.getExtensions());
             putString(cert.getReserved());
-            tmpBuffer = new ByteArrayBuffer();
+
+            tmpBuffer = new ByteArrayBuffer();  // TODO tmpBuffer.clear() 
instead of allocate new buffer
             tmpBuffer.putRawPublicKey(cert.getCaPubKey());
             putBytes(tmpBuffer.getCompactData());
+
             putBytes(cert.getSignature());
         } else {
             throw new BufferException("Unsupported raw public key algorithm: " 
+ key.getAlgorithm());
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/client/auth/pubkey/RSAVariantsAuthPublicKeyTest.java
 
b/sshd-core/src/test/java/org/apache/sshd/client/auth/pubkey/RSAVariantsAuthPublicKeyTest.java
new file mode 100644
index 0000000..1380e24
--- /dev/null
+++ 
b/sshd-core/src/test/java/org/apache/sshd/client/auth/pubkey/RSAVariantsAuthPublicKeyTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.auth.pubkey;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.sshd.client.SshClient;
+import org.apache.sshd.client.session.ClientSession;
+import org.apache.sshd.common.BaseBuilder;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.kex.KexProposalOption;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.signature.Signature;
+import org.apache.sshd.common.signature.SignatureFactory;
+import org.apache.sshd.server.SshServer;
+import org.apache.sshd.server.auth.hostbased.RejectAllHostBasedAuthenticator;
+import org.apache.sshd.server.auth.password.RejectAllPasswordAuthenticator;
+import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;
+import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
+import org.apache.sshd.util.test.BaseTestSupport;
+import org.apache.sshd.util.test.CoreTestSupportUtils;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+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;
+import org.junit.runners.Parameterized.UseParametersRunnerFactory;
+
+/**
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see 
https://github.com/junit-team/junit/wiki/Parameterized-tests
+@UseParametersRunnerFactory(JUnit4ClassRunnerWithParametersFactory.class)
+public class RSAVariantsAuthPublicKeyTest extends BaseTestSupport {
+    private static final List<NamedFactory<Signature>> RSA_FACTORIES = 
Collections.unmodifiableList(
+            BaseBuilder.DEFAULT_SIGNATURE_PREFERENCE.stream()
+                    .filter(f -> f.getName().contains("rsa"))
+                    .filter(f -> !f.getName().contains("cert"))
+                    .collect(Collectors.toList()));
+    private static final AbstractGeneratorHostKeyProvider KEYS_PROVIDER = new 
SimpleGeneratorHostKeyProvider() {
+        {
+            setAlgorithm(KeyUtils.RSA_ALGORITHM);
+            setKeySize(2048);
+        }
+    };
+
+    private static SshServer sshd;
+    private static int port;
+    private static SshClient client;
+
+    private final SignatureFactory factory;
+
+    public RSAVariantsAuthPublicKeyTest(SignatureFactory factory) {
+        Assume.assumeTrue("Skip unsupported factory", factory.isSupported());
+        this.factory = factory;
+    }
+
+    @BeforeClass
+    public static void setupClientAndServer() throws Exception {
+        sshd = 
CoreTestSupportUtils.setupTestServer(RSAVariantsAuthPublicKeyTest.class);
+        sshd.setSignatureFactories(RSA_FACTORIES);
+        sshd.setKeyPairProvider(KEYS_PROVIDER);
+        sshd.setPasswordAuthenticator(RejectAllPasswordAuthenticator.INSTANCE);
+        
sshd.setHostBasedAuthenticator(RejectAllHostBasedAuthenticator.INSTANCE);
+        sshd.setPublickeyAuthenticator((username, key, session) -> {
+            String keyType = KeyUtils.getKeyType(key);
+            outputDebugMessage("authenticate(%s) keyType=%s session=%s", 
username, keyType, session);
+            return KeyPairProvider.SSH_RSA.equals(keyType);
+        });
+
+        sshd.start();
+        port = sshd.getPort();
+
+        client = 
CoreTestSupportUtils.setupTestClient(RSAVariantsAuthPublicKeyTest.class);
+        client.setServerKeyVerifier((session, peerAddress, key) -> {
+            String keyType = KeyUtils.getKeyType(key);
+            outputDebugMessage("verifyServerKey - keyType=%s session=%s", 
keyType, session);
+            return KeyPairProvider.SSH_RSA.equals(keyType);
+        });
+        client.start();
+    }
+
+    @AfterClass
+    public static void tearDownClientAndServer() throws Exception {
+        if (sshd != null) {
+            try {
+                sshd.stop(true);
+            } finally {
+                sshd = null;
+            }
+        }
+
+        if (client != null) {
+            try {
+                client.stop();
+            } finally {
+                client = null;
+            }
+        }
+    }
+
+    @Parameters(name = "{0}")
+    public static List<Object[]> parameters() {
+        return parameterize(RSA_FACTORIES);
+    }
+
+    @Test
+    public void testRSAVariantAuth() throws IOException {
+        client.setSignatureFactories(Collections.singletonList(factory));
+        try (ClientSession session = createClientSession(client, port)) {
+            List<KeyPair> keys = KEYS_PROVIDER.loadKeys(session);
+            KeyPair kp = keys.get(0);
+            assertEquals("Mismatched key type", KeyPairProvider.SSH_RSA, 
KeyUtils.getKeyType(kp));
+            session.addPublicKeyIdentity(kp);
+            session.auth().verify(AUTH_TIMEOUT);
+
+            String serverKeyType = 
session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);
+            assertEquals("Mismatched host key used", factory.getName(), 
serverKeyType);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + factory + "]";
+    }
+}
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/util/test/BaseTestSupport.java 
b/sshd-core/src/test/java/org/apache/sshd/util/test/BaseTestSupport.java
index 5bc19cc..068a2d8 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/test/BaseTestSupport.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/test/BaseTestSupport.java
@@ -122,18 +122,24 @@ public abstract class BaseTestSupport extends 
JUnitTestSupport {
     }
 
     protected ClientSession createClientSession(SshClient client, int port) 
throws IOException {
-        return client.connect(getCurrentTestName(), TEST_LOCALHOST, port)
+        return createClientSession(getCurrentTestName(), client, port);
+    }
+
+    protected ClientSession createAuthenticatedClientSession(SshClient client, 
int port) throws IOException {
+        return createAuthenticatedClientSession(getCurrentTestName(), client, 
port);
+    }
+
+    public static ClientSession createClientSession(String username, SshClient 
client, int port) throws IOException {
+        return client.connect(username, TEST_LOCALHOST, port)
                 .verify(CONNECT_TIMEOUT)
                 .getSession();
     }
 
-    protected ClientSession createAuthenticatedClientSession(SshClient client, 
int port) throws IOException {
-        ClientSession session = createClientSession(client, port);
+    public static ClientSession createAuthenticatedClientSession(String 
username, SshClient client, int port)
+            throws IOException {
+        ClientSession session = createClientSession(username, client, port);
         try {
-            session.addPasswordIdentity(getCurrentTestName());
-            session.auth().verify(AUTH_TIMEOUT);
-
-            ClientSession authSession = session;
+            ClientSession authSession = 
createAuthenticatedClientSession(session, username);
             session = null;     // avoid auto-close at finally clause
             return authSession;
         } finally {
@@ -143,6 +149,12 @@ public abstract class BaseTestSupport extends 
JUnitTestSupport {
         }
     }
 
+    public static ClientSession createAuthenticatedClientSession(ClientSession 
session, String username) throws IOException {
+        session.addPasswordIdentity(username);
+        session.auth().verify(AUTH_TIMEOUT);
+        return session;
+    }
+
     public static IoServiceFactoryFactory getIoServiceProvider() {
         DefaultIoServiceFactoryFactory factory = 
DefaultIoServiceFactoryFactory.getDefaultIoServiceFactoryFactoryInstance();
         return factory.getIoServiceProvider();
diff --git 
a/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java 
b/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java
index b5f6c87..317e1f5 100644
--- 
a/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java
+++ 
b/sshd-scp/src/test/java/org/apache/sshd/scp/client/AbstractScpTestSupport.java
@@ -143,9 +143,7 @@ public abstract class AbstractScpTestSupport extends 
BaseTestSupport {
     }
 
     protected ClientSession createClientSession() throws IOException {
-        return client.connect(getCurrentTestName(), TEST_LOCALHOST, port)
-                .verify(CONNECT_TIMEOUT)
-                .getSession();
+        return createClientSession(client, port);
     }
 
     protected ClientSession createAuthenticatedClientSession() throws 
IOException {

Reply via email to