4

I'm having a problem where when I export a key from 1password, and use it with ssh -i, I get

Load key "/home/user/.ssh/private_ed25519": invalid format

Doing a google search on this, it seems to be a problem where 1password stores their ED25519 key in PKCS#8, from their developer

Copying a private key will copy it in PKCS#8--the format 1Password stores the key. Unfortunately, OpenSSH does not support ED25519 keys in PKCS#8, only in OpenSSH format. Downloading a key will convert it to OpenSSH format. The reason RSA keys work is because OpenSSH does support RSA keys in PKCS#8.

They suggest using a "Download" feature, but I don't have that feature and many other people also don't have that feature. But there should be more than one way to skin this cat,

You can create an ed25519 keyfile in PKCS#8 with,

openssl genpkey -algorithm ed25519 -out private.pem

Is there any method to convert a private Ed25519 key (private.pem in the above) from PKCS#8 to the OpenSSH format?

When I try, with ssh-keygen, I get

$ ssh-keygen -i -f private.pem -m pkcs8
do_convert_from_pkcs8: private.pem is not a recognised public key format
Evan Carroll
  • 2,547
  • 4
  • 23
  • 35
  • Ed25519 keys OpenSSH generic format, see RFC8032. – Nadeem Taj Jan 20 '23 at 17:44
  • @NadeemTaj What does that have to do with this question? RFC8032 doesn't mention OpenSSH at all https://www.rfc-editor.org/rfc/rfc8032 – Evan Carroll Jan 20 '23 at 17:50
  • Base64 is used in many formats under many standards but this format, with the dashes-BEGIN,END-type lines was originated by PEM and does require lines broken/wrapped (not truncated) every 64 characters; see – Nadeem Taj Jan 20 '23 at 17:52
  • What does that have to do with anything. The header BEGIN/END indicates the format of the data which is base64 encoded. It can be OpenSSH format, or PKCS#8. The problem in this question is there is key in PKCS#8, and I need it to be in OpenSSH. – Evan Carroll Jan 20 '23 at 17:56
  • This document describes the private key format for OpenSSH. – Nadeem Taj Jan 20 '23 at 17:59
  • 1) https://security.stackexchange.com/questions/32768/converting-keys-between-openssl-and-openssh. 2) https://unix.stackexchange.com/questions/26924/how-do-i-convert-a-ssh-keygen-public-key-into-a-format-that-openssl-pem-read-bio – Nadeem Taj Jan 20 '23 at 18:24
  • @NadeemTaj again, unrelated. (1) doesn't cover ed25519. (2) both doesn't cover ed25519, and goes the other direction from OpenSSH -> OpenSSL. – Evan Carroll Jan 21 '23 at 04:55
  • the way you explained and ask just like a great piece of '$a'. No interest in following your communication and actions. But you should. – Nadeem Taj Jan 21 '23 at 05:34

3 Answers3

6

Let's walk through it. First, we generate a private key in Ed25519:

$ openssl genpkey -algorithm ED25519 -out ed25519.pem
$ cat ed25519.pem
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEID+U9VakauO4Fsv4b/znpDHcdYg74U68siZjnWLPn7Q1
-----END PRIVATE KEY-----

We read the man page on ssh-keygen -i:

 -i    This option will read an unencrypted private (or public)
       key file in the format specified by the -m option and print
       an OpenSSH compatible private (or public) key to stdout.

and think, "oh, so we just do this":

$ ssh-keygen -i -f ed25519.pem -m pkcs8
do_convert_from_pkcs8: ed25519.pem is not a recognised public key format

Nope, maybe the documentation lies and the error is instructive.

So, we grab the public key corresponding to that private key:

$ openssl pkey -in ed25519.pem -pubout > ed25519.pub
$ cat ed25519.pub
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA0IgiJOLeGDwumzkm+wi82nP7wvmbnaoWKmNNHMaq/Mw=
-----END PUBLIC KEY-----

and try again, this time giving the public key:

$ ssh-keygen -i -f ed25519.pub -m pkcs8
do_convert_from_pkcs8: unsupported pubkey type 1087

Dang it. Why?!

Well, it's a bug:

OpenSSH doesn't currently support reading or writing Ed25519 keys in any format other than the OpenSSH native key format.

Not all libcrypto implementations support Ed25519 keys, in particular LibreSSL does not.

This patch adds support for reading PKCS8 Ed25519 keys on recent OpenSSL, but it can't be upstreamed until LibreSSL supports these keys too.

