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 5b38e8124e6c59beb8c11a6939f57b5ec9b819a4
Author: Thomas Wolf <thomas.w...@paranor.ch>
AuthorDate: Fri May 22 07:51:24 2020 +0300

    [SSHD-997] Fixed OpenSSH ed25519 private key decoder
---
 .../OpenSSHEd25519PrivateKeyEntryDecoder.java      |  11 +-
 .../openssh/OpenSSHKeyPairResourceWriterTest.java  | 135 ++++++++++++++++++---
 2 files changed, 123 insertions(+), 23 deletions(-)

diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
index 5e72064..b4cd0f6 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/util/security/eddsa/OpenSSHEd25519PrivateKeyEntryDecoder.java
@@ -101,15 +101,8 @@ public class OpenSSHEd25519PrivateKeyEntryDecoder extends 
AbstractPrivateKeyEntr
             }
 
             byte[] sk = Arrays.copyOf(keypair, SK_SIZE);
-            EdDSAPrivateKey privateKey;
-            try {
-                // create the private key
-                EdDSAParameterSpec params = 
EdDSANamedCurveTable.getByName(EdDSASecurityProviderUtils.CURVE_ED25519_SHA512);
-                privateKey = generatePrivateKey(new EdDSAPrivateKeySpec(sk, 
params));
-            } finally {
-                // get rid of sensitive data a.s.a.p
-                Arrays.fill(sk, (byte) 0);
-            }
+            EdDSAParameterSpec params = 
EdDSANamedCurveTable.getByName(EdDSASecurityProviderUtils.CURVE_ED25519_SHA512);
+            EdDSAPrivateKey privateKey = generatePrivateKey(new 
EdDSAPrivateKeySpec(sk, params));
 
             // the private key class contains the calculated public key (Abyte)
             // pointers to the corresponding code:
diff --git 
a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriterTest.java
 
b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriterTest.java
index 050615a..f3c03e2 100644
--- 
a/sshd-common/src/test/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriterTest.java
+++ 
b/sshd-common/src/test/java/org/apache/sshd/common/config/keys/writer/openssh/OpenSSHKeyPairResourceWriterTest.java
@@ -38,9 +38,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
-import java.util.Objects;
 
-import net.i2p.crypto.eddsa.EdDSAKey;
 import net.i2p.crypto.eddsa.spec.EdDSAGenParameterSpec;
 import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
 import org.apache.sshd.common.config.keys.FilePasswordProvider;
@@ -130,14 +128,6 @@ public class OpenSSHKeyPairResourceWriterTest extends 
JUnitTestSupport {
     }
 
     private boolean compare(KeyPair a, KeyPair b) {
-        if ("EDDSA".equals(data.algorithm)) {
-            // Bug in net.i2p.crypto.eddsa and in sshd? Both also compare the
-            // seed of the private key, but for a generated key, this is some
-            // random value, while it is all zeroes for a key read from a file.
-            return KeyUtils.compareKeys(a.getPublic(), b.getPublic())
-                    && Objects.equals(((EdDSAKey) a.getPrivate()).getParams(),
-                            ((EdDSAKey) b.getPrivate()).getParams());
-        }
         // Compares both public and private keys.
         return KeyUtils.compareKeyPairs(a, b);
     }
@@ -156,6 +146,115 @@ public class OpenSSHKeyPairResourceWriterTest extends 
JUnitTestSupport {
     }
 
     @Test
