You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by co...@apache.org on 2019/07/05 08:45:47 UTC

[camel] branch master updated: CAMEL-13726 - Add support for PKCS8 keys and encrypted PKCS8 keys

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

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


The following commit(s) were added to refs/heads/master by this push:
     new d09b13c  CAMEL-13726 - Add support for PKCS8 keys and encrypted PKCS8 keys
d09b13c is described below

commit d09b13cb9205a058a1974a172ac904a0f14a6de0
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Fri Jul 5 09:44:54 2019 +0100

    CAMEL-13726 - Add support for PKCS8 keys and encrypted PKCS8 keys
---
 .../camel-ssh/src/main/docs/ssh-component.adoc     | 10 ++--
 .../ssh/ResourceHelperKeyPairProvider.java         | 59 ++++++++++++++++++++--
 .../apache/camel/component/ssh/SshComponent.java   | 23 +++++++--
 .../camel/component/ssh/SshConfiguration.java      | 16 ++++++
 .../apache/camel/component/ssh/SshEndpoint.java    | 14 +++--
 .../org/apache/camel/component/ssh/SshHelper.java  |  8 ++-
 .../component/ssh/SshComponentSecurityTest.java    | 56 +++++++++++++++++++-
 .../camel-ssh/src/test/resources/ecpkcs8.pem       |  8 +++
 components/camel-ssh/src/test/resources/encrsa.pem | 30 +++++++++++
 components/camel-ssh/src/test/resources/rsa.pem    | 28 ++++++++++
 .../endpoint/dsl/SshEndpointBuilderFactory.java    | 33 ++++++++++++
 .../ssh/springboot/SshComponentConfiguration.java  | 26 ++++++++++
 12 files changed, 294 insertions(+), 17 deletions(-)

diff --git a/components/camel-ssh/src/main/docs/ssh-component.adoc b/components/camel-ssh/src/main/docs/ssh-component.adoc
index 3b961f8..4df54df 100644
--- a/components/camel-ssh/src/main/docs/ssh-component.adoc
+++ b/components/camel-ssh/src/main/docs/ssh-component.adoc
@@ -31,7 +31,7 @@ ssh:[username[:password]@]host[:port][?options]
 
 
 // component options: START
-The SSH component supports 15 options, which are listed below.
+The SSH component supports 16 options, which are listed below.
 
 
 
@@ -48,6 +48,7 @@ The SSH component supports 15 options, which are listed below.
 | *keyType* (security) | Sets the key type to pass to the KeyPairProvider as part of authentication. KeyPairProvider.loadKey(...) will be passed this value. Defaults to ssh-rsa. |  | String
 | *timeout* (common) | Sets the timeout in milliseconds to wait in establishing the remote SSH server connection. Defaults to 30000 milliseconds. |  | long
 | *certResource* (security) | Sets the resource path of the certificate to use for Authentication. Will use ResourceHelperKeyPairProvider to resolve file based certificate, and depends on keyType setting. |  | String
+| *certResourcePassword* (security) | Sets the password to use in loading certResource, if certResource is an encrypted key. |  | String
 | *channelType* (advanced) | Sets the channel type to pass to the Channel as part of command execution. Defaults to exec. |  | String
 | *shellPrompt* (advanced) | Sets the shellPrompt to be dropped when response is read after command execution |  | String
 | *sleepForShellPrompt* (advanced) | Sets the sleep period in milliseconds to wait reading response from shell prompt. Defaults to 100 milliseconds. |  | long
