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 <[email protected]> Authored: Sun Dec 24 10:42:22 2017 +0200 Committer: Goldstein Lyor <[email protected]> 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:[email protected]">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:[email protected]">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; }
