🔑

OpenSSHでPEM形式のed25519鍵を使う

2024/06/06に公開

二つの秘密鍵形式

OpenSSHの秘密鍵には二種類の形式があります。

  • OpenSSL PEM形式[1] (旧形式)
  • OpenSSH独自形式 (新形式)

しかしed25519鍵については歴史的経緯[2]により常にOpenSSH形式が使われ、PEM形式は使えませんでした。

この為OpenSSLでPEM形式のed25519鍵を生成してもOpenSSHでは長い間使えなかったのですが、2023-12-19に出たOpenSSH 9.6ではRelease Notes

 * ssh(1), sshd(8), ssh-add(1), ssh-keygen(1): add support for
   reading ED25519 private keys in PEM PKCS8 format. Previously
   only the OpenSSH private key format was supported.

と有るようにPEM形式のed25519秘密鍵の読み込みに対応しました。

今回はこのPEM形式ed25519秘密鍵の読み込みを試してみます。

テスト環境

今回のテストは以下の環境で行いました。

OS: FreeBSD 13.2-RELEASE
OpenSSL: OS付属(1.1.1t)

OS付属のOpenSSHが 9.3 だった為、PEM形式のed25519鍵が扱えません。
なので、2024-06-06時点で最新のOpenSSH 9.7p1をビルドして試します。
今回はJAISTのミラーサーバーからopenssh-9.7p1.tar.gzを入手しました。

sue@hiyo% fetch http://ftp.jaist.ac.jp/pub/OpenBSD/OpenSSH/portable/openssh-9.7p1.tar.gz
openssh-9.7p1.tar.gz                                  1805 kB 3119 kBps    01s
sue@hiyo% ls -l openssh-9.7p1.tar.gz
-rw-r--r--  1 sue  yac  1848766 Mar 11 19:19 openssh-9.7p1.tar.gz

入手した openssh-9.7p1.tar.gz を展開して、ビルドします。

sue@hiyo% tar xf openssh-9.7p1.tar.gz
sue@hiyo% cd openssh-9.7p1
sue@hiyo% ./configure && make
checking for cc... cc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
  ~略~
sue@hiyo% ./ssh -V
OpenSSH_9.7p1, OpenSSL 1.1.1t-freebsd  7 Feb 2023

無事?にビルド出来ました。

PEM形式のed25519秘密鍵の生成

opensslコマンドで、ed25519秘密鍵を生成します。

sue@hiyo% openssl genpkey -algorithm ed25519 -aes256 -out ed25519.pem
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
sue@hiyo% ls -l ed25519.pem
-rw-------  1 sue  yac  290 Jun  6 05:28 ed25519.pem

生成された秘密鍵の内容を確認します。

sue@hiyo% cat ed25519.pem
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAiX4qpoSTUwnwICCAAw
DAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEED8l6dB/KGe/dujI2/26E6QEQCxB
K1RfjhHkoKQKBxZDJJQx9onZV20wim2l/hQvGVfDZhFtnNPC53bXDZ28x5+FrRjZ
tr04tYiOz3P/znQG0ZQ=
-----END ENCRYPTED PRIVATE KEY-----

1行目が -----BEGIN ENCRYPTED PRIVATE KEY----- となっており、OpenSSH形式の秘密鍵では無い事が確認出来ました。

この秘密鍵を使ってSSHログインする為には対応する公開鍵が必要になります。
そこでssh-keygenコマンドを使って秘密鍵から公開鍵を取り出してみましょう。

sue@hiyo% ./ssh-keygen -y -f ed25519.pem
Enter passphrase:
Load key "ed25519.pem": invalid format

……なぜかエラーが出てうまくいきません。
念の為、sshコマンドで秘密鍵が読めるか試してみますが、やはりエラーになります。

sue@hiyo% ./ssh -i ed25519.pem localhost
Enter passphrase for key 'ed25519.pem':
Load key "ed25519.pem": invalid format
(sue@localhost) Password for sue@hiyo.iwmt.org:

エラーの原因と対処

エラーの原因を調べます。まず、configureの出力で気になる部分が無いかを確認してみます。

sue@hiyo% ./configure && make
checking for cc... cc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
  ~略~
checking for EVP_PKEY_get_raw_private_key... yes
checking whether OpenSSL has ED25519 support... no
checking whether to enable PKCS11... yes
  ~略~

なぜかOpenSSLがed25519に対応していないと判定されています。
詳細を調べる為、config.logを確認します。

config.log
  ~略~
configure:19224: checking whether OpenSSL has ED25519 support
configure:19245: cc -o conftest -g -O2 -pipe -Wunknown-warning-option -Qunused-arguments -Wall -Wextra -Wpointer-arith -Wuninitialized -Wsign-compare -Wformat-security -Wsizeof-pointer-memaccess -Wno-pointer-sign -Wno-unused-parameter -Wno-unused-result -Wmisleading-indentation -Wbitwise-instead-of-logical -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -ftrapv -mretpoline -fno-builtin-memset -fstack-protector-strong   -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,retpolineplt -fstack-protector-strong conftest.c -lcrypto -lutil  >&5
conftest.c:293:23: error: too few arguments to function call, expected 4, have 3
                    buf, sizeof(buf)) == NULL);
                                    ^
/usr/include/openssl/evp.h:1362:11: note: 'EVP_PKEY_new_raw_private_key' declared here
EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *e,
          ^
1 error generated.
  ~略~

OpenSSLのed25519サポート判定の部分で、関数の引数の数が違う為コンパイルに失敗し、ed25519に対応していないと判定されているようです。

どうやらconfigureスクリプトにバグが有り、OpenSSH 9.7p1のリリース後に修正されたようです。

