You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2019/08/17 05:27:56 UTC

[karaf] branch master updated: KARAF-6383 - Replace not-yet-commons-ssl with BouncyCastle

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

jbonofre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/karaf.git


The following commit(s) were added to refs/heads/master by this push:
     new 5342bfe  KARAF-6383 - Replace not-yet-commons-ssl with BouncyCastle
     new bf6ded2  Merge pull request #910 from coheigea/KARAF-6383
5342bfe is described below

commit 5342bfefaa43935bd6de3556cd5769a32390621b
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Fri Aug 16 16:28:52 2019 +0100

    KARAF-6383 - Replace not-yet-commons-ssl with BouncyCastle
---
 assemblies/features/standard/pom.xml               |  12 ++-
 .../features/standard/src/main/feature/feature.xml |   3 +-
 .../apache/karaf/features/internal/service/f01.xml |   3 +-
 .../apache/karaf/features/internal/service/f02.xml |   3 +-
 itests/test/pom.xml                                |  12 ++-
 .../src/test/filtered-resources/etc/feature.xml    |   3 +-
 .../test/java/org/apache/karaf/itests/WebTest.java |   6 +-
 .../apache/karaf/itests/ssh/SshKeyFormatTest.java  |  29 ++++-
 pom.xml                                            |   1 +
 shell/ssh/pom.xml                                  |  13 ++-
 .../shell/ssh/keygenerator/KeyPairLoader.java      | 118 +++++++++++++++++++++
 .../ssh/keygenerator/OpenSSHKeyPairProvider.java   |   8 +-
 .../karaf/shell/ssh/keygenerator/PemWriter.java    |  23 ++--
 .../OpenSSHGeneratorKeyFileProviderTest.java       |   6 +-
 14 files changed, 192 insertions(+), 48 deletions(-)

