cloudflare/gokey

Please support ed25519

bdrung opened this issue ยท 11 comments

Please support ed25519 for SSH host keys.

I've been looking into it for a while. One issue though - I would like gokey to generate "standard" private keys, so they are interoperable with other de-facto crypto libs/software (mostly openssl). However unfortunately, unlike RSA/ECDSA there is no standard private key format for ed25519 as of today. The closest thing is an RFC draft https://tools.ietf.org/id/draft-ietf-curdle-pkix-10.txt, which has been a draft for a while.

I suggest to implement a ed25519-openssh option until a standard private key format for ed25519 is defined.

I'm afraid it might create confusion: people might ask why there is ed25519-openssh but no rsa2048-openssh for example. Furthermore, because the way how gokey works - we integrate key type into the final salt when deriving keys, means when plain ed25519 will be available, generated keys will be different for ed25519 and ed25519-openssh.

On second though I might follow other implementation by implementing the current draft for ed25519 and specify explicitly that the output format might change in the future. But at least the contents of the key (the crypto material itself) will be same - so it will be a matter of converting formats rather...

@bdrung can you, please, check the PR above and let me know if you have any comments/concerns?

I took the patch from the merge prosposal and tried to build an updated Debian package, but it failed:

dpkg-buildpackage: info: source package gokey
dpkg-buildpackage: info: source version 0.0~git20170602.05f83bb-1+ed25519
dpkg-buildpackage: info: source distribution buster
 dpkg-source --before-build gokey-0.0~git20170602.05f83bb
dpkg-buildpackage: info: host architecture amd64
 fakeroot debian/rules clean
dh clean --buildsystem=golang --with=golang

   debian/rules override_dh_auto_clean
make[1]: Entering directory '/<<PKGBUILDDIR>>'
dh_auto_clean

rm -f gokey.1
make[1]: Leaving directory '/<<PKGBUILDDIR>>'
   dh_clean -O--buildsystem=golang
 debian/rules build
dh build --buildsystem=golang --with=golang

   dh_update_autotools_config -O--buildsystem=golang
   dh_autoreconf -O--buildsystem=golang
   dh_auto_configure -O--buildsystem=golang
   debian/rules override_dh_auto_build
make[1]: Entering directory '/<<PKGBUILDDIR>>'
dh_auto_build

	cd obj-x86_64-linux-gnu && go install -gcflags=\"-trimpath=/<<BUILDDIR>>/gokey-0.0\~git20170602.05f83bb/obj-x86_64-linux-gnu/src\" -asmflags=\"-trimpath=/<<BUILDDIR>>/gokey-0.0\~git20170602.05f83bb/obj-x86_64-linux-gnu/src\" -v -p 16 github.com/cloudflare/gokey github.com/cloudflare/gokey/cmd/gokey
golang.org/x/crypto/hkdf
golang.org/x/crypto/pbkdf2
golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/sys/unix

golang.org/x/crypto/ed25519
github.com/cloudflare/gokey
# github.com/cloudflare/gokey
src/github.com/cloudflare/gokey/gokey.go:104:39: key.(*ed25519.PrivateKey).Seed undefined (type *ed25519.PrivateKey has no field or method Seed)
golang.org/x/crypto/ssh/terminal
dh_auto_build: cd obj-x86_64-linux-gnu && go install -gcflags=\"-trimpath=/<<BUILDDIR>>/gokey-0.0\~git20170602.05f83bb/obj-x86_64-linux-gnu/src\" -asmflags=\"-trimpath=/<<BUILDDIR>>/gokey-0.0\~git20170602.05f83bb/obj-x86_64-linux-gnu/src\" -v -p 16 github.com/cloudflare/gokey github.com/cloudflare/gokey/cmd/gokey returned exit code 2
debian/rules:18: recipe for target 'override_dh_auto_build' failed
make[1]: *** [override_dh_auto_build] Error 2
make[1]: Leaving directory '/<<PKGBUILDDIR>>'
debian/rules:11: recipe for target 'build' failed
make: *** [build] Error 2
dpkg-buildpackage: error: debian/rules build subprocess returned exit status 2

So I figured it out, golang-go.crypto 1:0.0~git20180513.94e3fad-2 is too old, I need following commit:

commit 5ba7f63082460102a45837dbd1827e10f9479ac0
Author: David Benjamin <davidben@google.com>
Date:   Wed May 30 11:49:09 2018 -0400

    ed25519: actually be compatible with RFC 8032

My test failed on Debian 9 (stretch) with openssh-server 1:7.4p1-10+deb9u3:

$ gokey -p $password -s /etc/gokey_seed -skip 0 -o /etc/ssh/ssh_host_ed25519_key -r ssh-ed25519 -t ed25519
$ systemctl start ssh.service
$ journalctl -u ssh.service 
-- Logs begin at Thu 2018-06-14 17:54:01 UTC, end at Thu 2018-06-14 17:55:01 UTC. --
Jun 14 17:54:03 testhost systemd[1]: Starting OpenBSD Secure Shell server...
Jun 14 17:54:03 testhost sshd[1213]: Could not load host key: /etc/ssh/ssh_host_ed25519_key
Jun 14 17:54:03 testhost sshd[1217]: Could not load host key: /etc/ssh/ssh_host_ed25519_key
Jun 14 17:54:03 testhost sshd[1217]: Server listening on 0.0.0.0 port 22.
Jun 14 17:54:03 testhost sshd[1217]: Server listening on :: port 22.
Jun 14 17:54:03 testhost systemd[1]: Started OpenBSD Secure Shell server.
Jun 14 17:54:09 testhost sshd[1227]: error: Could not load host key: /etc/ssh/ssh_host_ed25519_key

I noticed that the key format differs. An example SSH key looks like:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCW+/nf1fOm/2QD4dRRsv2PPmEP3hAJyLuuibFhwbpRrQAAAJhE6RRsROkU
bAAAAAtzc2gtZWQyNTUxOQAAACCW+/nf1fOm/2QD4dRRsv2PPmEP3hAJyLuuibFhwbpRrQ
AAAEDRjsfysIVah4XR7o7IFkkl5/LVZjsjeq4I/aEsUVYMN5b7+d/V86b/ZAPh1FGy/Y8+
YQ/eEAnIu66JsWHBulGtAAAADnJvb3RAa29uc3RydWt0AQIDBAUGBw==
-----END OPENSSH PRIVATE KEY-----

Note: The other generated key files /etc/ssh/ssh_host_ecdsa_key and /etc/ssh/ssh_host_rsa_key work as expected.

OpenSSH supports different key formats. Most popular ones are pkix ones and their OpenSSH ones proper. I've looked at the source code and there is code to parse rsa and ecdsa keys from pkix format, but not for ed25519, so OpenSSH only understands ed25519 keys in the SSH format.

I did not find any readily available tools to convert from one format to another. Even golang crypto package cannot "generate" keys in SSH format, only parse them.

I'll probably write a simple converter for the time being and see if I can submit a patch to OpenSSH to handle pkix ed25519 keys.

Here is (a bit dirty for now) python script to convert gokey (and OpenSSL) format ed25519 private keys to OpenSSH format

https://gist.github.com/secumod/886858a2257352253880541dcb496710

Usage

$ gokey -t ed25519 -r test -p test -u | ./ed25519tossh.py

The Python snippet is sufficient for me (for now). Let me try it out.

After adjusting the snippet to work with Python 3, the generated OpenSSL format works.