diff --git a/cli/pom.xml b/cli/pom.xml
index e7772b1bf228..a6623d626f42 100644
--- a/cli/pom.xml
+++ b/cli/pom.xml
@@ -72,7 +72,7 @@
org.apache.sshd
sshd-core
- 1.7.0
+ 2.6.0
true
diff --git a/cli/src/main/java/hudson/cli/PrivateKeyProvider.java b/cli/src/main/java/hudson/cli/PrivateKeyProvider.java
index 579aae6e536b..1dc5444a61d8 100644
--- a/cli/src/main/java/hudson/cli/PrivateKeyProvider.java
+++ b/cli/src/main/java/hudson/cli/PrivateKeyProvider.java
@@ -34,14 +34,20 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
+import java.nio.file.Paths;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyPair;
+import java.security.Security;
+import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
+import java.util.stream.StreamSupport;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
+import org.apache.sshd.common.util.io.resource.PathResource;
import org.apache.sshd.common.util.security.SecurityUtils;
/**
@@ -52,7 +58,7 @@
*/
public class PrivateKeyProvider {
- private List privateKeys = new ArrayList<>();
+ private final List privateKeys = new ArrayList<>();
/**
* Get keys read so far.
@@ -137,9 +143,18 @@ private static String readPemFile(File f) throws IOException{
}
public static KeyPair loadKey(String pemString, String passwd) throws IOException, GeneralSecurityException {
- return SecurityUtils.loadKeyPairIdentity("key",
+ Iterable itr = SecurityUtils.loadKeyPairIdentities(null,
+ new PathResource(Paths.get("key")),
new ByteArrayInputStream(pemString.getBytes(UTF_8)),
FilePasswordProvider.of(passwd));
+ long numLoaded = itr == null ? 0 : StreamSupport.stream(itr.spliterator(), false).count();
+ if (numLoaded <= 0) {
+ throw new InvalidKeyException("Unsupported private key file format: key");
+ }
+ if (numLoaded != 1) {
+ throw new InvalidKeySpecException("Multiple private key pairs N/A: key");
+ }
+ return itr.iterator().next();
}
private static final Logger LOGGER = Logger.getLogger(PrivateKeyProvider.class.getName());
diff --git a/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java b/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java
index b186263346ac..ab4b762a6ee8 100644
--- a/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java
+++ b/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java
@@ -7,10 +7,10 @@
import java.io.File;
import java.io.IOException;
-import java.lang.IllegalArgumentException;
import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -81,13 +81,44 @@ public void loadKeyOpenSSH() throws IOException, GeneralSecurityException {
}
/**
- key command: ssh-keygen -f openssh-unsupported -t rsa -b 1024 -p password
- */
+ key command: ssh-keygen -f openssh-unsupported -t rsa -b 1024 -m PKCS8 -p password
+ */
+ @Test
+ public void loadKeyOpenSSHPKCS8() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("openssh-pkcs8").getFile());
+ String password = "password";
+ assertKeyPairNotNull(file, password);
+ }
+
+ /**
+ key command: ssh-keygen -f openssh-unsupported -t rsa -b 1024 -m RFC4716 -p password
+ */
+ @Test
+ public void loadKeyOpenSSHRFC4716() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("openssh-rfc4716").getFile());
+ String password = "password";
+ assertKeyPairNotNull(file, password);
+ }
+
+ /**
+ key command: ssh-keygen -f openssh-unsupported -t rsa -b 1024 -m RFC4716 -p password
+ Copy pasted the same key twice
+ */
+ @Test
+ public void loadKeyOpenSSHMultipleKeys() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("openssh-multiple-keys").getFile());
+ String password = "password";
+ assertThrows(InvalidKeySpecException.class, () -> PrivateKeyProvider.loadKey(file, password));
+ }
+
+ /**
+ * Uses a blank file
+ */
@Test
- public void loadKeyUnsupportedCipher() throws IOException, GeneralSecurityException {
- File file = new File(this.getClass().getResource("openssh-unsuported").getFile());
+ public void loadBlankKey() throws IOException, GeneralSecurityException {
+ File file = new File(this.getClass().getResource("blank").getFile());
String password = "password";
- assertThrows(NoSuchAlgorithmException.class, () -> PrivateKeyProvider.loadKey(file, password));
+ assertThrows(InvalidKeyException.class, () -> PrivateKeyProvider.loadKey(file, password));
}
/**
diff --git a/cli/src/test/resources/hudson/cli/blank b/cli/src/test/resources/hudson/cli/blank
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/cli/src/test/resources/hudson/cli/openssh-multiple-keys b/cli/src/test/resources/hudson/cli/openssh-multiple-keys
new file mode 100644
index 000000000000..be36fb99a579
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/openssh-multiple-keys
@@ -0,0 +1,35 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB7+Wg6qP
+jwYDqZ6ghEjcxsAAAAEAAAAAEAAACXAAAAB3NzaC1yc2EAAAADAQABAAAAgQDDQX8IscJ6
+Axj5nni6lv4uh6w+CyNfsItKdLBj2KaohA7fcgpL2DrjcYo0Z9W74jbVRSW9mcCp/6Kdfl
+JumpnUjpx7QBlUcnKIakpFuIHJl8HcHDLusy/R1RB1H/ShXqkHfPT3JmSbo1iwrGS4UFSq
+S/KZsfKNph4x/vbyizUlPQAAAiAhHAwqGb+KrmywoeqT/QkWflUH/aRy7iZM9rYx7ROh2K
+FY143YePB66yCczropqQPFn4hgf2wxSEsvMLKnBy44ruUl7w8O/mmsO993DkXmtVTHdipz
+vWHZLtSFe2IB1IFAoGGcOeGFIBKQ6DfIVWPaPRFF+jmpVpn19qYpkxmp6uBq8guViXmoTV
+eM/r46ipHYQ57BVopYnUQrxa13p7PZQRmrfNapfAgJpvvJxHjO9RFUeJndWNKVbCXblc24
+TTQ5EUxlLrTsRhH5ICdTSvPnm50I8yjiIZVOXNkPn8UOrj2yVaU2LDkFnbzB4EJIEtdmVb
+iavgaTO/TURIS5b7oa21rVnYVacUmhZyBRgo/abu49ovvTyyNGk+MIgtmgbq8NZunBP/Te
+HpaeTgZm9uMOFy7ni/S9raMYzKun8dCoNaEES/WIFBdAtw3SY2eLXYVRVKI1dk2q3swhiL
+t+M81BfSzCrBzqENyrRSvbMIV0fI6Kvc8Kq5aNIPw5JIFTNYc0c8JWyxf72Is4PffyCrK7
+7qGrXiU/fys1j+LCQUg7UOLaMnYetY+JnN7Z284J59YsvFnyjoZnCJeS6Ewy6s8alLDi3k
+da3VASzohO4j1mD1HWVYG/eEWMxcX5TkyxaMcXkpFkR/lEXZXMr0y+1mgICefspMsi+OSf
+1xrbdd5CNbELWRD88BOuIKFhdThx9C2A65AKGpCt7UkFfNB2pCm6
+-----END OPENSSH PRIVATE KEY-----
+
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB7+Wg6qP
+jwYDqZ6ghEjcxsAAAAEAAAAAEAAACXAAAAB3NzaC1yc2EAAAADAQABAAAAgQDDQX8IscJ6
+Axj5nni6lv4uh6w+CyNfsItKdLBj2KaohA7fcgpL2DrjcYo0Z9W74jbVRSW9mcCp/6Kdfl
+JumpnUjpx7QBlUcnKIakpFuIHJl8HcHDLusy/R1RB1H/ShXqkHfPT3JmSbo1iwrGS4UFSq
+S/KZsfKNph4x/vbyizUlPQAAAiAhHAwqGb+KrmywoeqT/QkWflUH/aRy7iZM9rYx7ROh2K
+FY143YePB66yCczropqQPFn4hgf2wxSEsvMLKnBy44ruUl7w8O/mmsO993DkXmtVTHdipz
+vWHZLtSFe2IB1IFAoGGcOeGFIBKQ6DfIVWPaPRFF+jmpVpn19qYpkxmp6uBq8guViXmoTV
+eM/r46ipHYQ57BVopYnUQrxa13p7PZQRmrfNapfAgJpvvJxHjO9RFUeJndWNKVbCXblc24
+TTQ5EUxlLrTsRhH5ICdTSvPnm50I8yjiIZVOXNkPn8UOrj2yVaU2LDkFnbzB4EJIEtdmVb
+iavgaTO/TURIS5b7oa21rVnYVacUmhZyBRgo/abu49ovvTyyNGk+MIgtmgbq8NZunBP/Te
+HpaeTgZm9uMOFy7ni/S9raMYzKun8dCoNaEES/WIFBdAtw3SY2eLXYVRVKI1dk2q3swhiL
+t+M81BfSzCrBzqENyrRSvbMIV0fI6Kvc8Kq5aNIPw5JIFTNYc0c8JWyxf72Is4PffyCrK7
+7qGrXiU/fys1j+LCQUg7UOLaMnYetY+JnN7Z284J59YsvFnyjoZnCJeS6Ewy6s8alLDi3k
+da3VASzohO4j1mD1HWVYG/eEWMxcX5TkyxaMcXkpFkR/lEXZXMr0y+1mgICefspMsi+OSf
+1xrbdd5CNbELWRD88BOuIKFhdThx9C2A65AKGpCt7UkFfNB2pCm6
+-----END OPENSSH PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/openssh-pkcs8 b/cli/src/test/resources/hudson/cli/openssh-pkcs8
new file mode 100644
index 000000000000..9c17399c3b2e
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/openssh-pkcs8
@@ -0,0 +1,17 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDvGXdAqe
+A3cfETZNuKc2qEAAAAEAAAAAEAAACXAAAAB3NzaC1yc2EAAAADAQABAAAAgQDNj316M4aw
+DJHITn0XzcGapC6+vkXOLSwD/hK8qC6cp/FPEPrOo20jxRiTrd00/M6SbfeJR+wUyZl4V5
+mz8RPKGjVFtktZ5jQJZ3QY4Jqtpc5iMxQfMXmcV0UBJaom8zc7vHSdsH2XrM+xt9Tvrob3
+wQIMjLbwj7cjcHh/1b7iywAAAiDP15QQ8FKnRgbnbRgwuOoEpAqMEt0z7l4CJE6WAQ8hCU
+YyvDFs6c9LPftxa0BlS/INKC3hblqs35X24iU8XzKWTZL3ac99/AfC4Mru9NhpOme1Xdi6
+ZWpjbakqyGHeBX9ERnxcGb/hlKsWErdsMttKFgOm5WvnlOb/Rywt74zIJdq6/LTWvwjgQi
+mF5yZSsJuZiFaq9fASul1gLFikhdxVPGHtI+pzDCviC2UkPdI8jVnqBEzDl7ewjZdcHykX
+hZW+LxbxjKRxrFPSn8prxPqRwAbM4bWoeyh0Y1F+DUaWS9LQjMyG2eHM5RCJdjb8V3NNpH
+vOFD213akcrA7X6lQFlbI5wbVgfMQ6Zo4EGlSA8f9U9fMuBhL24Opbb1d7PFaJLUnw/mJl
+BlqHS2LMaTz5k/dhwVKZfaDLq6Q1RJ/0toJN6LtlQjz5DU7tmUwNmt5/CYtkjMHUQWffk9
+WQ7hPSmKiO2m07zfmwuE2Hdihbb5o2imDuBbTz129Dr5OyqhMcmAxg4GAIZBCjdlUItaAP
+y9ieAVgG4gPYn1tYYa8259Gjug+v8rWzvjdRuUW21gv+quQ+yx1Q1/dErxP8m6VU6pdE7b
+3TgQH+sxdXZpOksYLpuDBZ6KNdkDtQjWCCfkDCXm/4Pr5ljyu5n56YDBYyzbxq+Amsc02S
+iC8i6JQjGsnvJzuGMbmrr1qE99vbRnwWJAeZsjh3U4ResfZ5mAgs
+-----END OPENSSH PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/openssh-rfc4716 b/cli/src/test/resources/hudson/cli/openssh-rfc4716
new file mode 100644
index 000000000000..af0075e9cc5b
--- /dev/null
+++ b/cli/src/test/resources/hudson/cli/openssh-rfc4716
@@ -0,0 +1,17 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABB7+Wg6qP
+jwYDqZ6ghEjcxsAAAAEAAAAAEAAACXAAAAB3NzaC1yc2EAAAADAQABAAAAgQDDQX8IscJ6
+Axj5nni6lv4uh6w+CyNfsItKdLBj2KaohA7fcgpL2DrjcYo0Z9W74jbVRSW9mcCp/6Kdfl
+JumpnUjpx7QBlUcnKIakpFuIHJl8HcHDLusy/R1RB1H/ShXqkHfPT3JmSbo1iwrGS4UFSq
+S/KZsfKNph4x/vbyizUlPQAAAiAhHAwqGb+KrmywoeqT/QkWflUH/aRy7iZM9rYx7ROh2K
+FY143YePB66yCczropqQPFn4hgf2wxSEsvMLKnBy44ruUl7w8O/mmsO993DkXmtVTHdipz
+vWHZLtSFe2IB1IFAoGGcOeGFIBKQ6DfIVWPaPRFF+jmpVpn19qYpkxmp6uBq8guViXmoTV
+eM/r46ipHYQ57BVopYnUQrxa13p7PZQRmrfNapfAgJpvvJxHjO9RFUeJndWNKVbCXblc24
+TTQ5EUxlLrTsRhH5ICdTSvPnm50I8yjiIZVOXNkPn8UOrj2yVaU2LDkFnbzB4EJIEtdmVb
+iavgaTO/TURIS5b7oa21rVnYVacUmhZyBRgo/abu49ovvTyyNGk+MIgtmgbq8NZunBP/Te
+HpaeTgZm9uMOFy7ni/S9raMYzKun8dCoNaEES/WIFBdAtw3SY2eLXYVRVKI1dk2q3swhiL
+t+M81BfSzCrBzqENyrRSvbMIV0fI6Kvc8Kq5aNIPw5JIFTNYc0c8JWyxf72Is4PffyCrK7
+7qGrXiU/fys1j+LCQUg7UOLaMnYetY+JnN7Z284J59YsvFnyjoZnCJeS6Ewy6s8alLDi3k
+da3VASzohO4j1mD1HWVYG/eEWMxcX5TkyxaMcXkpFkR/lEXZXMr0y+1mgICefspMsi+OSf
+1xrbdd5CNbELWRD88BOuIKFhdThx9C2A65AKGpCt7UkFfNB2pCm6
+-----END OPENSSH PRIVATE KEY-----
diff --git a/cli/src/test/resources/hudson/cli/openssh-unsuported b/cli/src/test/resources/hudson/cli/openssh-unsuported
deleted file mode 100644
index 4ed6878f12c8..000000000000
--- a/cli/src/test/resources/hudson/cli/openssh-unsuported
+++ /dev/null
@@ -1,17 +0,0 @@
------BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDIzkiSdr
-mRRbRY1S2YtBacAAAAEAAAAAEAAACXAAAAB3NzaC1yc2EAAAADAQABAAAAgQCpXxUyU7MR
-b4GrSMnufZb6kaBb1lHBywI7+dBNnpHyq1rpZJRi36lpxxZoaiG+inOeSBh7QPnDVvm2aN
-DdT7V0PFzfZKWzxl2PRSd6EIXUsaaXuqaFcJM7rSqU1EB+9qM9JfGIqkdNKwzGdu3kdJJG
-3VQQUQVtYXAOLIrApslndQAAAiDAF+/lDARNPSMcOlH6uGqfSBszQBwOf22df5yGHLbnpi
-e5yslN+9Z3jFrl2XNDb8sD9e7gZtB/CbkJaDqFCqSOoW979xLLl89jJYle2L48SBbpV7i2
-0/51YYrxs4/75kJUd8uMaOBpNanyI8CBqA5IPmms1NLrSOpAbU20imQNoLUb1B8v2zNBxo
-R64UyU8AkKDMwPmAHwdrM73c7eirAsuVknhg0fFjy4iCxurqz5RO0Hpjf8GHfaCh37gim/
-8f/XqwS+MlAn9KaAGi4hZJFaSuyPPVLmRTS+gleoM0zSt5J+Fvdrs/JnL/XIpf64QZafKZ
-HyiZXnbJKxWhhhpslHz6QoiZ76LxwRS6bP//fsl7KWPY6IUGMD8h6JGi8o6xpsj16xIGUf
-7K+c9TNcjzaO8jtC8ggaixoKdC48LdenfdaagAtBgyWQqxfxTg9ZLiQ2lrZIaF4C0aZi3+
-byeT/mzPyh6aSAsBETjHCbdy/ixi0BNbDB10LlD44J8i9yBROk7WQtM3lJL78Va4KfxSCC
-dsJQPu1ABZEr1SGVqVprUaM43C/VKZk5PjXmkbAy5TCztztiWwa8HtKk4V7sH4G/ENjAtJ
-w2SEybRTx0WNhD9viTSu8z+BqH1mWP2ek/orE0OWU+H6r1zSoBo9scvpUrLC2NYvcUMw+I
-cDupua/5kKQgTzY+kEyRClwvziHEVe4TLZen3UMf2GM3fVC9AUC8
------END OPENSSH PRIVATE KEY-----