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 2018/11/18 04:55:07 UTC

[12/12] mina-sshd git commit: [SSHD-864] Replaced BC deprecated PEMWriter with JCAPemWriter in BouncyCastleGeneratorHostKeyProvider

[SSHD-864] Replaced BC deprecated PEMWriter with JCAPemWriter in BouncyCastleGeneratorHostKeyProvider


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

Branch: refs/heads/master
Commit: 025df0e85655c83d99a585a620479b2a44287cb2
Parents: 895f30f
Author: Lyor Goldstein <lg...@apache.org>
Authored: Thu Nov 15 16:18:51 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Sun Nov 18 06:54:48 2018 +0200

----------------------------------------------------------------------
 .../BouncyCastleGeneratorHostKeyProvider.java   |  28 +++-
 .../AbstractGeneratorHostKeyProvider.java       |   4 +-
 ...ouncyCastleGeneratorHostKeyProviderTest.java | 140 +++++++++++++++++++
 3 files changed, 166 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/025df0e8/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java b/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java
index 534b033..cee48bd 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProvider.java
@@ -22,12 +22,16 @@ import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
 import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 
 import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;
+import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -37,11 +41,27 @@ public class BouncyCastleGeneratorHostKeyProvider extends AbstractGeneratorHostK
         setPath(path);
     }
 
-    @SuppressWarnings("deprecation")
     @Override
