DEV Community

dpm_bush
dpm_bush

Posted on Originally published at sshflow.com

Fixing the SSH “error in libcrypto” Private Key Error

When SSH reports Load key "...": error in libcrypto, it usually hasn’t reached the server’s authentication step. The client couldn’t parse the private-key data it was given. That points you toward the local key file or the way a script supplies it—not toward a network problem or, by itself, a compromised key.

The same parsing failure can appear as Error loading key "(stdin)": error in libcrypto when a command such as ssh-add - reads key data from standard input.

Start by testing the exact key file

Use ssh-keygen -y to check whether OpenSSH can read the private key independently of SSH, Git, an agent, or a CI pipeline:

ssh-keygen -y -f /path/to/private_key
Enter fullscreen mode Exit fullscreen mode

If the key is encrypted, this may prompt for its passphrase. If it succeeds, it prints the corresponding public key. If it produces the same libcrypto error, the file or its format needs attention. If it succeeds but another command fails, check whether that command is using the same file and SSH client.

Keep the output in mind: this command prints a public key, but do not print or paste the private key into logs or shared output.

Check the simple file problems first

A key copied between systems or pasted into a secret field may have been changed along the way. Check that the file is complete, has its expected -----BEGIN ... KEY----- and -----END ... KEY----- lines, and hasn’t acquired quote characters or other extra text. Compare it with a known-good copy if you have one; don’t try to reconstruct missing key data by hand.

Also make sure the path points to the private key, not its matching .pub public-key file. A public key cannot be used in place of a private key.

A missing final newline can matter in some key-handling workflows. To inspect the ending bytes on Linux, use:

tail -c 50 /path/to/private_key | xxd | tail -3
Enter fullscreen mode Exit fullscreen mode

If you confirm the file is otherwise intact and simply lacks a final line break, you can add one:

printf '\n' >> /path/to/private_key
Enter fullscreen mode Exit fullscreen mode

Don’t append a newline blindly to a file you haven’t checked. If the ending is already correct, look at other causes instead.

Check for Windows line endings

Carriage-return characters (\r) can cause key-loading trouble with some OpenSSH builds and key-format paths. This is worth checking if the key started failing after it was edited or copied on Windows.

If dos2unix is installed, it can normalize the file in place:

dos2unix /path/to/private_key
Enter fullscreen mode Exit fullscreen mode

Or use sed:

sed -i 's/\r$//' /path/to/private_key
Enter fullscreen mode Exit fullscreen mode

To preserve the original while testing a cleaned copy:

tr -d '\r' < /path/to/private_key > /path/to/private_key.fixed
ssh-keygen -y -f /path/to/private_key.fixed
Enter fullscreen mode Exit fullscreen mode

On Windows, the built-in OpenSSH client and Git for Windows’ bundled OpenSSH are separate builds. If a key still fails in Git Bash after checking line endings, compare which client is being used. In PowerShell, where.exe ssh shows the available ssh executable paths.

If it only fails in CI or through ssh-add

A key that works as a file locally but fails in a pipeline may be altered while being stored or reconstructed. Common suspects include lost newlines, carriage returns, shell quoting, YAML parsing, or a script that passes only part of a multiline value.

If the error names (stdin), test the original file first with ssh-keygen -y -f. If that succeeds, inspect the pipe or script that supplies the key. For example, a GitLab job may pass a variable to ssh-add like this:

printf '%s\n' "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
Enter fullscreen mode Exit fullscreen mode

That command does not prove every pipeline has preserved the secret correctly. Validate the key file the job actually creates before trying to connect, and keep both the private key and any encoded form out of job logs.

For some pipelines, storing a one-line base64 representation avoids multiline formatting problems. On GNU/Linux, create it locally with:

base64 -w0 ~/.ssh/deploy_key > deploy_key.b64
Enter fullscreen mode Exit fullscreen mode

Decode it in the job and validate the resulting file:

printf '%s' "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keygen -y -f ~/.ssh/deploy_key >/dev/null
Enter fullscreen mode Exit fullscreen mode

Base64 is an encoding, not encryption. Treat the encoded value as a private secret, restrict access, and never print it or the decoded key in logs.

Make sure the key format is supported

A file can look like a key but still be in a format your OpenSSH client can’t read. PuTTY’s .ppk is not OpenSSH private-key format; convert it with PuTTYgen before using it with OpenSSH. It’s also worth checking that the file is actually a private key and not a public key with a misleading filename. For help identifying common formats, see how to recognize SSH key formats.

An unsupported message doesn’t identify one universal problem. Verify the file’s contents and format, then test with the same OpenSSH client that the failing command uses. The OpenSSH private-key header explained can help clarify what a key’s header does—and does not—tell you.

When should you replace the key?

Usually, don’t start by generating a new key. A line-ending issue or a pipeline that dropped a newline may be fixable without changing the key pair. Replace the key if it is genuinely truncated or corrupted and you don’t have an intact copy. If you do replace it, install the new public key anywhere the old one was authorized.

The useful distinction is simple: error in libcrypto means the client couldn’t parse the supplied key data. Test the file with ssh-keygen -y -f first, then investigate its contents, line endings, format, and delivery path. Only troubleshoot server authentication after the key can be read locally.

I originally published a more detailed version of this guide on the SSHFlow blog.

I'm also building SSHFlow — an SSH client where every server gets its own workspace for terminals, SFTP, code, and databases.

Top comments (0)