+    public void testFileRoundtripNoEncryption() throws Exception {
+        Path tmp = getTemporaryOutputFile();
+        try (SecureByteArrayOutputStream out = new 
SecureByteArrayOutputStream()) {
+            OpenSSHKeyPairResourceWriter.INSTANCE.writePrivateKey(testKey, "a 
comment", null, out);
+            writeToFile(tmp, out.toByteArray());
+        }
+        try (InputStream in = Files.newInputStream(tmp)) {
+            KeyPair key = SecurityUtils.loadKeyPairIdentities(null,
+                    new PathResource(tmp), in, null).iterator().next();
+            assertNotNull("No key pair parsed", key);
+            assertKeyPairEquals("Mismatched recovered keys", testKey, key);
+            assertTrue("Keys should be equal", compare(key, testKey));
+            Path tmp2 = getTemporaryOutputFile("again");
+            try (SecureByteArrayOutputStream out = new 
SecureByteArrayOutputStream()) {
+                OpenSSHKeyPairResourceWriter.INSTANCE.writePrivateKey(key, "a 
comment", null, out);
+                writeToFile(tmp2, out.toByteArray());
+            }
+            try (InputStream in2 = Files.newInputStream(tmp2)) {
+                KeyPair key2 = SecurityUtils.loadKeyPairIdentities(null,
+                        new PathResource(tmp2), in2, null).iterator().next();
+                assertNotNull("No key pair parsed", key2);
+                assertKeyPairEquals("Mismatched recovered keys", testKey, 
key2);
+                assertTrue("Keys should be equal", compare(key2, testKey));
+
+                assertKeyPairEquals("Mismatched recovered keys", key, key2);
+                assertTrue("Keys should be equal", compare(key2, key));
+            }
+        }
+    }
+
+    @Test
+    public void testFileRoundtripWithEncryption() throws Exception {
+        Path tmp = getTemporaryOutputFile();
+        try (SecureByteArrayOutputStream out = new 
SecureByteArrayOutputStream()) {
+            OpenSSHKeyEncryptionContext options = new 
OpenSSHKeyEncryptionContext();
+            options.setPassword("nonsense");
+            options.setCipherName("AES");
+            options.setCipherMode("CTR");
+            options.setCipherType("256");
+            OpenSSHKeyPairResourceWriter.INSTANCE.writePrivateKey(testKey, "a 
comment", options, out);
+            writeToFile(tmp, out.toByteArray());
+        }
+        try (InputStream in = Files.newInputStream(tmp)) {
+            KeyPair key = SecurityUtils.loadKeyPairIdentities(null,
+                    new PathResource(tmp), in, 
FilePasswordProvider.of("nonsense")).iterator().next();
+            assertNotNull("No key pair parsed", key);
+            assertKeyPairEquals("Mismatched recovered keys", testKey, key);
+            assertTrue("Keys should be equal", compare(key, testKey));
+            Path tmp2 = getTemporaryOutputFile("again");
+            try (SecureByteArrayOutputStream out = new 
SecureByteArrayOutputStream()) {
+                OpenSSHKeyEncryptionContext options = new 
OpenSSHKeyEncryptionContext();
+                options.setPassword("nonsense");
+                options.setCipherName("AES");
+                options.setCipherMode("CTR");
+                options.setCipherType("256");
+                OpenSSHKeyPairResourceWriter.INSTANCE.writePrivateKey(key, "a 
comment", options, out);
+                writeToFile(tmp2, out.toByteArray());
+            }
+            try (InputStream in2 = Files.newInputStream(tmp2)) {
+                KeyPair key2 = SecurityUtils.loadKeyPairIdentities(null,
+                        new PathResource(tmp2), in2, 
FilePasswordProvider.of("nonsense")).iterator().next();
+                assertNotNull("No key pair parsed", key2);
+                assertKeyPairEquals("Mismatched recovered keys", testKey, 
key2);
+                assertTrue("Keys should be equal", compare(key2, testKey));
+
+                assertKeyPairEquals("Mismatched recovered keys", key, key2);
+                assertTrue("Keys should be equal", compare(key2, key));
+            }
+        }
+    }
+
+    @Test
+    public void testFileRoundtripAsymmetric() throws Exception {
+        // Write first unencrypted, then encrypted. read both and compare.
+        Path tmp = getTemporaryOutputFile();
+        try (SecureByteArrayOutputStream out = new 
SecureByteArrayOutputStream()) {
+            OpenSSHKeyPairResourceWriter.INSTANCE.writePrivateKey(testKey, "a 
comment", null, out);
+            writeToFile(tmp, out.toByteArray());
+        }
+        try (InputStream in = Files.newInputStream(tmp)) {
+            KeyPair key = SecurityUtils.loadKeyPairIdentities(null,
+                    new PathResource(tmp), in, null).iterator().next();
+            assertNotNull("No key pair parsed", key);
+            assertKeyPairEquals("Mismatched recovered keys", testKey, key);
+            assertTrue("Keys should be equal", compare(key, testKey));
+            Path tmp2 = getTemporaryOutputFile("again");
+            try (SecureByteArrayOutputStream out = new 
SecureByteArrayOutputStream()) {
+                OpenSSHKeyEncryptionContext options = new 
OpenSSHKeyEncryptionContext();
+                options.setPassword("nonsense");
+                options.setCipherName("AES");
+                options.setCipherMode("CTR");
+                options.setCipherType("256");
+                OpenSSHKeyPairResourceWriter.INSTANCE.writePrivateKey(key, "a 
comment", options, out);
+                writeToFile(tmp2, out.toByteArray());
+            }
+            try (InputStream in2 = Files.newInputStream(tmp2)) {
+                KeyPair key2 = SecurityUtils.loadKeyPairIdentities(null,
+                        new PathResource(tmp2), in2, 
FilePasswordProvider.of("nonsense")).iterator().next();
+                assertNotNull("No key pair parsed", key2);
+                assertKeyPairEquals("Mismatched recovered keys", testKey, 
key2);
+                assertTrue("Keys should be equal", compare(key2, testKey));
+
+                assertKeyPairEquals("Mismatched recovered keys", key, key2);
+                assertTrue("Keys should be equal", compare(key2, key));
+            }
+        }
+    }
+
+    @Test
     public void testWritePrivateKeyNoEncryption() throws Exception {
         Path tmp = getTemporaryOutputFile();
         try (SecureByteArrayOutputStream out = new 
SecureByteArrayOutputStream()) {
@@ -330,22 +429,30 @@ public class OpenSSHKeyPairResourceWriterTest extends 
JUnitTestSupport {
         checkPublicKey(tmp, null);
     }
 
-    private Path getTemporaryOutputFile() throws IOException {
+    private Path getTemporaryOutputFile(String suffix) throws IOException {
         Path dir = createTempClassFolder();
         String testName = getCurrentTestName();
         int pos = testName.indexOf('[');
-        Path file;
+        String fileName;
         if (pos > 0) {
             String baseName = testName.substring(0, pos);
             String paramName = testName.substring(pos + 1, testName.length() - 
1);
-            file = dir.resolve(baseName + "-" + paramName.replace('(', 
'-').replace(")", "").trim());
+            fileName = baseName + "-" + paramName.replace('(', 
'-').replace(")", "").trim();
         } else {
-            file = dir.resolve(testName);
+            fileName = testName;
         }
+        if (suffix != null) {
+            fileName += suffix;
+        }
+        Path file = dir.resolve(fileName);
         Files.deleteIfExists(file);
         return file;
     }
 
+    private Path getTemporaryOutputFile() throws IOException {
+        return getTemporaryOutputFile(null);
+    }
+
     @SuppressWarnings("checkstyle:VisibilityModifier")
     private static class TestData {
         public final String algorithm;

Reply via email to