diff --git a/assemblies/features/standard/pom.xml b/assemblies/features/standard/pom.xml
index e4d8a4e..82f4e6b 100644
--- a/assemblies/features/standard/pom.xml
+++ b/assemblies/features/standard/pom.xml
@@ -315,9 +315,15 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.not-yet-commons-ssl</artifactId>
-            <version>0.3.11_1</version>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <version>${bouncycastle.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+            <version>${bouncycastle.version}</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/assemblies/features/standard/src/main/feature/feature.xml b/assemblies/features/standard/src/main/feature/feature.xml
index 8bb69fa..0dd524d 100644
--- a/assemblies/features/standard/src/main/feature/feature.xml
+++ b/assemblies/features/standard/src/main/feature/feature.xml
@@ -1018,7 +1018,8 @@ realm=karaf
         <feature>shell</feature>
         <feature>jaas</feature>
         <bundle start-level="30">mvn:org.apache.sshd/sshd-core/${sshd.version}</bundle>
-        <bundle start-level="30">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.not-yet-commons-ssl/0.3.11_1</bundle>
+        <bundle start-level="30">mvn:org.bouncycastle/bcprov-jdk15on/${bouncycastle.version}</bundle>
+        <bundle start-level="30">mvn:org.bouncycastle/bcpkix-jdk15on/${bouncycastle.version}</bundle>
         <bundle start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/${project.version}</bundle>
     </feature>
 
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
index 63747c6..74804b8 100644
--- a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f01.xml
@@ -83,7 +83,8 @@
         <bundle>mvn:org.apache.mina/mina-core/2.0.0-RC1</bundle>
         <bundle>mvn:org.apache.sshd/sshd-core/0.4.0</bundle>
         <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/2.0.0</bundle>
-        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.not-yet-commons-ssl/0.3.11_1</bundle>
+        <bundle>mvn:org.bouncycastle/bcprov-jdk15on/1.62</bundle>
+        <bundle>mvn:org.bouncycastle/bcpkix-jdk15on/1.62</bundle>
     </feature>
     <feature name="management" version="2.0.0">
         <bundle>mvn:org.apache.karaf/org.apache.karaf.management/2.0.0</bundle>
diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
index b8fb77c..825d4a0 100644
--- a/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
+++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/f02.xml
@@ -145,7 +145,8 @@
         </config>
         <bundle dependency='true'>mvn:org.apache.mina/mina-core/2.0.1</bundle>
         <bundle dependency='true'>mvn:org.apache.sshd/sshd-core/0.5.0</bundle>
-        <bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.not-yet-commons-ssl/0.3.11_1</bundle>
+        <bundle>mvn:org.bouncycastle/bcprov-jdk15on/1.62</bundle>
+        <bundle>mvn:org.bouncycastle/bcpkix-jdk15on/1.62</bundle>
         <bundle>mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/2.2.0</bundle>
     </feature>
     <feature name="management" version="2.2.0">
diff --git a/itests/test/pom.xml b/itests/test/pom.xml
index d56b7c5..a82e488 100644
--- a/itests/test/pom.xml
+++ b/itests/test/pom.xml
@@ -177,10 +177,16 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.not-yet-commons-ssl</artifactId>
-            <version>0.3.11_1</version>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <scope>test</scope>
+            <version>${bouncycastle.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
             <scope>test</scope>
+            <version>${bouncycastle.version}</version>
         </dependency>
 
         <dependency>
diff --git a/itests/test/src/test/filtered-resources/etc/feature.xml b/itests/test/src/test/filtered-resources/etc/feature.xml
index 3197680..916a782 100644
--- a/itests/test/src/test/filtered-resources/etc/feature.xml
+++ b/itests/test/src/test/filtered-resources/etc/feature.xml
@@ -682,7 +682,8 @@
         <feature>shell</feature>
         <feature>jaas</feature>
         <bundle start="true" start-level="30">mvn:org.apache.sshd/sshd-core/${sshd.version}</bundle>
-        <bundle start="true" start-level="30">mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.not-yet-commons-ssl/0.3.11_1</bundle>
+        <bundle start="true" start-level="30">mvn:org.bouncycastle/bcprov-jdk15on/${bouncycastle.version}</bundle>
+        <bundle start="true" start-level="30">mvn:org.bouncycastle/bcpkix-jdk15on/${bouncycastle.version}</bundle>
         <bundle start="true" start-level="30">mvn:org.apache.karaf.shell/org.apache.karaf.shell.ssh/${project.version}</bundle>
     </feature>
 
diff --git a/itests/test/src/test/java/org/apache/karaf/itests/WebTest.java b/itests/test/src/test/java/org/apache/karaf/itests/WebTest.java
index 246072e..c663f04 100644
--- a/itests/test/src/test/java/org/apache/karaf/itests/WebTest.java
+++ b/itests/test/src/test/java/org/apache/karaf/itests/WebTest.java
@@ -41,7 +41,7 @@ public class WebTest extends KarafTestSupport {
     public void installWarFeature() throws Exception {
         installAndAssertFeature("war");
     }
-    
+
     @Test
     public void listCommand() throws Exception {
         String listOutput = executeCommand("web:list");
@@ -81,7 +81,9 @@ public class WebTest extends KarafTestSupport {
         System.out.println(buffer.toString());
         assertContains("Hello World!", buffer.toString());
 
-        System.out.println(executeCommand("web:uninstall 124"));
+        String name = "mvn_org.apache.karaf.examples_karaf-war-example-webapp_" + System.getProperty("karaf.version") + "_war";
+        String bundleId = executeCommand("bundle:id " + name);
+        System.out.println(executeCommand("web:uninstall " + bundleId));
         listOutput = executeCommand("web:list");
         System.out.println(listOutput);
         while (listOutput.contains("/test")) {
diff --git a/itests/test/src/test/java/org/apache/karaf/itests/ssh/SshKeyFormatTest.java b/itests/test/src/test/java/org/apache/karaf/itests/ssh/SshKeyFormatTest.java
index 210b86a..c464abe 100644
--- a/itests/test/src/test/java/org/apache/karaf/itests/ssh/SshKeyFormatTest.java
+++ b/itests/test/src/test/java/org/apache/karaf/itests/ssh/SshKeyFormatTest.java
@@ -22,18 +22,26 @@ package org.apache.karaf.itests.ssh;
 
 import com.google.common.io.ByteSource;
 import com.google.common.io.Resources;
-import org.apache.commons.ssl.PKCS8Key;
+
 import org.apache.sshd.client.SshClient;
 import org.apache.sshd.client.future.ConnectFuture;
 import org.apache.sshd.client.keyverifier.RequiredServerKeyVerifier;
 import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.client.session.ClientSession.ClientSessionEvent;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
 import org.junit.Test;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
 import java.util.EnumSet;
 import java.util.Set;
 
@@ -50,22 +58,23 @@ public class SshKeyFormatTest extends SshCommandTestBase {
         File keyFile = new File("src/test/resources/org/apache/karaf/itests/ssh/test.pem");
         return options(composite(super.config()),
                 editConfigurationFilePut("etc/org.apache.karaf.shell.cfg", "hostKey", keyFile.getAbsolutePath()),
-                bundle("mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.not-yet-commons-ssl/0.3.11_1"),
+                bundle("mvn:org.bouncycastle/bcprov-jdk15on/1.62"),
+                bundle("mvn:org.bouncycastle/bcpkix-jdk15on/1.62"),
                 bundle("mvn:com.google.guava/guava/16.0.1")
                 );
     }
 
-        
+
     @Test
     public void usePemKey() throws Exception {
         SshClient client = SshClient.setUpDefaultClient();
         URL testPemURL = Resources.getResource(SshKeyFormatTest.class, "test.pem");
         ByteSource source = Resources.asByteSource(testPemURL);
-        PKCS8Key pkcs8 = new PKCS8Key(source.openStream(), null);
+        KeyPair keyPair = getKeyPair(source.openStream());
 
         String sshPort = getSshPort();
 
-        client.setServerKeyVerifier(new RequiredServerKeyVerifier(pkcs8.getPublicKey()));
+        client.setServerKeyVerifier(new RequiredServerKeyVerifier(keyPair.getPublic()));
         client.start();
         ConnectFuture future = client.connect("karaf", "localhost", Integer.parseInt(sshPort));
         future.await();
@@ -82,4 +91,14 @@ public class SshKeyFormatTest extends SshCommandTestBase {
         }
         session.close(true);
     }
+
+    public static KeyPair getKeyPair(InputStream is) throws GeneralSecurityException, IOException {
+        try (PEMParser parser = new PEMParser(new InputStreamReader(is))) {
+            Object o = parser.readObject();
+
+            JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
+            return pemConverter.getKeyPair((PEMKeyPair)o);
+        }
+    }
+
 }
diff --git a/pom.xml b/pom.xml
index 5cada72..1c18e63 100644
--- a/pom.xml
+++ b/pom.xml
@@ -150,6 +150,7 @@
         <asm.version>7.1</asm.version>
         <javax.annotation.version>1.3.1</javax.annotation.version>
         <awaitility.version>3.1.6</awaitility.version>
+        <bouncycastle.version>1.62</bouncycastle.version>
         <cglib.bundle.version>3.2.9_1</cglib.bundle.version>
         
         <jna.version>5.3.1</jna.version>
diff --git a/shell/ssh/pom.xml b/shell/ssh/pom.xml
index 74dd49f..ae30adf 100644
--- a/shell/ssh/pom.xml
+++ b/shell/ssh/pom.xml
@@ -75,9 +75,16 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.servicemix.bundles</groupId>
-            <artifactId>org.apache.servicemix.bundles.not-yet-commons-ssl</artifactId>
-            <version>0.3.11_1</version>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk15on</artifactId>
+            <scope>compile</scope>
+            <version>${bouncycastle.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcpkix-jdk15on</artifactId>
+            <scope>compile</scope>
+            <version>${bouncycastle.version}</version>
         </dependency>
 
         <dependency>
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/KeyPairLoader.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/KeyPairLoader.java
new file mode 100644
index 0000000..d0ac5a5
--- /dev/null
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/KeyPairLoader.java
@@ -0,0 +1,118 @@
+/*
+ * 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.karaf.shell.ssh.keygenerator;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
+import org.bouncycastle.jce.spec.ECParameterSpec;
+import org.bouncycastle.jce.spec.ECPublicKeySpec;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A utility class to convert a private key file into a KeyPair object
+ */
+public final class KeyPairLoader {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(KeyPairLoader.class);
+
+    private KeyPairLoader() {
+        // complete
+    }
+
+    public static KeyPair getKeyPair(InputStream is) throws GeneralSecurityException, IOException {
+        try (PEMParser parser = new PEMParser(new InputStreamReader(is))) {
+            Object o = parser.readObject();
+
+            JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
+
+            if (o instanceof PEMKeyPair) {
+                return pemConverter.getKeyPair((PEMKeyPair)o);
+            } else if (o instanceof KeyPair) {
+                return (KeyPair) o;
+            } else if (o instanceof PrivateKeyInfo) {
+                PrivateKey privateKey = pemConverter.getPrivateKey((PrivateKeyInfo)o);
+                PublicKey publicKey = convertPrivateToPublicKey(privateKey);
+                if (publicKey != null) {
+                    return new KeyPair(publicKey, privateKey);
+                }
+            }
+        }
+
+        throw new GeneralSecurityException("Failed to parse input stream");
+    }
+
+    private static PublicKey convertPrivateToPublicKey(PrivateKey privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
+        if (privateKey instanceof RSAPrivateCrtKey) {
+            KeySpec keySpec = new RSAPublicKeySpec(((RSAPrivateCrtKey)privateKey).getModulus(),
+                                                            ((RSAPrivateCrtKey)privateKey).getPublicExponent());
+            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+            return keyFactory.generatePublic(keySpec);
+        } else if (privateKey instanceof ECPrivateKey) {
+            ECPrivateKey ecPrivateKey = (ECPrivateKey)privateKey;
+
+            // Derive the public point by multiplying the generator by the private value
+            ECParameterSpec paramSpec = EC5Util.convertSpec(ecPrivateKey.getParams(), false);
+            ECPoint q = paramSpec.getG().multiply(ecPrivateKey.getS());
+
+            KeySpec keySpec = new ECPublicKeySpec(q, paramSpec);
+
+            KeyFactory keyFactory = KeyFactory.getInstance("EC");
+            return keyFactory.generatePublic(keySpec);
+        } else if (privateKey instanceof DSAPrivateKey) {
+            DSAPrivateKey dsaPrivateKey = (DSAPrivateKey)privateKey;
+
+            BigInteger q = dsaPrivateKey.getParams().getQ();
+            BigInteger p = dsaPrivateKey.getParams().getP();
+            KeySpec keySpec = new DSAPublicKeySpec(q.modPow(dsaPrivateKey.getX(), p),
+                                                   p,
+                                                   q,
+                                                   dsaPrivateKey.getParams().getG());
+
+            KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+            return keyFactory.generatePublic(keySpec);
+        } else {
+            LOGGER.warn("Unable to convert private key to public key. Only RSA, DSA + ECDSA supported");
+            return null;
+        }
+    }
+
+}
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHKeyPairProvider.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHKeyPairProvider.java
index 0e16d2e..8f527d0 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHKeyPairProvider.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHKeyPairProvider.java
@@ -37,7 +37,6 @@ import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.Base64;
 
-import org.apache.commons.ssl.PKCS8Key;
 import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -70,7 +69,7 @@ public class OpenSSHKeyPairProvider extends AbstractKeyPairProvider {
         // 1. Try to read the PKCS8 private key. If it is RSA or DSA we can infer the public key directly from the
         // private key, so there is no need to load the public key.
         try (InputStream is = Files.newInputStream(privateKeyPath)) {
-            KeyPair kp = getKeyPair(is);
+            KeyPair kp = KeyPairLoader.getKeyPair(is);
             cachedKey = kp;
             return singleton(kp);
         } catch (Exception e) {
@@ -98,11 +97,6 @@ public class OpenSSHKeyPairProvider extends AbstractKeyPairProvider {
         }
     }
 
-    private KeyPair getKeyPair(InputStream is) throws GeneralSecurityException, IOException {
-        PKCS8Key pkcs8 = new PKCS8Key(is, password == null ? null : password.toCharArray());
-        return new KeyPair(pkcs8.getPublicKey(), pkcs8.getPrivateKey());
-    }
-
     private KeyPair convertLegacyKey(Path privateKeyPath) throws GeneralSecurityException, IOException {
         KeyPair keypair = null;
         try (ObjectInputStream r = new ObjectInputStream(Files.newInputStream(privateKeyPath))) {
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/PemWriter.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/PemWriter.java
index 66755c4..9eb763e 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/PemWriter.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/keygenerator/PemWriter.java
@@ -19,16 +19,12 @@
 package org.apache.karaf.shell.ssh.keygenerator;
 
 import java.io.FileNotFoundException;
+import java.io.FileWriter;
 import java.io.IOException;
-import java.io.OutputStream;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.security.KeyPair;
-import java.util.ArrayList;
-import java.util.Collection;
 
-import org.apache.commons.ssl.PEMItem;
-import org.apache.commons.ssl.PEMUtil;
+import org.bouncycastle.util.io.pem.PemObject;
 
 public class PemWriter {
     private Path privateKeyPath;
@@ -40,19 +36,12 @@ public class PemWriter {
     }
 
     public void writeKeyPair(String resource, KeyPair kp) throws IOException, FileNotFoundException {
-        Collection<Object> items = new ArrayList<>();
-
-        items.add(new PEMItem(kp.getPrivate().getEncoded(), "PRIVATE KEY"));
-        byte[] bytes = PEMUtil.encode(items);
-        try (OutputStream os = Files.newOutputStream(privateKeyPath)) {
-            os.write(bytes);
+        try (org.bouncycastle.util.io.pem.PemWriter writer = new org.bouncycastle.util.io.pem.PemWriter(new FileWriter(privateKeyPath.toFile()))) {
+            writer.writeObject(new PemObject("PRIVATE KEY", kp.getPrivate().getEncoded()));
         }
 
-        items.clear();
-        items.add(new PEMItem(kp.getPublic().getEncoded(), "PUBLIC KEY"));
-        bytes = PEMUtil.encode(items);
-        try (OutputStream os = Files.newOutputStream(publicKeyPath)) {
-            os.write(bytes);
+        try (org.bouncycastle.util.io.pem.PemWriter writer = new org.bouncycastle.util.io.pem.PemWriter(new FileWriter(publicKeyPath.toFile()))) {
+            writer.writeObject(new PemObject("PUBLIC KEY", kp.getPublic().getEncoded()));
         }
     }
 }
diff --git a/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHGeneratorKeyFileProviderTest.java b/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHGeneratorKeyFileProviderTest.java
index 8034e9d..bf106b0 100644
--- a/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHGeneratorKeyFileProviderTest.java
+++ b/shell/ssh/src/test/java/org/apache/karaf/shell/ssh/keygenerator/OpenSSHGeneratorKeyFileProviderTest.java
@@ -27,7 +27,6 @@ import java.security.interfaces.RSAPrivateCrtKey;
 import java.security.interfaces.RSAPublicKey;
 import java.util.List;
 
-import org.apache.commons.ssl.PKCS8Key;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
 import org.junit.Assert;
@@ -69,7 +68,7 @@ public class OpenSSHGeneratorKeyFileProviderTest {
 
         Assert.assertEquals("DSA", simpleKeyPair.getPrivate().getAlgorithm());
 
-        OpenSSHKeyPairProvider provider = 
+        OpenSSHKeyPairProvider provider =
             new OpenSSHKeyPairProvider(privateKeyTemp.toPath(), publicKeyTemp.toPath(), "DSA", 2048);
         KeyPair convertedKeyPair = provider.loadKeys().iterator().next();
         Assert.assertEquals("DSA", convertedKeyPair.getPrivate().getAlgorithm());
@@ -78,8 +77,7 @@ public class OpenSSHGeneratorKeyFileProviderTest {
         Assert.assertArrayEquals(simpleKeyPair.getPublic().getEncoded(),convertedKeyPair.getPublic().getEncoded());
 
         //also test that the original file has been replaced
-        PKCS8Key pkcs8 = new PKCS8Key(Files.newInputStream(privateKeyTemp.toPath()), null );
-        KeyPair keyPair = new KeyPair(pkcs8.getPublicKey(), pkcs8.getPrivateKey());
+        KeyPair keyPair = KeyPairLoader.getKeyPair(Files.newInputStream(privateKeyTemp.toPath()));
         Assert.assertArrayEquals(simpleKeyPair.getPrivate().getEncoded(),keyPair.getPrivate().getEncoded());
     }