@@ -79,7 +80,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (33 parameters):
+==== Query Parameters (34 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -114,6 +115,7 @@ with the following path and query parameters:
 | *timeUnit* (scheduler) | Time unit for initialDelay and delay options. | MILLISECONDS | TimeUnit
 | *useFixedDelay* (scheduler) | Controls if fixed delay or fixed rate is used. See ScheduledExecutorService in JDK for details. | true | boolean
 | *certResource* (security) | Sets the resource path of the certificate to use for Authentication. Will use ResourceHelperKeyPairProvider to resolve file based certificate, and depends on keyType setting. |  | String
+| *certResourcePassword* (security) | Sets the password to use in loading certResource, if certResource is an encrypted key. |  | String
 | *keyPairProvider* (security) | Sets the KeyPairProvider reference to use when connecting using Certificates to the remote SSH Server. |  | KeyPairProvider
 | *keyType* (security) | Sets the key type to pass to the KeyPairProvider as part of authentication. KeyPairProvider.loadKey(...) will be passed this value. From Camel 3.0.0 / 2.25.0, by default Camel will select the first available KeyPair that is loaded. Prior to this, a KeyType of 'ssh-rsa' was enforced by default. |  | String
 | *password* (security) | Sets the password to use in connecting to remote SSH server. Requires keyPairProvider to be set to null. |  | String
@@ -136,7 +138,7 @@ When using Spring Boot make sure to use the following Maven dependency to have s
 ----
 
 
-The component supports 30 options, which are listed below.
+The component supports 32 options, which are listed below.
 
 
 
@@ -145,8 +147,10 @@ The component supports 30 options, which are listed below.
 | Name | Description | Default | Type
 | *camel.component.ssh.basic-property-binding* | Whether the component should use basic property binding (Camel 2.x) or the newer property binding with additional capabilities | false | Boolean
 | *camel.component.ssh.cert-resource* | Sets the resource path of the certificate to use for Authentication. Will use ResourceHelperKeyPairProvider to resolve file based certificate, and depends on keyType setting. |  | String
+| *camel.component.ssh.cert-resource-password* | Sets the password to use in loading certResource, if certResource is an encrypted key. |  | String
 | *camel.component.ssh.channel-type* | Sets the channel type to pass to the Channel as part of command execution. Defaults to exec. |  | String
 | *camel.component.ssh.configuration.cert-resource* | Sets the resource path of the certificate to use for Authentication. Will use {@link ResourceHelperKeyPairProvider} to resolve file based certificate, and depends on keyType setting. |  | String
+| *camel.component.ssh.configuration.cert-resource-password* | Sets the password to use in loading certResource, if certResource is an encrypted key. |  | String
 | *camel.component.ssh.configuration.channel-type* | Sets the channel type to pass to the Channel as part of command execution. Defaults to "exec". | exec | String
 | *camel.component.ssh.configuration.fail-on-unknown-host* | Specifies whether a connection to an unknown host should fail or not. This value is only checked when the property knownHosts is set. | false | Boolean
 | *camel.component.ssh.configuration.host* | Sets the hostname of the remote SSH server. |  | String
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/ResourceHelperKeyPairProvider.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/ResourceHelperKeyPairProvider.java
index 9436cbe..a0763ed 100644
--- a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/ResourceHelperKeyPairProvider.java
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/ResourceHelperKeyPairProvider.java
@@ -18,7 +18,16 @@ package org.apache.camel.component.ssh;
 
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.security.KeyFactory;
 import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.RSAPublicKeySpec;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Supplier;
@@ -28,12 +37,20 @@ import org.apache.camel.support.ResourceHelper;
 import org.apache.sshd.common.keyprovider.AbstractKeyPairProvider;
 import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.common.util.security.SecurityUtils;
+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.PEMDecryptorProvider;
 import org.bouncycastle.openssl.PEMEncryptedKeyPair;
 import org.bouncycastle.openssl.PEMKeyPair;
 import org.bouncycastle.openssl.PEMParser;
 import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
 import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.bouncycastle.operator.InputDecryptorProvider;
+import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -112,22 +129,33 @@ public class ResourceHelperKeyPairProvider extends AbstractKeyPairProvider {
                 r = new PEMParser(isr);
 
                 Object o = r.readObject();
-                
+
                 JcaPEMKeyConverter pemConverter = new JcaPEMKeyConverter();
                 pemConverter.setProvider("BC");
                 if (passwordFinder != null && o instanceof PEMEncryptedKeyPair) {
                     JcePEMDecryptorProviderBuilder decryptorBuilder = new JcePEMDecryptorProviderBuilder();
                     PEMDecryptorProvider pemDecryptor = decryptorBuilder.build(passwordFinder.get());
                     o = pemConverter.getKeyPair(((PEMEncryptedKeyPair) o).decryptKeyPair(pemDecryptor));
+                } else if (passwordFinder != null && o instanceof PKCS8EncryptedPrivateKeyInfo) {
+                    JceOpenSSLPKCS8DecryptorProviderBuilder jce = new JceOpenSSLPKCS8DecryptorProviderBuilder();
+                    jce.setProvider("BC");
+                    InputDecryptorProvider decProv = jce.build(passwordFinder.get());
+                    o = ((PKCS8EncryptedPrivateKeyInfo)o).decryptPrivateKeyInfo(decProv);
                 }
-                
+
                 if (o instanceof PEMKeyPair) {
                     o = pemConverter.getKeyPair((PEMKeyPair)o);
                     keys.add((KeyPair) o);
                 } else if (o instanceof KeyPair) {
                     keys.add((KeyPair) o);
+                } else if (o instanceof PrivateKeyInfo) {
+                    PrivateKey privateKey = pemConverter.getPrivateKey((PrivateKeyInfo)o);
+                    PublicKey publicKey = convertPrivateToPublicKey(privateKey);
+                    if (publicKey != null) {
+                        keys.add(new KeyPair(publicKey, privateKey));
+                    }
                 }
-                
+
             } catch (Exception e) {
                 log.warn("Unable to read key", e);
             } finally {
@@ -137,5 +165,28 @@ public class ResourceHelperKeyPairProvider extends AbstractKeyPairProvider {
 
         return keys;
     }
-    
+
+    private 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 {
+            log.warn("Unable to convert private key to public key. Only RSA + ECDSA supported");
+            return null;
+        }
+    }
+
 }
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java
index 5cc5972..35e267b 100644
--- a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshComponent.java
@@ -190,7 +190,22 @@ public class SshComponent extends DefaultComponent {
     public void setCertResource(String certResource) {
         getConfiguration().setCertResource(certResource);
     }
-    
+
+    public String getCertResourcePassword() {
+        return getConfiguration().getCertResourcePassword();
+    }
+
+    /**
+     * Sets the password to use in loading certResource, if certResource is an encrypted key.
+     *
+     * @param certResourcePassword
+     *            String representing password use to load the certResource key
+     */
+    @Metadata(label = "security", secret = true)
+    public void setCertResourcePassword(String certResourcePassword) {
+        getConfiguration().setCertResourcePassword(certResourcePassword);
+    }
+
     /**
      * Sets the channel type to pass to the Channel as part of command execution.
      * Defaults to "exec".
@@ -204,19 +219,19 @@ public class SshComponent extends DefaultComponent {
     public void setChannelType(String channelType) {
         getConfiguration().setChannelType(channelType);
     }
-    
+
     /**
      * Sets the shellPrompt to be dropped when response is read after command execution
      *
      * @param shellPrompt
-     *            String defining ending string of command line which has to be dropped when response is 
+     *            String defining ending string of command line which has to be dropped when response is
      *            read after command execution.
      */
     @Metadata(label = "advanced")
     public void setShellPrompt(String shellPrompt) {
         getConfiguration().setShellPrompt(shellPrompt);
     }
-    
+
     /**
      * Sets the sleep period in milliseconds to wait reading response from shell prompt.
      * Defaults to 100 milliseconds.
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java
index 9899a2d6..417b755 100644
--- a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshConfiguration.java
@@ -48,6 +48,8 @@ public class SshConfiguration implements Cloneable {
     private String keyType;
     @UriParam(label = "security")
     private String certResource;
+    @UriParam(label = "security", secret = true)
+    private String certResourcePassword;
     @UriParam(defaultValue = "30000")
     private long timeout = 30000;
     @UriParam()
@@ -263,6 +265,20 @@ public class SshConfiguration implements Cloneable {
         this.certResource = certResource;
     }
 
+    public String getCertResourcePassword() {
+        return certResourcePassword;
+    }
+
+    /**
+     * Sets the password to use in loading certResource, if certResource is an encrypted key.
+     *
+     * @param certResourcePassword
+     *            String representing password use to load the certResource key
+     */
+    public void setCertResourcePassword(String certResourcePassword) {
+        this.certResourcePassword = certResourcePassword;
+    }
+
     public String getKnownHostsResource() {
         return knownHostsResource;
     }
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
index 71ced79..041226e 100644
--- a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshEndpoint.java
@@ -163,6 +163,14 @@ public class SshEndpoint extends ScheduledPollEndpoint {
         getConfiguration().setCertResource(certResource);
     }
 
+    public String getCertResourcePassword() {
+        return getConfiguration().getCertResourcePassword();
+    }
+
+    public void setCertResourcePassword(String certResourcePassword) {
+        getConfiguration().setCertResourcePassword(certResourcePassword);
+    }
+
     public String getKnownHostsResource() {
         return getConfiguration().getKnownHostsResource();
     }
@@ -178,7 +186,7 @@ public class SshEndpoint extends ScheduledPollEndpoint {
     public void setFailOnUnknownHost(boolean failOnUnknownHost) {
         getConfiguration().setFailOnUnknownHost(failOnUnknownHost);
     }
-    
+
     public String getChannelType() {
         return getConfiguration().getChannelType();
     }
@@ -186,7 +194,7 @@ public class SshEndpoint extends ScheduledPollEndpoint {
     public void setChannelType(String channelType) {
         getConfiguration().setChannelType(channelType);
     }
-    
+
     public String getShellPrompt() {
         return getConfiguration().getShellPrompt();
     }
@@ -194,7 +202,7 @@ public class SshEndpoint extends ScheduledPollEndpoint {
     public void setShellPrompt(String shellPrompt) {
         getConfiguration().setShellPrompt(shellPrompt);
     }
-    
+
     public long getSleepForShellPrompt() {
         return getConfiguration().getSleepForShellPrompt();
     }
diff --git a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshHelper.java b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshHelper.java
index d5ae2fe..92a5723 100644
--- a/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshHelper.java
+++ b/components/camel-ssh/src/main/java/org/apache/camel/component/ssh/SshHelper.java
@@ -27,6 +27,7 @@ import java.util.Arrays;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Supplier;
 
 import org.apache.camel.RuntimeCamelException;
 import org.apache.sshd.client.SshClient;
@@ -83,7 +84,12 @@ public final class SshHelper {
             final String certResource = configuration.getCertResource();
             if (certResource != null) {
                 LOG.debug("Attempting to authenticate using ResourceKey '{}'...", certResource);
-                keyPairProvider = new ResourceHelperKeyPairProvider(new String[]{certResource}, endpoint.getCamelContext());
+                if (endpoint.getCertResourcePassword() != null) {
+                    Supplier<char[]> passwordFinder = () -> endpoint.getCertResourcePassword().toCharArray();
+                    keyPairProvider = new ResourceHelperKeyPairProvider(new String[]{certResource}, passwordFinder, endpoint.getCamelContext());
+                } else {
+                    keyPairProvider = new ResourceHelperKeyPairProvider(new String[]{certResource}, endpoint.getCamelContext());
+                }
             } else {
                 keyPairProvider = configuration.getKeyPairProvider();
             }
diff --git a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentSecurityTest.java b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentSecurityTest.java
index d9ab553..c0607eb 100644
--- a/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentSecurityTest.java
+++ b/components/camel-ssh/src/test/java/org/apache/camel/component/ssh/SshComponentSecurityTest.java
@@ -53,6 +53,32 @@ public class SshComponentSecurityTest extends SshComponentTestSupport {
     }
 
     @Test
+    public void testRsaFilePKCS8() throws Exception {
+        final String msg = "test";
+
+        MockEndpoint mock = getMockEndpoint("mock:rsapkcs8");
+        mock.expectedMinimumMessageCount(1);
+        mock.expectedBodiesReceived(msg);
+
+        template.sendBody("direct:ssh-rsapkcs8", msg);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testEncryptedRsaFile() throws Exception {
+        final String msg = "test";
+
+        MockEndpoint mock = getMockEndpoint("mock:encrsaFile");
+        mock.expectedMinimumMessageCount(1);
+        mock.expectedBodiesReceived(msg);
+
+        template.sendBody("direct:ssh-encrsaFile", msg);
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
     public void testECFile() throws Exception {
         final String msg = "test";
 
@@ -65,6 +91,19 @@ public class SshComponentSecurityTest extends SshComponentTestSupport {
         assertMockEndpointsSatisfied();
     }
 
+    @Test
+    public void testECFilePKCS8() throws Exception {
+        final String msg = "test";
+
+        MockEndpoint mock = getMockEndpoint("mock:ecFilepkcs8");
+        mock.expectedMinimumMessageCount(1);
+        mock.expectedBodiesReceived(msg);
+
+        template.sendBody("direct:ssh-ecFilepkcs8", msg);
+
+        assertMockEndpointsSatisfied();
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
@@ -91,9 +130,22 @@ public class SshComponentSecurityTest extends SshComponentTestSupport {
                         .to("ssh://smx@localhost:" + port + "?certResource=file:src/test/resources/hostkey.pem")
                         .to("mock:rsaFile");
 
+                from("direct:ssh-rsapkcs8")
+                        .to("ssh://smx@localhost:" + port + "?certResource=file:src/test/resources/rsa.pem")
+                        .to("mock:rsapkcs8");
+
+                from("direct:ssh-encrsaFile")
+                        .to("ssh://smx@localhost:" + port + "?certResource=file:src/test/resources/encrsa.pem&certResourcePassword=security")
+                        .to("mock:encrsaFile");
+
                 from("direct:ssh-ecFile")
-                    .to("ssh://smx@localhost:" + port + "?certResource=file:src/test/resources/ec.pem")
-                    .to("mock:ecFile");
+                        .to("ssh://smx@localhost:" + port + "?certResource=file:src/test/resources/ec.pem")
+                        .to("mock:ecFile");
+
+
+                from("direct:ssh-ecFilepkcs8")
+                        .to("ssh://smx@localhost:" + port + "?certResource=file:src/test/resources/ecpkcs8.pem")
+                        .to("mock:ecFilepkcs8");
             }
         };
     }
diff --git a/components/camel-ssh/src/test/resources/ecpkcs8.pem b/components/camel-ssh/src/test/resources/ecpkcs8.pem
new file mode 100644
index 0000000..8b8d4b3
--- /dev/null
+++ b/components/camel-ssh/src/test/resources/ecpkcs8.pem
@@ -0,0 +1,8 @@
+-----BEGIN PRIVATE KEY-----
+MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB5Twq2mxiOAieZslZ
+lOkOG1Pi4PEmAWJ78+bRLAV7Q4F5Nd4u0bAdzGIEMFARoeVb/2C8ZFjNhL8xgOUP
+WJqY316hgYkDgYYABADMulfTEOAzU9gsMEfrOuTJj9J8c4SNaAeeUb6uDHYfKPnY
+vfMJrBcGlnRePjJjeWpGHOykqB8NYpCFk/TPgYFGpQGpz51EZngsQwpEEQXw/jzB
+HZsVOdrTADYu09Cy/AMLu3wAnaQ5rWm41G3eC8mfZ1Q0BQ7Fc0K103mxlayEM605
+jw==
+-----END PRIVATE KEY-----
diff --git a/components/camel-ssh/src/test/resources/encrsa.pem b/components/camel-ssh/src/test/resources/encrsa.pem
new file mode 100644
index 0000000..f9d39df
--- /dev/null
+++ b/components/camel-ssh/src/test/resources/encrsa.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQICsCP4wKZn6cCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAqBNa9ItIjNW16FFwcOqYRBIIE
+0Fd0cEbimhWmGaoC4zfJT1MyLUnqLrctscaE62NvBr5LL6ei6doShIViIWW0xNdG
+1/c8loSSraXmTaxUWLihQKwEwjV2NETEz/JNT0hkUNKmSk225Rrq0LBXGFiV3sd/
+uA9UGbn8GsD+pAj/pEC2Z9XfuSgUB8ZreO/N3eSfRyzryJqmhiJuskG6Q5JhkWur
+0B1YaDd2AszVrI7UnAJn/RjnlL2YzW9NO0NTaCHHS5syFwg7ocgwVCd3jkXyx9os
+x3Wvd3FF4DwbT5Au3LxlUbWCyyTaB2NAm5yqYa9D2eTajPoxnT9OLkG2tq+LVlYl
+OpDykHZIqOxUJ1+bTbmKSw9CTj7a/2L6TbmP3Z6OkXeDfNpelM8HzNVFvYTUbIuj
++IxJVNo4/GdI3j1LunPJLccAmA7RbLrxISDvoVE79L56c8dGd1DVzMyr33jnVqXi
+SP+1sgHKMeyL3iZpo69/F+brkz7/HgH7hlsqGP718TXwt+ZMy9+cftfdngDe+5FI
+spCnduZveHx4B98Nwlxl+TYlZO1sXNzmxck7g8fngjWgtKK/B1HEVhUUEiJaneUN
+AG4R/6bibpZDSorslPbWzGQAoMK2tEFYIxKRagBA1GiX9HsHU8rYx7+fNEHe5yJm
+BM/p1OLBTO9crvPhaRHNK4NWYd1kmKz9gJQtK7y16A1JO8gaI6XsZZdsitAEuFsR
+Ni4BjrTxb89TEoI7l9Hn6NQBfJBp4W5/IQ4UFtvX4T8hfAt/ELFH8QvJJdYkpf95
+XvJ69dKp4yptpWmyfp8D/t22cls28Bj8sxSXnuf45tN6EJcTqCM4YCFX2O2/upc/
+8GKWteYNGBo2G/9Y9fxiiWmi3mSsPGzbdjHTqDW0g38RqdMkTq1FTDojeMUiaRsF
+7wx/QwDq80hkTX4Jv+tVF1czCjfu3kfVxiOw3YQf2DpjNCAZX/QLYLQYOadpxp3m
+SdHpm4+L4uNLgtDNrXtMpMCJz8yuCeCz4diKCUT2GVKUNvDpz5sKKPIeJlEGJkAU
+llBpcCJcUk2VQCzz+PePNJgrGtbtGlXqkxfGESzctndoQsc3NAK5QHlvT/tfKrwA
+buPfg4gT/YAJiTD7tU4fiB/qyX4p+VKV6/FQZzXOx6H1U7mdqGjGUgUUpyGhDr2r
+oMVipIH8n8ndXe+8iYlqHyjjm9ROHO3etadAzaOxohG4wAF4s0T2aabR6cYftK9L
+XYmtjgoPh6tHgley3U4MNWX3Zew0t9vIPz4khoDokBbslEc9ePaqHGyqgpuQ4aZE
+jaQpyZ3hJOBy7+zoAAxCnMT0S2qH+MthKLp3I/OHTkSqFS1LsK8wdTBCAsTww0zJ
+nNfJ9LYVnsX6qfzfQxlkLlxJVxWjSorMvoiawunpftDvnTcoWk2zf6JSFq2ccgKA
++vxSyMyegDcHgYbhbOPVzCqcE/766upfkFVngaEyC8lI5D4eXc8IJIzMJb00kSmY
+n7jo6OZXOFwL2B6tKvwWaYXz8zgwCbTYv+RBtF3lb0aG1hSwQ0Pc0puZ9IV1FR0q
+7gT3g/uWBqUBGy4aaCUraf16K+DNHipmTSeYk5Z1fu27aTruY/Dlt7NwtsNxDtAO
+IzjSY69NAvmjtdjz237yeVXUFS0LJJ4dCrOxBA+oV2cD
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/components/camel-ssh/src/test/resources/rsa.pem b/components/camel-ssh/src/test/resources/rsa.pem
new file mode 100644
index 0000000..bfbaec8
--- /dev/null
+++ b/components/camel-ssh/src/test/resources/rsa.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC65ADW0lX/y6v0
+XK0zWoeE7WHI6odRl6vy+ocvjvFwSjjDsj8/fyHyq8hbeMAsR98SIEUh5gHjX2T+
+1RVE2AJ2+jV+5llY7tYG2He1kvMKra+fppWvVkbJ/wEqQ38eyN9G/KgET5p/izgb
+CycCKSe/VO/I6gLJSDB3kIKvX+sh0oynOg67A1OcFA0GOcM9p3mIbYjnz4QLAueT
+vkQdBPgojB+ooh1nZtb35naUTwXuKBCEeuc39P+HFeBSDuQoZQUqxXSbi2kq9vO6
+0qXQDb4hmLjJ32LrMeU+Kwe6c2TL76SxXZnsTPSnPA9+R+ChD0RElYLgqqIiUi2Y
+Q6lDyG77AgMBAAECggEBAIcapqSln3fws9lOWgNC0a89sC//o11PqQVZKPsveci0
+Tz7hj6mGbXMxzgCaVUptloxS+cccsIa/gpJaVirTgUyjaqLXQQXyepSuTjPcDIjO
+sKRYV+NOGpSSHTSBYNdPXWHC6m9bYJQNf7zFHikIuWwuqb1zthnubuMwe9juHVvv
+za7Qni/AbjLiazXvWtiqzUjo7k0TRlJq2UM/uKun2MCT5tRGTIj4v053U7MnxHlr
+05TJ7KDhxMzbSjkDWC/fQxSvPJiqfO241+rHRYl4/xGgN1mvk0SMU3Hpk/PzQZAu
+jw2/ztMIYV8NMe83GAIVdmZH0aDdUhHPYy8aED2UCfkCgYEA6mI6yJ17y3+llttD
+pZe9S3MvhQdJBRgRespT6vmatM+QjYZT49IG/VWhBwB91xP9qe4XwQpW7vUPAvTk
+mxX8QekY5JhCFQ29LUalKUswjGJ8j894ailvdNDtUIyVgjoBpBWj9VRYfY8F/6ew
+1mJ7CsIbTFcs06wXLqYy6Zxh2z8CgYEAzCB31gS5Y8VjncdZ0PvOBHTLxL4wStFp
+5Dw6dSzFZrB6PJc9xFqVS1ffdfNtzfIH9uT9ISNHSWq6F4JM1YipYg3LLraRTK2I
+KOr2B2fZllhKk3LUZcVouFWys4jM7976IGEHL1r973Av9iBXfRgakYMMihTu/ONA
+81YWb8gk6UUCgYB/fW78MK1lw8kOhbYGHMOahs0STyQo4S6g2+1JovvD3iOC185J
+3bRvmGQ+qsXId9dC13+UQUuIL0Q7F3pB4XOVZnVj4m4PhamhNwwfqgZ+VhPrJa8a
+D+/QWtS7O70XWPYLirnkeDyqD2Hz7gMCmg7Ti0HOBJ0dhj4V4dFPwQB5gQKBgQCe
+xu6P4bLWwXYgBy182jDA1Jyfl5R2zfeBGbwa4s1VeBZMxRO9hPw10880rzoNBKNf
+T3T57rgHimXf3XGocxnV9IbD+iyBKUYNFd5zmjrssBaqJJrD4s72+2n6LoHCX33N
+68sr8aouMeSMnVGQM0yPPRFm4quWt6oQ3TiskFDtxQKBgQCJraYImZDjd9hcPMk4
+dYY9RnX6NVSvsy9YTmie6W7HfjAfZqw1V/5MZXY0rnD/H+aqTttNaHHM0ANR7Z5H
+b9rbZArpM+AliJavMFYeooQPSpb87Vz2BR6ZVbJQFTJwFAP4krA5ypCDqTawQfXS
+hXNkIr8C4/CL0I0ho339Gp6o1g==
+-----END PRIVATE KEY-----
diff --git a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SshEndpointBuilderFactory.java b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SshEndpointBuilderFactory.java
index 73eabe8..3589d7f 100644
--- a/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SshEndpointBuilderFactory.java
+++ b/core/camel-endpointdsl/src/main/java/org/apache/camel/builder/endpoint/dsl/SshEndpointBuilderFactory.java
@@ -499,6 +499,17 @@ public interface SshEndpointBuilderFactory {
             return this;
         }
         /**
+         * Sets the password to use in loading certResource, if certResource is
+         * an encrypted key.
+         * The option is a <code>java.lang.String</code> type.
+         * @group security
+         */
+        default SshEndpointConsumerBuilder certResourcePassword(
+                String certResourcePassword) {
+            setProperty("certResourcePassword", certResourcePassword);
+            return this;
+        }
+        /**
          * Sets the KeyPairProvider reference to use when connecting using
          * Certificates to the remote SSH Server.
          * The option is a
@@ -868,6 +879,17 @@ public interface SshEndpointBuilderFactory {
             return this;
         }
         /**
+         * Sets the password to use in loading certResource, if certResource is
+         * an encrypted key.
+         * The option is a <code>java.lang.String</code> type.
+         * @group security
+         */
+        default SshEndpointProducerBuilder certResourcePassword(
+                String certResourcePassword) {
+            setProperty("certResourcePassword", certResourcePassword);
+            return this;
+        }
+        /**
          * Sets the KeyPairProvider reference to use when connecting using
          * Certificates to the remote SSH Server.
          * The option is a
@@ -1121,6 +1143,17 @@ public interface SshEndpointBuilderFactory {
             return this;
         }
         /**
+         * Sets the password to use in loading certResource, if certResource is
+         * an encrypted key.
+         * The option is a <code>java.lang.String</code> type.
+         * @group security
+         */
+        default SshEndpointBuilder certResourcePassword(
+                String certResourcePassword) {
+            setProperty("certResourcePassword", certResourcePassword);
+            return this;
+        }
+        /**
          * Sets the KeyPairProvider reference to use when connecting using
          * Certificates to the remote SSH Server.
          * The option is a
diff --git a/platforms/spring-boot/components-starter/camel-ssh-starter/src/main/java/org/apache/camel/component/ssh/springboot/SshComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-ssh-starter/src/main/java/org/apache/camel/component/ssh/springboot/SshComponentConfiguration.java
index b8e6a32..51d01c9 100644
--- a/platforms/spring-boot/components-starter/camel-ssh-starter/src/main/java/org/apache/camel/component/ssh/springboot/SshComponentConfiguration.java
+++ b/platforms/spring-boot/components-starter/camel-ssh-starter/src/main/java/org/apache/camel/component/ssh/springboot/SshComponentConfiguration.java
@@ -91,6 +91,11 @@ public class SshComponentConfiguration
      */
     private String certResource;
     /**
+     * Sets the password to use in loading certResource, if certResource is an
+     * encrypted key.
+     */
+    private String certResourcePassword;
+    /**
      * Sets the channel type to pass to the Channel as part of command
      * execution. Defaults to exec.
      */
@@ -198,6 +203,14 @@ public class SshComponentConfiguration
         this.certResource = certResource;
     }
 
+    public String getCertResourcePassword() {
+        return certResourcePassword;
+    }
+
+    public void setCertResourcePassword(String certResourcePassword) {
+        this.certResourcePassword = certResourcePassword;
+    }
+
     public String getChannelType() {
         return channelType;
     }
@@ -292,6 +305,11 @@ public class SshComponentConfiguration
          */
         private String certResource;
         /**
+         * Sets the password to use in loading certResource, if certResource is
+         * an encrypted key.
+         */
+        private String certResourcePassword;
+        /**
          * Sets the resource path for a known_hosts file
          */
         private String knownHostsResource;
@@ -399,6 +417,14 @@ public class SshComponentConfiguration
             this.certResource = certResource;
         }
 
+        public String getCertResourcePassword() {
+            return certResourcePassword;
+        }
+
+        public void setCertResourcePassword(String certResourcePassword) {
+            this.certResourcePassword = certResourcePassword;
+        }
+
         public String getKnownHostsResource() {
             return knownHostsResource;
         }