仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

YubiKey 5をSSHの秘密鍵にする

YubiKey 5はPIV (Personal Identity Verification) という規格に対応しています。PIVとは米国政府機関が発行するスマートカードのことで、YubiKeyではこれを操作することができます。

YubiKey 5のPIVは、RSA 1024 / RSA 2048 / ECC P-256 / ECC P-384に対応しています。今回はYubiKey内にECC P-384の鍵を生成し、保存した鍵を利用してSSHログインできるようにしてみようと思います。

検証環境

  • YubiKey 5C NFC Ver.5.2.7
  • macOS Big Sur Ver.11.5.2

ツールのインストール

YubiKeyのコマンドラインツールykmanと、スマートカードを扱うためのライブラリ、ユーティリティを提供しているOpenSCをインストールします。

$ brew install ykman opensc

検証時のMacではYubiKeyに保存したECC鍵を読み込むことができませんでした。

$ ssh-keygen -D /usr/local/lib/opensc-pkcs11.so -e                 
skipping unsupported key type
failed to fetch key
unknown certificate key type
failed to fetch key
Enter PIN for 'SSH key': 
skipping unsupported key type
failed to fetch key
unknown certificate key type
failed to fetch key
cannot read public key from pkcs11

これはデフォルトでインストールされているOpenSSHがLibreSSL 2.7.3でビルドされているのが原因でした。 HomebrewにあるOpenSSHはOpenSSL 1.1以上でビルドされているようなので、こちらをインストールすることで回避できます。

$ brew install openssh

Homebrewでインストールしたsshコマンドを実行できるように/usr/local/binをPATHの先頭に追加します。

$ export PATH=“/usr/local/bin:$PATH”

私の環境では以下の通りでした。

$ which ssh
/usr/local/bin/ssh
$ ssh -V
OpenSSH_8.7p1, OpenSSL 1.1.1l  24 Aug 2021

鍵を生成

  • 鍵ペアを生成

YubiKeyのPIVには証明書を保存するために4つのスロットがあります。 それぞれの用途は公式ドキュメントを確認してください。

今回はスロット 9a (PIV Authentication) を使用していきます。公開鍵はpubkey.pemというファイル名で出力します。

$ ykman piv keys generate -a ECCP384 9a pubkey.pem
Enter a management key [blank to use default key]:

Management Keyを入力して鍵ペアの生成は完了です。

  • 自己署名証明証を生成

pubkey.pemを持つ自己署名証明書をスロット 9aで生成します。

$ ykman piv certificates generate -s 'SSH key' 9a pubkey.pem
Enter a management key [blank to use default key]: 
Enter PIN: 

Management KeyとPINコードを入力して自己署名証明書の生成は完了です。

  • 確認
$ ykman piv info
PIV version: 5.2.7
PIN tries remaining: 3
Management key algorithm: TDES
CHUID:  3019d4e739da739ced39ce739d836858210842108421c84210c3eb3410d04f85e66ea295b74b4c523c7ec9a8bf350832303330303130313e00fe00
CCC:    No data available.
Slot 9a:
    Algorithm:  ECCP384
    Subject DN: CN=SSH key
    Issuer DN:  CN=SSH key
    Serial:     38854637746760389760709390196415882874710771519
    Fingerprint:    4e7bf6cf4491a692c5f82ca56046b91f23e5210020402fa4dc5e7b0e13b3dca7
    Not before: 2021-08-26 06:12:10
    Not after:  2022-08-26 06:12:10

実際に保存されているPEM形式の公開鍵を取得してみます。

$ ykman piv certificates export -F PEM 9a cert.pem
$ openssl x509 -in cert.pem -pubkey -noout                                                                                               
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyxDRpSughb7+Q0Yf6LOZpC3zBzl22Q5R
DS41qCdA33fx5+VGkofRlUO078vd7G1vTEpF8/uiZ2IdCJxkrpVmrDE6iwMxwah1
0x4VczU0Bap3NIe1YrxbU92Tn/pnC72N
-----END PUBLIC KEY-----

PEM形式の公開鍵が出力されていれば成功です。

SSHの設定

今回はローカルホストに対してSSHを試してみます。 ~/.sshディレクトリがなければinstall -m700 -d ~/.sshで作成しておいてください。

  • 公開鍵を登録

ssh-keygen -DするとSSHの公開鍵のフォーマットで出力されます。 これをローカルのauthorized_keysに保存し、公開鍵認証でログインできるようにします。

ssh-keygen -D /usr/local/lib/opensc-pkcs11.so >> ~/.ssh/authorized_keys

リモートに登録する場合は

ssh-keygen -D /usr/local/bin/opensc-pkcs11.so > /tmp/key.pub
ssh-copy-id -i /tmp/key.pub

で登録するといいかと思います。

  • SSHしてみる
ssh -I /usr/local/lib/opensc-pkcs11.so localhost
Enter PIN for 'SSH key':

Enter PIN for 'SSH key':でYubiKeyに登録されているPINを入力するとログインできます。

  • ~/.ssh/configに設定

~/.ssh/configにPKCS11Providerを設定するとssh -Iする必要がなくなります。

Host *
    PKCS11Provider /usr/local/lib/opensc-pkcs11.so

まとめ

SSHの鍵をYubiKeyに入れておけば、マシーンに依存せず同じ鍵でSSHできるようになります。YubiKeyから秘密鍵を取り出すことができないので、YubiKeyさえ紛失しなければ流出の心配はないと思います。

しかし、今回YubiKeyで直接鍵を生成したのでYubiKeyの故障の際は鍵の登録し直しが必要になります。鍵がなくなると困るような場合は、ssh-keygenで生成した鍵をYubiKeyにインポートすることも可能ですので、こちらの機能を試してみるといいかもしれません。