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&Bundle-SymbolicName=net.i2p.crypto.eddsa_wrapped&Bundle-Version=${eddsa.version}&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>