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

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-server.git


The following commit(s) were added to refs/heads/master by this push:
     new 86dfbb0932 support (partially) openssh key format
86dfbb0932 is described below

commit 86dfbb09324f09f96b9a5075a87983ca3386388b
Author: Alex Heneveld <[email protected]>
AuthorDate: Wed Dec 7 17:31:28 2022 +0000

    support (partially) openssh key format
---
 core/pom.xml                                       |  10 +-
 .../internal/ssh/sshj/SshjClientConnection.java    | 113 +++++++++++++++++----
 karaf/features/src/main/feature/feature.xml        |   6 +-
 pom.xml                                            |   8 +-
 utils/jmx/jmxmp-ssl-agent/pom.xml                  |   2 +-
 5 files changed, 110 insertions(+), 29 deletions(-)

diff --git a/core/pom.xml b/core/pom.xml
index 157e2fb70d..2eeef7af18 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -65,11 +65,15 @@
             <groupId>com.hierynomus</groupId>
             <artifactId>sshj</artifactId>
             <exclusions>
-                <!-- provided by bcprov-ext instead -->
+                <!-- we use jdk18on -->
                 <exclusion>
                     <groupId>org.bouncycastle</groupId>
                     <artifactId>bcprov-jdk15on</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>org.bouncycastle</groupId>
+                    <artifactId>bcpkix-jdk15on</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
@@ -97,11 +101,11 @@
 
         <dependency>
             <groupId>org.bouncycastle</groupId>
-            <artifactId>bcprov-ext-jdk15on</artifactId>
+            <artifactId>bcprov-jdk18on</artifactId>
         </dependency>
         <dependency>
             <groupId>org.bouncycastle</groupId>
-            <artifactId>bcpkix-jdk15on</artifactId>
+            <artifactId>bcpkix-jdk18on</artifactId>
         </dependency>
 
         <dependency>
diff --git 
a/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjClientConnection.java
 
b/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjClientConnection.java
index ddad016388..b3e16085fc 100644
--- 
a/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjClientConnection.java
+++ 
b/core/src/main/java/org/apache/brooklyn/util/core/internal/ssh/sshj/SshjClientConnection.java
@@ -21,8 +21,8 @@ package org.apache.brooklyn.util.core.internal.ssh.sshj;
 import static com.google.common.base.Objects.equal;
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import java.io.File;
-import java.io.IOException;
+import java.io.*;
+import java.util.List;
 
 import net.schmizz.sshj.SSHClient;
 import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
@@ -30,7 +30,18 @@ import net.schmizz.sshj.userauth.keyprovider.OpenSSHKeyFile;
 import net.schmizz.sshj.userauth.password.PasswordUtils;
 
 import org.apache.brooklyn.util.JavaGroovyEquivalents;
+import org.apache.brooklyn.util.collections.MutableList;
 import org.apache.brooklyn.util.core.internal.ssh.SshAbstractTool.SshAction;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.stream.Streams;
+import org.apache.brooklyn.util.text.Strings;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
+import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
+import org.bouncycastle.openssl.MiscPEMGenerator;
+import org.bouncycastle.util.io.pem.PemReader;
+import org.bouncycastle.util.io.pem.PemWriter;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -174,6 +185,21 @@ public class SshjClientConnection implements 
SshAction<SSHClient> {
         ssh = null;
     }
 
