Skip to content

Key formats — PEM, OpenSSH, and PPK

If you've ever had a key "just not work" with one tool but work fine with another, you've hit a format mismatch. Cleat's current SSH stack (libssh2 + mbedTLS) is strict about what it accepts.

TL;DR

Format First line of file Works in Cleat?
PEM (PKCS#1) -----BEGIN RSA PRIVATE KEY----- ✅ Yes
PEM (PKCS#8) -----BEGIN PRIVATE KEY----- ✅ Yes
OpenSSH -----BEGIN OPENSSH PRIVATE KEY----- ❌ No — convert first
PuTTY (.ppk) PuTTY-User-Key-File-... ❌ No — convert first
Ed25519 (any format) varies ⚠️ Limited — RSA PEM is the safe default for now

Why this matters

ssh-keygen on modern OpenSSH (8.x+) defaults to OpenSSH format — even when you ask for RSA. So a key generated with:

bash ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa

…on a 2020+ system is not the same format as the same command on an older system. The file format changed; the underlying cryptography did not.

Converting OpenSSH → PEM

In place, rewriting the file:

bash ssh-keygen -p -m PEM -f ~/.ssh/id_rsa

You'll be prompted for the current passphrase (if any) and a new one. The public key (id_rsa.pub) is unchanged — only the private key encoding is rewritten. No need to re-deploy it to your servers.

Converting PuTTY → PEM

```bash puttygen mykey.ppk -O private-openssh -o mykey.pem

Then convert that to PEM:

ssh-keygen -p -m PEM -f mykey.pem ```

On macOS, install PuTTY tools with brew install putty.

Generating a fresh PEM key

If you just want a working key without dealing with conversions:

bash ssh-keygen -t rsa -b 4096 -m PEM -f ~/.ssh/cleat_id_rsa ssh-copy-id -i ~/.ssh/cleat_id_rsa.pub user@host

Then point Cleat at ~/.ssh/cleat_id_rsa when creating the connection.

Why not just support OpenSSH format?

The constraint is in mbedTLS, which is Cleat's crypto backend. A future release may add native OpenSSH key parsing or swap the backend to OpenSSL — see the project's issue tracker for status. For now, PEM is the path of least resistance.