Skip to content

Commit

Permalink
Improved malformed file handling for OpenSSH Private Keys (#898)
Browse files Browse the repository at this point in the history
  • Loading branch information
exceptionfactory authored Oct 9, 2023
1 parent f4d34d8 commit 461c0e4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,19 @@ public void init(File location) {

@Override
protected KeyPair readKeyPair() throws IOException {
BufferedReader reader = new BufferedReader(resource.getReader());
final BufferedReader reader = new BufferedReader(resource.getReader());
try {
if (!checkHeader(reader)) {
throw new IOException("This key is not in 'openssh-key-v1' format");
if (checkHeader(reader)) {
final String encodedPrivateKey = readEncodedKey(reader);
byte[] decodedPrivateKey = Base64.getDecoder().decode(encodedPrivateKey);
final PlainBuffer bufferedPrivateKey = new PlainBuffer(decodedPrivateKey);
return readDecodedKeyPair(bufferedPrivateKey);
} else {
final String message = String.format("File header not found [%s%s]", BEGIN, OPENSSH_PRIVATE_KEY);
throw new IOException(message);
}

String keyFile = readKeyFile(reader);
byte[] decode = Base64.getDecoder().decode(keyFile);
PlainBuffer keyBuffer = new PlainBuffer(decode);
return readDecodedKeyPair(keyBuffer);

} catch (GeneralSecurityException e) {
throw new SSHRuntimeException(e);
} catch (final GeneralSecurityException e) {
throw new SSHRuntimeException("Read OpenSSH Version 1 Key failed", e);
} finally {
IOUtils.closeQuietly(reader);
}
Expand Down Expand Up @@ -149,7 +149,7 @@ private KeyPair readDecodedKeyPair(final PlainBuffer keyBuffer) throws IOExcepti
logger.debug("Reading unencrypted keypair");
return readUnencrypted(privateKeyBuffer, publicKey);
} else {
logger.info("Keypair is encrypted with: " + cipherName + ", " + kdfName + ", " + Arrays.toString(kdfOptions));
logger.info("Keypair is encrypted with: {}, {}, {}", cipherName, kdfName, Arrays.toString(kdfOptions));
while (true) {
PlainBuffer decryptionBuffer = new PlainBuffer(privateKeyBuffer);
PlainBuffer decrypted = decryptBuffer(decryptionBuffer, cipherName, kdfName, kdfOptions);
Expand Down Expand Up @@ -209,14 +209,26 @@ private PublicKey readPublicKey(final PlainBuffer plainBuffer) throws Buffer.Buf
return KeyType.fromString(plainBuffer.readString()).readPubKeyFromBuffer(plainBuffer);
}

private String readKeyFile(final BufferedReader reader) throws IOException {
StringBuilder sb = new StringBuilder();
private String readEncodedKey(final BufferedReader reader) throws IOException {
final StringBuilder builder = new StringBuilder();

boolean footerFound = false;
String line = reader.readLine();
while (!line.startsWith(END)) {
sb.append(line);
while (line != null) {
if (line.startsWith(END)) {
footerFound = true;
break;
}
builder.append(line);
line = reader.readLine();
}
return sb.toString();

if (footerFound) {
return builder.toString();
} else {
final String message = String.format("File footer not found [%s%s]", END, OPENSSH_PRIVATE_KEY);
throw new IOException(message);
}
}

private boolean checkHeader(final BufferedReader reader) throws IOException {
Expand Down Expand Up @@ -244,7 +256,7 @@ private KeyPair readUnencrypted(final PlainBuffer keyBuffer, final PublicKey pub
// The private key section contains both the public key and the private key
String keyType = keyBuffer.readString(); // string keytype
KeyType kt = KeyType.fromString(keyType);
logger.info("Read key type: {}", keyType, kt);

KeyPair kp;
switch (kt) {
case ED25519:
Expand Down
19 changes: 17 additions & 2 deletions src/test/java/net/schmizz/sshj/keyprovider/OpenSSHKeyFileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import net.schmizz.sshj.userauth.password.PasswordUtils;
import net.schmizz.sshj.userauth.password.Resource;
import net.schmizz.sshj.util.KeyUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

Expand Down Expand Up @@ -226,6 +225,22 @@ public void shouldLoadED25519PrivateKey() throws IOException {
assertThat(aPrivate.getAlgorithm(), equalTo("EdDSA"));
}

@Test
public void shouldHandlePrivateKeyMissingHeader() {
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
keyFile.init(new File("src/test/resources/keyformats/pkcs8"));
final IOException exception = assertThrows(IOException.class, keyFile::getPrivate);
assertTrue(exception.getMessage().contains("header not found"));
}

@Test
public void shouldHandlePrivateKeyMissingFooter() {
final OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
keyFile.init(new File("src/test/resources/keytypes/test_ed25519_missing_footer"));
final IOException exception = assertThrows(IOException.class, keyFile::getPrivate);
assertTrue(exception.getMessage().contains("footer not found"));
}

@Test
public void shouldLoadProtectedED25519PrivateKeyAes256CTR() throws IOException {
checkOpenSSHKeyV1("src/test/resources/keytypes/ed25519_protected", "sshjtest", false);
Expand All @@ -245,7 +260,7 @@ public void shouldLoadProtectedED25519PrivateKeyAes128CBC() throws IOException {
}

@Test
public void shouldFailOnIncorrectPassphraseAfterRetries() throws IOException {
public void shouldFailOnIncorrectPassphraseAfterRetries() {
assertThrows(KeyDecryptionFailedException.class, () -> {
OpenSSHKeyV1KeyFile keyFile = new OpenSSHKeyV1KeyFile();
keyFile.init(new File("src/test/resources/keytypes/ed25519_aes256cbc.pem"), new PasswordFinder() {
Expand Down
6 changes: 6 additions & 0 deletions src/test/resources/keytypes/test_ed25519_missing_footer
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAwHSYkZJATPMgvLHkxKAJ9j38Gyyq5HGoWdMcT6FiAiQAAAJDimgR84poE
fAAAAAtzc2gtZWQyNTUxOQAAACAwHSYkZJATPMgvLHkxKAJ9j38Gyyq5HGoWdMcT6FiAiQ
AAAECmsckQycWnfGQK6XtQpaMGODbAkMQOdJNK6XJSipB7dDAdJiRkkBM8yC8seTEoAn2P
fwbLKrkcahZ0xxPoWICJAAAACXJvb3RAc3NoagECAwQ=

0 comments on commit 461c0e4

Please sign in to comment.