+    static String convertOpensshPrivateKeyToRsaPrivateKeyData(String 
opensshPrivateKeyNewFormatData) throws IOException {
+        AsymmetricKeyParameter privateKeyParameters;
+        try (StringReader r = new 
StringReader(opensshPrivateKeyNewFormatData)) {
+            PemReader pemReader = new PemReader(r);
+            byte[] privateKeyContent = pemReader.readPemObject().getContent();
+            privateKeyParameters = 
OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(privateKeyContent);
+        }
+        PrivateKeyInfo keyInfo = 
PrivateKeyInfoFactory.createPrivateKeyInfo(privateKeyParameters);
+        StringWriter sw = new StringWriter();
+        PemWriter pw = new PemWriter(sw);
+        pw.writeObject(new MiscPEMGenerator(keyInfo).generate());
+        pw.close();
+        return sw.toString();
+    }
+
     @Override
     public SSHClient create() throws Exception {
         if (LOG.isTraceEnabled()) LOG.trace("Connecting SshjClientConnection 
{} ({})", this, System.identityHashCode(this));
@@ -191,23 +217,74 @@ public class SshjClientConnection implements 
SshAction<SSHClient> {
         
         if (password != null) {
             ssh.authPassword(username, password);
-        } else if (privateKeyData != null) {
-            OpenSSHKeyFile key = new OpenSSHKeyFile();
-            key.init(privateKeyData, null, 
-                    JavaGroovyEquivalents.groovyTruth(privateKeyPassphrase) ? 
-                            
PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
-                            : null);
-            ssh.authPublickey(username, key);
-        } else if (privateKeyFile != null) {
-            OpenSSHKeyFile key = new OpenSSHKeyFile();
-            key.init(privateKeyFile, 
-                    JavaGroovyEquivalents.groovyTruth(privateKeyPassphrase) ? 
-                            
PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
-                            : null);
-            ssh.authPublickey(username, key);
         } else {
-            // Accept defaults (in ~/.ssh)
-            ssh.authPublickey(username);
+            boolean auth = false;
+
+            String actualPrivateKeyData = privateKeyData;
+
+
+            List<Exception> errors = MutableList.of();
+
+            if (Strings.isBlank(actualPrivateKeyData) && privateKeyFile!=null) 
{
+                actualPrivateKeyData = Streams.readFullyStringAndClose(new 
FileInputStream(privateKeyFile));
+            }
+
+            try {
+                if (Strings.isNonBlank(actualPrivateKeyData) && 
actualPrivateKeyData.trim().matches("(?s)-+ *BEGIN OPENSSH PRIVATE KEY.*")) {
+                    // bouncy castle has low-level routines for OPENSSH 
PRIVATE KEY format
+                    // but does not recognize it in the PEM file, so we handle 
it specially
+                    // (but note passphrase is not supported)
+                    if (Strings.isNonBlank(privateKeyPassphrase)) throw new 
IllegalArgumentException(
+                            "Passphrase not supported with proprietary OPENSSH 
PRIVATE KEY format. " +
+                                    "Use RSA or other standard. If using 
ssh-keygen this means passing `-m pem`.");
+
+                    OpenSSHKeyFile key = new OpenSSHKeyFile();
+                    
key.init(convertOpensshPrivateKeyToRsaPrivateKeyData(actualPrivateKeyData), 
null,
+                            null /* passphrase would have been used earlier, 
but isn't supported by BC */);
+                    auth = true;
+                    ssh.authPublickey(username, key);
+                }
+            } catch (Exception e) {
+                errors.add(e);
+            }
+
+            if (!auth && privateKeyData != null) {
+                try {
+                    OpenSSHKeyFile key = new OpenSSHKeyFile();
+                    key.init(privateKeyData, null,
+                            
JavaGroovyEquivalents.groovyTruth(privateKeyPassphrase) ?
+                                    
PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
+                                    : null);
+                    auth = true;
+                    ssh.authPublickey(username, key);
+                } catch (Exception e) {
+                    errors.add(e);
+                }
+            }
+
+            if (!auth && privateKeyFile != null) {
+                try {
+                    OpenSSHKeyFile key = new OpenSSHKeyFile();
+                    key.init(privateKeyFile,
+                            
JavaGroovyEquivalents.groovyTruth(privateKeyPassphrase) ?
+                                    
PasswordUtils.createOneOff(privateKeyPassphrase.toCharArray())
+                                    : null);
+                    auth = true;
+                    ssh.authPublickey(username, key);
+                } catch (Exception e) {
+                    errors.add(e);
+                }
+            }
+
+            if (!errors.isEmpty()) {
+                if (errors.size()>1) LOG.warn("Invalid keys supplied, multiple 
errors. First will be rethrown. All errors are: "+errors);
+                throw Exceptions.propagate("Unsupported key type", errors);
+            }
+
+            if (!auth) {
+                // Accept defaults (in ~/.ssh)
+                ssh.authPublickey(username);
+            }
         }
         
         return ssh;
diff --git a/karaf/features/src/main/feature/feature.xml 
b/karaf/features/src/main/feature/feature.xml
index 8c0e864422..26e6bba9eb 100644
--- a/karaf/features/src/main/feature/feature.xml
+++ b/karaf/features/src/main/feature/feature.xml
@@ -62,9 +62,9 @@
 
         <feature prerequisite="true">wrap</feature>
 
-        
<bundle>mvn:org.bouncycastle/bcutil-jdk15on/${bouncycastle.version}</bundle>
-        
<bundle>mvn:org.bouncycastle/bcprov-ext-jdk15on/${bouncycastle.version}</bundle>
-        
<bundle>mvn:org.bouncycastle/bcpkix-jdk15on/${bouncycastle.version}</bundle>
+        
<bundle>mvn:org.bouncycastle/bcutil-jdk18on/${bouncycastle.version}</bundle>
+        
<bundle>mvn:org.bouncycastle/bcprov-jdk18on/${bouncycastle.version}</bundle>
+        
<bundle>mvn:org.bouncycastle/bcpkix-jdk18on/${bouncycastle.version}</bundle>
         
<bundle>mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.jzlib/${jzlib.version}</bundle>
         <!-- wrapped to import/export eddsa.math subpackage, and fix various 
other refs too -->
         
<bundle>wrap:mvn:net.i2p.crypto/eddsa/${eddsa.version}$overwrite=merge&amp;Bundle-SymbolicName=net.i2p.crypto.eddsa_wrapped&amp;Bundle-Version=${eddsa.version}&amp;Export-Package=*;version="${eddsa.version}"</bundle>
diff --git a/pom.xml b/pom.xml
index 7d0a6729c0..e304ea8bf1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,9 +143,9 @@
         <!-- Next version of swagger requires changes to how path mapping and 
scanner injection are done. -->
         <swagger.version>1.6.2</swagger.version>
         <mx4j.version>3.0.1</mx4j.version>
-        <bouncycastle.version>1.69</bouncycastle.version>  <!-- beyond this 
gives asn1 errors, needs a new dep probably -->
+        <bouncycastle.version>1.72</bouncycastle.version>  <!-- beyond this 
gives asn1 errors, needs a new dep probably -->
         <eddsa.version>0.3.0</eddsa.version>  <!-- eddsa 0.3.0 needs sun x509 
-->
-        <sshj.version>0.33.0</sshj.version>  <!-- jclouds 2.4 uses 0.27; 0.32 
needs eddsa 0.3.0 -->
+        <sshj.version>0.34.0</sshj.version>  <!-- jclouds 2.4 uses 0.27; 0.32 
needs eddsa 0.3.0 -->
         <sshj.asn1.version>0.6.0</sshj.asn1.version>
         <!-- jzlib osgi version is 1.1.3.2, but bundle is 1.1.3_2 ; JClouds 
2.2.0 pulls in 1.0.7_1 but is happy with 1.1.3.2 -->
         <jzlib.version>1.1.3_2</jzlib.version>
@@ -685,12 +685,12 @@
             </dependency>
             <dependency>
                 <groupId>org.bouncycastle</groupId>
-                <artifactId>bcprov-ext-jdk15on</artifactId>
+                <artifactId>bcprov-jdk18on</artifactId>
                 <version>${bouncycastle.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.bouncycastle</groupId>
-                <artifactId>bcpkix-jdk15on</artifactId>
+                <artifactId>bcpkix-jdk18on</artifactId>
                 <version>${bouncycastle.version}</version>
             </dependency>
             <dependency>
diff --git a/utils/jmx/jmxmp-ssl-agent/pom.xml 
b/utils/jmx/jmxmp-ssl-agent/pom.xml
index c580762398..819f778535 100644
--- a/utils/jmx/jmxmp-ssl-agent/pom.xml
+++ b/utils/jmx/jmxmp-ssl-agent/pom.xml
@@ -44,7 +44,7 @@
         </dependency>
         <dependency>
             <groupId>org.bouncycastle</groupId>
-            <artifactId>bcprov-ext-jdk15on</artifactId>
+            <artifactId>bcprov-jdk18on</artifactId>
         </dependency>
 
         <dependency>

Reply via email to