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 2017/12/24 08:42:49 UTC

mina-sshd git commit: [SSHD-773] Add support for ed25519 Putty key file

Repository: mina-sshd
Updated Branches:
  refs/heads/master 539893ca6 -> 3d5a8e70f


[SSHD-773] Add support for ed25519 Putty key file


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/3d5a8e70
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/3d5a8e70
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/3d5a8e70

Branch: refs/heads/master
Commit: 3d5a8e70ffd2dc6c37695428acf127d57dbaee66
Parents: 539893c
Author: Goldstein Lyor <ly...@c-b4.com>
Authored: Sun Dec 24 10:42:22 2017 +0200
Committer: Goldstein Lyor <ly...@c-b4.com>
Committed: Sun Dec 24 10:42:37 2017 +0200

----------------------------------------------------------------------
 sshd-contrib/pom.xml                            |  6 ++
 .../keys/loader/putty/ECDSAPuttyKeyDecoder.java | 10 +--
 .../keys/loader/putty/EdDSAPuttyKeyDecoder.java | 68 ++++++++++++++++++++
 .../config/keys/loader/putty/PuttyKeyUtils.java | 25 +++++--
 .../keys/loader/putty/PuttyKeyUtilsTest.java    | 15 ++++-
 .../PuttyKeyUtilsTest-ssh-ed25519-KeyPair.ppk   |  9 +++
 ...ssphrase-AES-256-CBC-ssh-ed25519-KeyPair.ppk |  9 +++
 .../OpenSSHKeyPairResourceParserTest.java       |  2 +-
 .../common/keyprovider/KeyPairProviderTest.java |  6 +-
 .../sshd/common/util/SecurityUtilsTest.java     |  1 -
 10 files changed, 134 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-contrib/pom.xml
----------------------------------------------------------------------
diff --git a/sshd-contrib/pom.xml b/sshd-contrib/pom.xml
index 718dd7e..ac5660a 100644
--- a/sshd-contrib/pom.xml
+++ b/sshd-contrib/pom.xml
@@ -51,6 +51,12 @@
             <artifactId>sshd-core</artifactId>
             <version>${project.version}</version>
         </dependency>
