diff --git a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java index eb857fb87..f7f41d3e1 100644 --- a/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java +++ b/src/main/java/net/schmizz/sshj/userauth/keyprovider/KeyProviderUtil.java @@ -51,8 +51,7 @@ public static KeyFormat detectKeyFileFormat(File location) * @return name of the key file format * @throws java.io.IOException */ - public static KeyFormat detectKeyFileFormat(String privateKey, - boolean separatePubKey) + public static KeyFormat detectKeyFileFormat(String privateKey, boolean separatePubKey) throws IOException { return detectKeyFileFormat(new StringReader(privateKey), separatePubKey); } @@ -67,35 +66,44 @@ public static KeyFormat detectKeyFileFormat(String privateKey, * @return name of the key file format * @throws java.io.IOException */ - public static KeyFormat detectKeyFileFormat(Reader privateKey, - boolean separatePubKey) + public static KeyFormat detectKeyFileFormat(Reader privateKey, boolean separatePubKey) throws IOException { + String header = readHeader(privateKey); + if (header == null) { + throw new IOException("Empty file"); + } + return keyFormatFromHeader(header, separatePubKey); + } + + private static String readHeader(Reader privateKey) throws IOException { BufferedReader br = new BufferedReader(privateKey); - final String firstLine; try { - firstLine = br.readLine(); - } - finally { + String header; + while ((header = br.readLine()) != null) { + header = header.trim(); + if (!header.isEmpty()) { + break; + } + } + return header; + } finally { IOUtils.closeQuietly(br); } - if(firstLine == null) { - throw new IOException("Empty file"); - } - if(firstLine.startsWith("-----BEGIN") && firstLine.endsWith("PRIVATE KEY-----")) { - if(separatePubKey) - // Can delay asking for password since have unencrypted pubkey - { + } + + private static KeyFormat keyFormatFromHeader(String header, boolean separatePubKey) { + if (header.startsWith("-----BEGIN") && header.endsWith("PRIVATE KEY-----")) { + if (separatePubKey) { + // Can delay asking for password since have unencrypted pubkey return KeyFormat.OpenSSH; - } - else - // More general - { + } else { + // More general return KeyFormat.PKCS8; } - } - if(firstLine.startsWith("PuTTY-User-Key-File-")) { + } else if (header.startsWith("PuTTY-User-Key-File-")) { return KeyFormat.PuTTY; + } else { + return KeyFormat.Unknown; } - return KeyFormat.Unknown; } } diff --git a/src/test/java/net/schmizz/sshj/keyprovider/KeyProviderUtilTest.java b/src/test/java/net/schmizz/sshj/keyprovider/KeyProviderUtilTest.java new file mode 100644 index 000000000..a599657cf --- /dev/null +++ b/src/test/java/net/schmizz/sshj/keyprovider/KeyProviderUtilTest.java @@ -0,0 +1,40 @@ +package net.schmizz.sshj.keyprovider; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; + +import org.junit.Test; + +import net.schmizz.sshj.userauth.keyprovider.KeyFormat; +import net.schmizz.sshj.userauth.keyprovider.KeyProviderUtil; + +public class KeyProviderUtilTest { + + private static final File ROOT = new File("src/test/resources/keyformats"); + + @Test + public void testOpenSsh() throws IOException { + KeyFormat format = KeyProviderUtil.detectKeyFileFormat(new File(ROOT, "openssh")); + assertEquals(KeyFormat.OpenSSH, format); + } + + @Test + public void testPkcs8() throws IOException { + KeyFormat format = KeyProviderUtil.detectKeyFileFormat(new File(ROOT, "pkcs8")); + assertEquals(KeyFormat.PKCS8, format); + } + + @Test + public void testPutty() throws IOException { + KeyFormat format = KeyProviderUtil.detectKeyFileFormat(new File(ROOT, "putty")); + assertEquals(KeyFormat.PuTTY, format); + } + + @Test + public void testSkipsBlankLines() throws IOException { + KeyFormat format = KeyProviderUtil.detectKeyFileFormat(new File(ROOT, "pkcs8-blanks")); + assertEquals(KeyFormat.PKCS8, format); + } +} diff --git a/src/test/resources/keyformats/openssh b/src/test/resources/keyformats/openssh new file mode 100644 index 000000000..221453d8a --- /dev/null +++ b/src/test/resources/keyformats/openssh @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCm2IJ9gWDkPTlQ37NNUB0za5mCsQ8bi++8fyEqw7wl8ZNBh3qt +TcnL+m+NZfQjUC0BXic7PcMLVm4A3ID2IAZQM+axfq9aL4huWerm4ua6tvdt4gQK +oL1+8JFmdFvFw5pWW/NZHtkIprbVf7KtYrU27WmMhXruN071UzqLsw08cwIDAQAB +AoGAHQ7cOyuLSnT3RISRX8eyLkBxLffUX8HRcQzbI+2PGTSnpuQHk6NWn/Xv87pr ++LKABBr3zjOFgrX81p2QwEz3jDxNXzbOeZzhuvGXCX5GocuEO4n5EhDvXRDF4uht +uvVV5FsQv/sTOR0PNo1nELiAA8k3NYDxraB83q7wtsmErtECQQDYWMnq8mwRe49d +jIXNKJeNiuLUYxO3CLI/vx279gDKlKrt677trr1e7JZqm/DapEWG511tw3cW63gQ ++qxtgkw1AkEAxW0UeaNaJd7DApqwGAcS1JkygCKwzQ4ns/Co15qUgMkqCkmQU9AU +/zQpt2+BjdYVe50r/nr8K1KYwrBsyndrBwJBALe90N+FvFqswfoFmq2/R9eimTsg +WmIdNKYHPs2gBNQIp5MhoSpkOdkgvi8U+d33nkUQwryyQbZpjbN98mufOfECQEML +eBiW0NZrf+4yefqu7EYmgG/jWAdK91C0OaJ+bFAQAKbdtJXB5F+GZ2RUCbsRKNqB +1Z7mRRyxQA9dupRHWaECQQCM9bbCtfGesgvZlhBavlWavu8iCvJlAbGdf5QMlFQE +kABmZg84Fy3NUFCD+RXCuatb4Oo9P/WPIbjYiC4p0hLJ +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/keyformats/openssh.pub b/src/test/resources/keyformats/openssh.pub new file mode 100644 index 000000000..39c3f9a06 --- /dev/null +++ b/src/test/resources/keyformats/openssh.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCm2IJ9gWDkPTlQ37NNUB0za5mCsQ8bi++8fyEqw7wl8ZNBh3qtTcnL+m+NZfQjUC0BXic7PcMLVm4A3ID2IAZQM+axfq9aL4huWerm4ua6tvdt4gQKoL1+8JFmdFvFw5pWW/NZHtkIprbVf7KtYrU27WmMhXruN071UzqLsw08cw== diff --git a/src/test/resources/keyformats/pkcs8 b/src/test/resources/keyformats/pkcs8 new file mode 100644 index 000000000..221453d8a --- /dev/null +++ b/src/test/resources/keyformats/pkcs8 @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCm2IJ9gWDkPTlQ37NNUB0za5mCsQ8bi++8fyEqw7wl8ZNBh3qt +TcnL+m+NZfQjUC0BXic7PcMLVm4A3ID2IAZQM+axfq9aL4huWerm4ua6tvdt4gQK +oL1+8JFmdFvFw5pWW/NZHtkIprbVf7KtYrU27WmMhXruN071UzqLsw08cwIDAQAB +AoGAHQ7cOyuLSnT3RISRX8eyLkBxLffUX8HRcQzbI+2PGTSnpuQHk6NWn/Xv87pr ++LKABBr3zjOFgrX81p2QwEz3jDxNXzbOeZzhuvGXCX5GocuEO4n5EhDvXRDF4uht +uvVV5FsQv/sTOR0PNo1nELiAA8k3NYDxraB83q7wtsmErtECQQDYWMnq8mwRe49d +jIXNKJeNiuLUYxO3CLI/vx279gDKlKrt677trr1e7JZqm/DapEWG511tw3cW63gQ ++qxtgkw1AkEAxW0UeaNaJd7DApqwGAcS1JkygCKwzQ4ns/Co15qUgMkqCkmQU9AU +/zQpt2+BjdYVe50r/nr8K1KYwrBsyndrBwJBALe90N+FvFqswfoFmq2/R9eimTsg +WmIdNKYHPs2gBNQIp5MhoSpkOdkgvi8U+d33nkUQwryyQbZpjbN98mufOfECQEML +eBiW0NZrf+4yefqu7EYmgG/jWAdK91C0OaJ+bFAQAKbdtJXB5F+GZ2RUCbsRKNqB +1Z7mRRyxQA9dupRHWaECQQCM9bbCtfGesgvZlhBavlWavu8iCvJlAbGdf5QMlFQE +kABmZg84Fy3NUFCD+RXCuatb4Oo9P/WPIbjYiC4p0hLJ +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/keyformats/pkcs8-blanks b/src/test/resources/keyformats/pkcs8-blanks new file mode 100644 index 000000000..b49fac327 --- /dev/null +++ b/src/test/resources/keyformats/pkcs8-blanks @@ -0,0 +1,18 @@ + + + +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCm2IJ9gWDkPTlQ37NNUB0za5mCsQ8bi++8fyEqw7wl8ZNBh3qt +TcnL+m+NZfQjUC0BXic7PcMLVm4A3ID2IAZQM+axfq9aL4huWerm4ua6tvdt4gQK +oL1+8JFmdFvFw5pWW/NZHtkIprbVf7KtYrU27WmMhXruN071UzqLsw08cwIDAQAB +AoGAHQ7cOyuLSnT3RISRX8eyLkBxLffUX8HRcQzbI+2PGTSnpuQHk6NWn/Xv87pr ++LKABBr3zjOFgrX81p2QwEz3jDxNXzbOeZzhuvGXCX5GocuEO4n5EhDvXRDF4uht +uvVV5FsQv/sTOR0PNo1nELiAA8k3NYDxraB83q7wtsmErtECQQDYWMnq8mwRe49d +jIXNKJeNiuLUYxO3CLI/vx279gDKlKrt677trr1e7JZqm/DapEWG511tw3cW63gQ ++qxtgkw1AkEAxW0UeaNaJd7DApqwGAcS1JkygCKwzQ4ns/Co15qUgMkqCkmQU9AU +/zQpt2+BjdYVe50r/nr8K1KYwrBsyndrBwJBALe90N+FvFqswfoFmq2/R9eimTsg +WmIdNKYHPs2gBNQIp5MhoSpkOdkgvi8U+d33nkUQwryyQbZpjbN98mufOfECQEML +eBiW0NZrf+4yefqu7EYmgG/jWAdK91C0OaJ+bFAQAKbdtJXB5F+GZ2RUCbsRKNqB +1Z7mRRyxQA9dupRHWaECQQCM9bbCtfGesgvZlhBavlWavu8iCvJlAbGdf5QMlFQE +kABmZg84Fy3NUFCD+RXCuatb4Oo9P/WPIbjYiC4p0hLJ +-----END RSA PRIVATE KEY----- diff --git a/src/test/resources/keyformats/putty b/src/test/resources/keyformats/putty new file mode 100644 index 000000000..1e002b481 --- /dev/null +++ b/src/test/resources/keyformats/putty @@ -0,0 +1,19 @@ +PuTTY-User-Key-File-2: ssh-rsa +Encryption: none +Comment: rsa-key-20150817 +Public-Lines: 4 +AAAAB3NzaC1yc2EAAAABJQAAAIEAhoCAakZdrCNrHNpJHRIED4movsposAlk4ZPz +n/IFGkiIZOWRF/p4Sq+CaLigamwpe3f2/vYxCwtF3oCcJMQdn6CLYytHgrC2pRWa +bNBBClSO4jzWMlBRBZnzXBHKJ04kviqIybEvrN2weg5ArSOK7297DU2id+kDxSJz +QleZ+9c= +Private-Lines: 8 +AAAAgBItCm858PuWFWTDjVb0mMPUVRLdFRDerMSJnXZ6pr5c1ClPdHjcqHjLnABQ +TQd2Znh3/siCIk2ZvVVrU17qEdcZyivntbi8NuehqcVQr2ny8pc+sXvxXv2inoA3 +4mIVqjhIoljYf1VWgDXUxUsGU6QZdMfkDCEuoxL9QM7RdFXNAAAAQQDk01miHj3M +LozpMovCU2oKDFLsmOrXe7jroff2sM4BX5Iwym4N197O7ZIs5E52K0bWIDH9SouX +RTseqiHsPxexAAAAQQCWeZFwG7qm8cyAGSzsDsN35cmzgkvlFl4uIuJ9jh0S2Yt5 +2couD/AoQVmHqGaxwYPc+q24yvbFbjCxtlkqMTYHAAAAQQCcpItltKrhNW2svG2P +NuOi0TQmMZQigMOYQx4wd/8G2n+nr0Qsi4wuq/qccgKViVRyobB7nxQqoJdGAI90 +ECNG +Private-MAC: 4f200e5f5b766351b996d92f3b733b671b9ff957 +