https://github.com/openssh/openssh-portable/commit/8d0e46c1ddb5b7f0992591b0dc5d8aaa77cc9dba

configureを使うのはポータブル版OpenSSHのみなので、未確認ですがOpenBSDでは問題無く使えると思われます。

GitHubのHEADでは修正済みですが、今回はこの修正をOpenSSH 9.7p1のソースに適用する事によって対応してみます。

configure.acviで開き、3187行目のEVP_PKEY_new_raw_private_keyの引数にNULLを追加します。

configure.ac(修正前)
                memset(buf, 0, sizeof(buf));
                exit(EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519,
                    buf, sizeof(buf)) == NULL);
                ]])],
configure.ac(修正後)
                memset(buf, 0, sizeof(buf));
                exit(EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
                    buf, sizeof(buf)) == NULL);
                ]])],

autoreconfconfigure.acからconfigureを生成し直して、再度ビルドします。

sue@hiyo% autoreconf
sue@hiyo% ./configure && make
checking for cc... cc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
  ~略~
checking for EVP_PKEY_get_raw_private_key... yes
checking whether OpenSSL has ED25519 support... yes
checking whether to enable PKCS11... yes
  ~略~

OpenSSLがed25519に対応していると、正しく判定されるようになりました。

PEM形式のed25519鍵によるログインテスト

今度こそPEM形式のed25519鍵が扱えるようになったので、実際にログインしてみます。
まずはPEM形式のed25519秘密鍵から、OpenSSH形式の公開鍵を生成します。
秘密鍵の形式は自動判別される為、ssh-keygenコマンドのオプションはOpenSSH形式の秘密鍵を扱う時と同じです。

sue@hiyo% ./ssh-keygen -y -f ed25519.pem | tee ed25519.pem.pub
Enter passphrase:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE3HgnDc+VfLP25llaY6PHEfIGW5k414MN3SD+fm6MHp
sue@hiyo% ls -l ed25519.pem.pub
-rw-r--r--  1 sue  yac  81 Jun  6 06:32 ed25519.pem.pub

PEM形式のed25519秘密鍵が読めて、OpenSSH形式の公開鍵が作成されました。

公開鍵をログイン先のサーバーの~/.ssh/authorized_keysに追加します。
今回はテストで自分自身に追加してみます。

sue@hiyo% cat ed25519.pem.pub >> ~/.ssh/authorized_keys

公開鍵を登録したので、実際にPEM形式のed25519秘密鍵を使ってログインしてみます。
sshコマンドで利用する時も秘密鍵の形式は自動判別されるので、OpenSSH形式の時とオプションは同じになります。

sue@hiyo% ./ssh -i ed25519.pem -o IdentitiesOnly=yes localhost
Enter passphrase for key 'ed25519.pem':
Last login: Thu Jun  6 05:22:32 2024 from localhost
FreeBSD 13.2-RELEASE-p4 GENERIC

Welcome to FreeBSD!

Release Notes, Errata: https://www.FreeBSD.org/releases/
Security Advisories:   https://www.FreeBSD.org/security/
FreeBSD Handbook:      https://www.FreeBSD.org/handbook/
FreeBSD FAQ:           https://www.FreeBSD.org/faq/
Questions List:        https://www.FreeBSD.org/lists/questions/
FreeBSD Forums:        https://forums.FreeBSD.org/

Documents installed with the system are in the /usr/local/share/doc/freebsd/
directory, or can be installed later with:  pkg install en-freebsd-doc
For other languages, replace "en" with a language code like de or fr.

Show the version of FreeBSD installed:  freebsd-version ; uname -a
Please include that output and any error messages when posting questions.
Introduction to manual pages:  man man
FreeBSD directory layout:      man hier

To change this login announcement, see motd(5).
sue@hiyo% 

無事ログイン出来ました。

注意点

OpenSSH 9.6で対応したのは、PEM形式ed25519秘密鍵の読み込みのみです。

PEM形式での書き出しには対応していません。
ssh-keygenでed25519鍵を生成する時に-m pem-m pkcs8を指定してもOpenSSH形式の秘密鍵が生成されます。
またssh-keygen -pでパスフレーズを付け直す時に-m pem-m pkcs8を指定してもOpenSSH形式の秘密鍵に変換されてしまいます。

PEM形式の公開鍵の読み込みには対応していません。
ssh-keygen -iで読み込もうとしてもエラーになります。

sue@hiyo% openssl pkey -in ed25519.pem -pubout -out ed25519.pem.pub
Enter pass phrase for ed25519.pem:
sue@hiyo% cat ed25519.pem.pub
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEATceCcNz5V8s/bmWVpjo8cR8gZbmTjXgw3dIP5+bowek=
-----END PUBLIC KEY-----
sue@hiyo% ./ssh-keygen -i -f ed25519.pem.pub -m pkcs8
do_convert_from_pkcs8: unsupported pubkey type 1087

まとめ

  • OpenSSH 9.6よりPEM形式のed25519秘密鍵が使えるようになりました。
  • 利用する時には鍵の形式は自動判別される為、オプションは特に指定する必要は有りません。
  • ポータブル版OpenSSH 9.6p1, 9.7p1ではconfigureスクリプトにバグが有って使えません。このバグは9.8p1以降では修正されています。
脚注
  1. 実際にはさらに細かく分けられるのですが、ここでは大雑把にOpenSSLや古いOpenSSHが出力する形式と考えてください。 ↩︎

  2. OpenSSHが最初にed25519鍵に対応した頃はOpenSSLはed25519に対応しておらず、PEM形式でのed25519鍵のフォーマットが決まっていませんでした。 ↩︎

Discussion