So, full stop, Ed25519 support is incomplete in the openssl available upstream (which is what we're familiar with in Linux, for example).

We have two possible choices:

  1. Compile a patched version of Portable OpenSSH and convert using the command above; or,
  2. Use the alternative tool mentioned by the bug reporter, sshpk, to convert.

Let's try the latter, since it's just a NPM package:

$ npm install -g sshpk
$ sshpk-conv ed25519.pem -t ssh -p
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDQiCIk4t4YPC6bOSb7CLzac/vC+ZudqhYqY00cxqr8zAAAAJAyR1o6Mkda
OgAAAAtzc2gtZWQyNTUxOQAAACDQiCIk4t4YPC6bOSb7CLzac/vC+ZudqhYqY00cxqr8zA
AAAEA/lPVWpGrjuBbL+G/856Qx3HWIO+FOvLImY51iz5+0NdCIIiTi3hg8Lps5JvsIvNpz
+8L5m52qFipjTRzGqvzMAAAAC2VkMjU1MTkucGVtAQI=
-----END OPENSSH PRIVATE KEY-----

and there we go: the private key in OpenSSH format.

bishop
  • 833
  • 6
  • 10
  • 1
    Wow, I would have bountied this more for this quality of answer. Thanks a ton all around. The only follow-up question I have is wtf does a patch to openssl require landing in libressl too? If they're different projects, why does one require support in the other? – Evan Carroll Jan 17 '23 at 15:55
  • 1
    May also be worth pointing out that it looks like LibreSSL got ed25519 on December 12, when 3.7 landed https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.7.0-relnotes.txt – Evan Carroll Jan 17 '23 at 16:21
0

Not my (original) work, copied from another thread when I was trying to find out something related (bugs fixed / added by me)

-- a shell script that converts openssl-generated ed25519 private key to a format understood by openssh

tested the following way:

$ openssl genpkey -algorithm ED25519 -out ed25519.pem
$ ./eddsa-ssl-to-ossh.sh ed25519.pem > okey
$ ssh-keygen -l -f okey
#!/bin/sh

set -euf

ssl_priv=$(cat ${1:+"$1"})

pub64=$(echo "$ssl_priv" | openssl pkey -pubout -outform der 2>/dev/null | dd bs=12 skip=1 status=none | base64)

test "$pub64" || { echo "Cannot get public key" >&2; exit 1; }

priv64=$(echo "$ssl_priv" | grep -v '^-' | base64 -d | dd bs=16 skip=1 status=none | base64)

echo '-----BEGIN OPENSSH PRIVATE KEY-----'

{
    printf openssh-key-v1'\000\000\000\000\004'none'\000\000\000\004'none'\000\000\000\000\000\000\000\001\000\000\000'3
    printf '\000\000\000\013'ssh-ed25519'\000\000\000 '
    echo $pub64 | base64 -d
    printf '\000\000\000'
    printf '\210\000\000\000\000\000\000\000\000'
    printf '\000\000\000\013'ssh-ed25519'\000\000\000 '
    echo $pub64 | base64 -d
    printf '\000\000\000@'
    echo $priv64| base64 -d
    echo $pub64 | base64 -d
    printf '\000\000\000\000\001\002\003\004\005'
} | base64

echo '-----END OPENSSH PRIVATE KEY-----'
Tomi
  • 1
  • 1
-1

Yes, there is a method to convert a private Ed25519 key from PKCS#8 to the OpenSSH format. You can use the ssh-keygen command-line tool that comes with OpenSSH to convert the key. The basic syntax of the command is as follows:

ssh-keygen -i -f keyfile.pem -m pkcs8

Where keyfile.pem is the file name of your PKCS#8 private key. The -i flag tells ssh-keygen to import a key, the -f flag specifies the input file and the -m flag specifies the key format as pkcs8.

When you run this command, ssh-keygen will convert the key and output it to the terminal. You can then redirect the output to a file to save it in the OpenSSH format:

ssh-keygen -i -f keyfile.pem -m pkcs8 > openssh-keyfile.pem

If you're trying to convert the key to be used in ssh-agent or ssh-add, you'll have to remove the passphrase from the key first, otherwise it will still prompt you for it when adding the key to the agent

The below command will prompt you to enter a new passphrase:

ssh-keygen -i -f keyfile.pem -m pkcs8 | ssh-keygen -p -m pem
schroeder
  • 125,553
  • 55
  • 289
  • 326
userlukman
  • 19
  • 2
  • 1
    This doesn't work on ed25519 keys. Try it `openssl genpkey -algorithm ed25519 -out keyfile.pem; ssh-keygen -i -f keyfile2.pem -m pkcs8` – Evan Carroll Jan 16 '23 at 17:37