-    protected void doWriteKeyPair(NamedResource resourceKey, KeyPair kp, OutputStream outputStream) throws IOException, GeneralSecurityException {
-        try (org.bouncycastle.openssl.PEMWriter w =
-                     new org.bouncycastle.openssl.PEMWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {
+    protected void doWriteKeyPair(NamedResource resourceKey, KeyPair kp, OutputStream outputStream)
+            throws IOException, GeneralSecurityException {
+        writePEMKeyPair(kp, outputStream);
+    }
+
+    public static void writePEMKeyPair(KeyPair kp, Path targetPath) throws IOException {
+        writePEMKeyPair(kp, targetPath, IoUtils.EMPTY_OPEN_OPTIONS);
+    }
+
+    public static void writePEMKeyPair(
+            KeyPair kp, Path targetPath, OpenOption... options)
+                throws IOException {
+        try (OutputStream os = Files.newOutputStream(targetPath, options)) {
+            writePEMKeyPair(kp, os);
+        }
+    }
+
+    public static void writePEMKeyPair(KeyPair kp, OutputStream outputStream) throws IOException {
+        try (JcaPEMWriter w = new JcaPEMWriter(
+                new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {
             w.writeObject(kp);
             w.flush();
         }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/025df0e8/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java b/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
index be4ceb5..287abec 100644
--- a/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
+++ b/sshd-common/src/main/java/org/apache/sshd/server/keyprovider/AbstractGeneratorHostKeyProvider.java
@@ -118,7 +118,7 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr
         if ((kp != null) & log.isDebugEnabled()) {
             PublicKey key = kp.getPublic();
             log.debug("clearLoadedKeys({}) removed key={}-{}",
-                      getPath(), KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key));
+                  getPath(), KeyUtils.getKeyType(key), KeyUtils.getFingerPrint(key));
         }
     }
 
@@ -162,7 +162,7 @@ public abstract class AbstractGeneratorHostKeyProvider extends AbstractKeyPairPr
                 }
             } catch (Throwable e) {
                 log.warn("resolveKeyPair({}) Failed ({}) to load: {}",
-                        keyPath, e.getClass().getSimpleName(), e.getMessage());
+                    keyPath, e.getClass().getSimpleName(), e.getMessage());
                 if (log.isDebugEnabled()) {
                     log.debug("resolveKeyPair(" + keyPath + ") load failure details", e);
                 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/025df0e8/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java
new file mode 100644
index 0000000..3bca2e2
--- /dev/null
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/security/bouncycastle/BouncyCastleGeneratorHostKeyProviderTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.util.security.bouncycastle;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sshd.common.cipher.ECCurves;
+import org.apache.sshd.common.config.keys.BuiltinIdentities;
+import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.util.security.SecurityUtils;
+import org.apache.sshd.server.keyprovider.AbstractGeneratorHostKeyProvider;
+import org.apache.sshd.util.test.JUnit4ClassRunnerWithParametersFactory;
+import org.apache.sshd.util.test.JUnitTestSupport;
+import org.apache.sshd.util.test.NoIoTestCase;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+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:dev@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)
+@Category({ NoIoTestCase.class })
+public class BouncyCastleGeneratorHostKeyProviderTest extends JUnitTestSupport {
+    private final String keyType;
+    private final int keySize;
+
+    public BouncyCastleGeneratorHostKeyProviderTest(String keyType, int keySize) {
+        this.keyType = keyType;
+        this.keySize = keySize;
+    }
+
+    @Parameters(name = "{0} / {1}")
+    public static List<Object[]> parameters() {
+        if (!SecurityUtils.isBouncyCastleRegistered()) {
+            return Collections.emptyList();
+        }
+
+        List<Object[]> params = new ArrayList<>();
+        for (Integer ks : RSA_SIZES) {
+            params.add(new Object[]{BuiltinIdentities.Constants.RSA, ks});
+        }
+        for (Integer ks : DSS_SIZES) {
+            params.add(new Object[]{BuiltinIdentities.Constants.DSA, ks});
+        }
+
+/* TODO - causes an issue where BC cannot parse its own file
+        if (SecurityUtils.isECCSupported()) {
+            for (ECCurves curve : ECCurves.VALUES) {
+                params.add(new Object[]{BuiltinIdentities.Constants.ECDSA, curve.getKeySize()});
+            }
+        }
+*/
+        return params;
+    }
+
+    @Test
+    public void testKeyReadWrite() throws IOException, GeneralSecurityException {
+        KeyPair expected;
+        if (BuiltinIdentities.Constants.RSA.equalsIgnoreCase(keyType)) {
+            expected = KeyUtils.generateKeyPair(KeyPairProvider.SSH_RSA, keySize);
+        } else if (BuiltinIdentities.Constants.DSA.equalsIgnoreCase(keyType)) {
+            expected = KeyUtils.generateKeyPair(KeyPairProvider.SSH_DSS, keySize);
+        } else if (BuiltinIdentities.Constants.ECDSA.equalsIgnoreCase(keyType)) {
+            ECCurves curve = ECCurves.fromCurveSize(keySize);
+            assertNotNull("No curve for key size=" + keySize, curve);
+            expected = KeyUtils.generateKeyPair(curve.getKeyType(), curve.getKeySize());
+        } else if (BuiltinIdentities.Constants.ED25519.equalsIgnoreCase(keyType)) {
+            KeyPairGenerator g = SecurityUtils.getKeyPairGenerator(SecurityUtils.EDDSA);
+            expected = g.generateKeyPair();
+        } else {
+            throw new InvalidKeyException("Unsupported key type: " + keyType);
+        }
+
+        PublicKey key = expected.getPublic();
+        String keyAlgorithm = key.getAlgorithm();
+        if (BuiltinIdentities.Constants.ECDSA.equalsIgnoreCase(keyAlgorithm)) {
+            keyAlgorithm = KeyUtils.EC_ALGORITHM;
+        } else if (BuiltinIdentities.Constants.ED25519.equalsIgnoreCase(keyAlgorithm)) {
+            keyAlgorithm = SecurityUtils.EDDSA;
+        }
+
+        Path dir = getTempTargetFolder();
+        dir = Files.createDirectories(dir.resolve(getClass().getSimpleName()));
+        Path file = dir.resolve(keyType + "-" + keySize + ".pem");
+        BouncyCastleGeneratorHostKeyProvider.writePEMKeyPair(expected, file);
+
+        AbstractGeneratorHostKeyProvider provider = new BouncyCastleGeneratorHostKeyProvider(file);
+        provider.setAlgorithm(keyAlgorithm);
+
+        Iterable<KeyPair> keys = provider.loadKeys(null);
+        KeyPair actual = null;
+        for (KeyPair k : keys) {
+            assertNull("Unexpected multiple keys loaded", actual);
+            actual = k;
+        }
+
+        assertKeyPairEquals(keyType + "/" + keySize, expected, actual);
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + keyType + "/" + keySize + "]";
+    }
+}