+            <!-- For ed25519 support -->
+        <dependency>
+            <groupId>net.i2p.crypto</groupId>
+            <artifactId>eddsa</artifactId>
+            <optional>true</optional>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.sshd</groupId>

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
index 03bfa6c..a257ff8 100644
--- a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
+++ b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/ECDSAPuttyKeyDecoder.java
@@ -23,7 +23,7 @@ import java.math.BigInteger;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyPair;
-import java.security.NoSuchProviderException;
+import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.interfaces.ECPrivateKey;
@@ -56,16 +56,16 @@ public class ECDSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder<ECPublicKey, E
     @Override
     public Collection<KeyPair> loadKeyPairs(String resourceKey, PuttyKeyReader pubReader, PuttyKeyReader prvReader)
             throws IOException, GeneralSecurityException {
+        if (!SecurityUtils.isECCSupported()) {
+            throw new NoSuchAlgorithmException("ECC not supported for " + resourceKey);
+        }
+
         String keyType = pubReader.readString();
         ECCurves curve = ECCurves.fromKeyType(keyType);
         if (curve == null) {
             throw new InvalidKeySpecException("Not an EC curve name: " + keyType);
         }
 
-        if (!SecurityUtils.isECCSupported()) {
-            throw new NoSuchProviderException("ECC not supported");
-        }
-
         String encCurveName = pubReader.readString();
         String keyCurveName = curve.getName();
         if (!keyCurveName.equals(encCurveName)) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/EdDSAPuttyKeyDecoder.java
----------------------------------------------------------------------
diff --git a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/EdDSAPuttyKeyDecoder.java b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/EdDSAPuttyKeyDecoder.java
new file mode 100644
index 0000000..bd2662c
--- /dev/null
+++ b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/EdDSAPuttyKeyDecoder.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sshd.common.config.keys.loader.putty;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Collection;
+import java.util.Collections;
+
+import net.i2p.crypto.eddsa.EdDSAPrivateKey;
+import net.i2p.crypto.eddsa.EdDSAPublicKey;
+
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.common.util.security.eddsa.EdDSASecurityProviderUtils;
+
+/**
+ * TODO Add javadoc
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class EdDSAPuttyKeyDecoder extends AbstractPuttyKeyDecoder<EdDSAPublicKey, EdDSAPrivateKey> {
+    public static final EdDSAPuttyKeyDecoder INSTANCE = new EdDSAPuttyKeyDecoder();
+
+    public EdDSAPuttyKeyDecoder() {
+        super(EdDSAPublicKey.class, EdDSAPrivateKey.class, Collections.singletonList(KeyPairProvider.SSH_ED25519));
+    }
+
+    @Override
+    public Collection<KeyPair> loadKeyPairs(String resourceKey, PuttyKeyReader pubReader, PuttyKeyReader prvReader)
+            throws IOException, GeneralSecurityException {
+        if (!SecurityUtils.isEDDSACurveSupported()) {
+            throw new NoSuchAlgorithmException(SecurityUtils.EDDSA + " provider not supported for " + resourceKey);
+        }
+
+        String keyType = pubReader.readString();
+        if (!KeyPairProvider.SSH_ED25519.equals(keyType)) {
+            throw new InvalidKeySpecException("Not an " + SecurityUtils.EDDSA + " key: " + keyType);
+        }
+
+        byte[] seed = pubReader.read();
+        PublicKey pubKey = EdDSASecurityProviderUtils.generateEDDSAPublicKey(seed);
+        seed = prvReader.read();
+        PrivateKey prvKey = EdDSASecurityProviderUtils.generateEDDSAPrivateKey(seed);
+        return Collections.singletonList(new KeyPair(pubKey, prvKey));
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
----------------------------------------------------------------------
diff --git a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
index a3b4745..ee2851b 100644
--- a/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
+++ b/sshd-contrib/src/main/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtils.java
@@ -19,7 +19,7 @@
 
 package org.apache.sshd.common.config.keys.loader.putty;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
@@ -27,17 +27,30 @@ import java.util.NavigableMap;
 import java.util.TreeMap;
 
 import org.apache.sshd.common.config.keys.loader.KeyPairResourceParser;
+import org.apache.sshd.common.util.security.SecurityUtils;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public final class PuttyKeyUtils {
     public static final List<PuttyKeyPairResourceParser<?, ?>> DEFAULT_PARSERS =
-            Collections.unmodifiableList(
-                    Arrays.asList(
-                            RSAPuttyKeyDecoder.INSTANCE,
-                            DSSPuttyKeyDecoder.INSTANCE,
-                            ECDSAPuttyKeyDecoder.INSTANCE));
+            Collections.unmodifiableList(new ArrayList<PuttyKeyPairResourceParser<?, ?>>() {
+                // Not serializing it
+                private static final long serialVersionUID = 1L;
+
+                {
+                    add(RSAPuttyKeyDecoder.INSTANCE);
+                    add(DSSPuttyKeyDecoder.INSTANCE);
+
+                    if (SecurityUtils.isECCSupported()) {
+                        add(ECDSAPuttyKeyDecoder.INSTANCE);
+                    }
+
+                    if (SecurityUtils.isEDDSACurveSupported()) {
+                        add(EdDSAPuttyKeyDecoder.INSTANCE);
+                    }
+                }
+            });
 
     public static final NavigableMap<String, PuttyKeyPairResourceParser<?, ?>> BY_KEY_TYPE =
             Collections.unmodifiableNavigableMap(

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java b/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
index 5ab953a..3f3d385 100644
--- a/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
+++ b/sshd-contrib/src/test/java/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest.java
@@ -30,6 +30,8 @@ import java.util.List;
 
 import org.apache.sshd.common.cipher.BuiltinCiphers;
 import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.PrivateKeyEntryDecoder;
+import org.apache.sshd.common.config.keys.loader.openssh.OpenSSHKeyPairResourceParser;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.util.test.BaseTestSupport;
@@ -123,7 +125,7 @@ public class PuttyKeyUtilsTest extends BaseTestSupport {
         assertLoadedKeyPair(encryptedFile, keys.iterator().next());
     }
 
-    private void assertLoadedKeyPair(String prefix, KeyPair kp) {
+    private void assertLoadedKeyPair(String prefix, KeyPair kp) throws GeneralSecurityException {
         assertNotNull(prefix + ": no key pair loaded", kp);
 
         PublicKey pubKey = kp.getPublic();
@@ -133,5 +135,16 @@ public class PuttyKeyUtilsTest extends BaseTestSupport {
         PrivateKey prvKey = kp.getPrivate();
         assertNotNull(prefix + ": no private key loaded", prvKey);
         assertEquals(prefix + ": mismatched private key type", keyType, KeyUtils.getKeyType(prvKey));
+
+        @SuppressWarnings("rawtypes")
+        PrivateKeyEntryDecoder decoder =
+            OpenSSHKeyPairResourceParser.getPrivateKeyEntryDecoder(prvKey);
+        assertNotNull("No private key decoder", decoder);
+
+        if (decoder.isPublicKeyRecoverySupported()) {
+            @SuppressWarnings("unchecked")
+            PublicKey recKey = decoder.recoverPublicKey(prvKey);
+            assertKeyEquals("Mismatched recovered public key", pubKey, recKey);
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ssh-ed25519-KeyPair.ppk
----------------------------------------------------------------------
diff --git a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ssh-ed25519-KeyPair.ppk b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ssh-ed25519-KeyPair.ppk
new file mode 100644
index 0000000..614ac69
--- /dev/null
+++ b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/PuttyKeyUtilsTest-ssh-ed25519-KeyPair.ppk
@@ -0,0 +1,9 @@
+PuTTY-User-Key-File-2: ssh-ed25519
+Encryption: none
+Comment: ed25519-key-20170917
+Public-Lines: 2
+AAAAC3NzaC1lZDI1NTE5AAAAIN7fuKSIM5TbAX/1I1Ts3tfyo5eEs7JpmKsegHs/
+9fIi
+Private-Lines: 1
+AAAAIADKJJPxsUp7JXLzm1zwk8UswW/lkiwPJ73CbqGvalgP
+Private-MAC: 28a22234152feaf1d9a6a10ca0ae3a51b5e6dd52

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ssh-ed25519-KeyPair.ppk
----------------------------------------------------------------------
diff --git a/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ssh-ed25519-KeyPair.ppk b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ssh-ed25519-KeyPair.ppk
new file mode 100644
index 0000000..668ef1e
--- /dev/null
+++ b/sshd-contrib/src/test/resources/org/apache/sshd/common/config/keys/loader/putty/super-secret-passphrase-AES-256-CBC-ssh-ed25519-KeyPair.ppk
@@ -0,0 +1,9 @@
+PuTTY-User-Key-File-2: ssh-ed25519
+Encryption: aes256-cbc
+Comment: ed25519-key-20170917
+Public-Lines: 2
+AAAAC3NzaC1lZDI1NTE5AAAAIN7fuKSIM5TbAX/1I1Ts3tfyo5eEs7JpmKsegHs/
+9fIi
+Private-Lines: 1
+0cPG5BR80jQcJmHKs6IjpHS3R4/CTnudnJB4BcjaqKlRk0l603GVMDzTxkaICCb8
+Private-MAC: 381cff136b2516331ff4511cf382533fc14f0aeb

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java
index b18564a..c45f89d 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/config/keys/loader/openssh/OpenSSHKeyPairResourceParserTest.java
@@ -92,7 +92,7 @@ public class OpenSSHKeyPairResourceParserTest extends BaseTestSupport {
             PrivateKey prvKey = ValidateUtils.checkInstanceOf(kp.getPrivate(), prvType, "Mismatched private key type");
             @SuppressWarnings("rawtypes")
             PrivateKeyEntryDecoder decoder =
-                    OpenSSHKeyPairResourceParser.getPrivateKeyEntryDecoder(prvKey);
+                OpenSSHKeyPairResourceParser.getPrivateKeyEntryDecoder(prvKey);
             assertNotNull("No private key decoder", decoder);
 
             if (decoder.isPublicKeyRecoverySupported()) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-core/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java b/sshd-core/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java
index 463045c..7e3775b 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/keyprovider/KeyPairProviderTest.java
@@ -55,9 +55,9 @@ public class KeyPairProviderTest extends BaseTestSupport {
 
     @Test
     public void testMapToKeyPairProvider() {
-        final PublicKey pubKey = Mockito.mock(PublicKey.class);
-        final PrivateKey prvKey = Mockito.mock(PrivateKey.class);
-        final String[] testKeys = {getCurrentTestName(), getClass().getSimpleName()};
+        PublicKey pubKey = Mockito.mock(PublicKey.class);
+        PrivateKey prvKey = Mockito.mock(PrivateKey.class);
+        String[] testKeys = {getCurrentTestName(), getClass().getSimpleName()};
         Map<String, KeyPair> pairsMap = GenericUtils.toSortedMap(
             Arrays.asList(testKeys),
             Function.identity(),

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3d5a8e70/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
index a3dec7a..8bd2129 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/SecurityUtilsTest.java
@@ -160,7 +160,6 @@ public class SecurityUtilsTest extends BaseTestSupport {
         Class<?> clazz = getClass();
         Package pkg = clazz.getPackage();
         KeyPair kpResource = testLoadPrivateKeyResource(pkg.getName().replace('.', '/') + "/" + name, pubType, prvType);
-
         assertTrue(name + ": Mismatched key file vs. resource values", KeyUtils.compareKeyPairs(kpFile, kpResource));
         return kpResource;
     }