YubiKeyを使ったSSH公開鍵認証(PIV)

はじめに

前回の投稿「YubiKeyを使ったSSH公開鍵認証(FIDO)」の冒頭で触れた、YubiKey のPKCS #11 準拠のPIV(Smart Card)を使ったSSH公開鍵認証を試してみたので、その手順などを解説します。

PIV を使ったSSHの公開鍵認証

  • PIV とは、FIPS 201 で規格化された個人識別情報を検証するための要件で、米国の政府職員が持つ身分証明用のICカードで使われている標準規格
  • YubiKey にはPIV の機能があり、YubiKey 5 シリーズの場合は公開鍵暗号の秘密鍵とX.509 証明書を格納するスロットが4つある
  • OpenSSH クライアントからYubiKey のPIV にアクセスするために、ミドルウェアとしてOSS のOpenSC をインストールして使う

YubiKeyPIV に格納した公開鍵暗号の秘密鍵を使って、SSHサーバにSSH公開鍵認証で接続します。
YubiKey のPIV は、秘密鍵が外部に漏洩しないようにする対策が施されているので、SSH サーバに登録した公開鍵に対応する秘密鍵が格納されたYubiKey を接続したパソコンからしか、SSH サーバに接続できないようにすることができます。
PIV にはPIN を登録することができ、連続して入力失敗するとロックされるので、万が一YubiKey が第三者に窃取されたとしても、不正ログインは防げる仕組みになっています。

環境

クライアント側の環境

  • MacBook Pro 2022(macOS Monterey 12.4)
  • OpenSSH client (8.6p1) ※macOSにバンドルインストール版 (*1)
  • OpenSC (0.22.0) ※当手順にインストール手順を記載
  • YubiKey Manager
    • GUIツール (1.2.4)
    • CLIツール (4.0.7)
  • YubiKey 5 NFC(Firmware 5.4.3)

(*1) 前回の解説でOpenSSHクライアント をmacOS バンドルインストール版からHomebrew からインストール版に切り替えていたので、元のmacOS バンドルインストール版に戻した

サーバ側の環境

  • Ubuntu 20.04.4 LTS
  • OpenSSH server 8.2p1

クライアント側の環境設定

1. OpenSC のインストール

Homebrew でOpenSC をインストールします。

brew install opensc

OpenSC のインストール先を確認して、OpenSSH のコマンドを実行する際に指定するPKCS #11 のライブラリのパスを確認します。

% brew --prefix opensc
/opt/homebrew/opt/opensc

% ls -l /opt/homebrew/opt/opensc/lib/opensc-pkcs11.so
-rw-r--r--  1 Capybara admin  247120  6  6 21:15 /opt/homebrew/opt/opensc/lib/opensc-pkcs11.so

YubiKey の初期設定

1. YubiKey のPIV のPIN管理

PIV のPIN管理機能では、PINPUKManagement Key の3つを登録できるようになっています。
いずれもデフォルト値が登録されていて変更しないでもPIV の機能を使うことができますが、セキュリティの観点で変更が推奨とされています。

  • PIN
    • 証明書の生成、SSH接続の際に使う
    • PIN の入力を3回連続失敗するとロックされる(回数は変更可能)
    • デフォルト:123456
  • PUK
    • PIN がロックされた際のロック解除で使う
    • PUK の入力を3回連続失敗するとロックされる
    • デフォルト:12345678
  • Management Key
    • 共通鍵暗号の鍵。鍵の種類は3DES、AES(128,192,256)から選択可能
    • デフォルト:010203040506070801020304050607080102030405060708

YubiKey Manager のCLIツール でPIV の状態を確認するコマンドを実行すると、PIN とManagement Key がデフォルトの状態なので”WARNING” と表示されていました。

% ykman piv info
PIV version: 5.4.3
WARNING: Using default PIN!
PIN tries remaining: 3/3
WARNING: Using default Management key!
Management key algorithm: TDES
CHUID:	No data available.
CCC: 	No data available.

YubiKey Manager にはGUIツールとCLIツールの2つあり、どちらを使ってもこの3つを変更できますが、ここではGUIツール を使って変更します。

GUIツールを起動してYubiKey をパソコンに挿入し、メニューの[Applications] > [PIV] > [Configure PINs] をクリックします。

YubiKey Manager(GUI) PIV PIN(未登録)

この画面からPINPUKManagement Key それぞれの変更画面に移り変更します。

YubiKey Manager(GUI) PIV PIN(登録)

PIN を変更します。
Current PIN は”Use default” のチェックをON にし、登録するPIN をNew PINConfirm new PIN の2ヶ所に入力して[Change PIN] をクリックします。
※ PIN は6〜8文字以上のASCII文字

YubiKey Manager(GUI) PIV PUK(登録)

PUK を変更します。
Current PUK は”Use default” のチェックをON にし、登録するPUK をNew PUKConfirm new PUK の2ヶ所に入力して[Change PUK] をクリックします。
※ PUK は6〜8文字以上の英数字

YubiKey Manager(GUI) PIV Management Key(登録)

Management Key を変更します。

  • Current Management Key は”Use default” のチェックをON にします
  • New Management Key は[Generate] をクリックして自動生成します
    • Algorithm を変える場合はドロップダウンで選択してから[Generate] をクリックします(今回はAES256 を選択しました)
    • 自動生成ではなく任意の値を手入力することもできます
  • Protect with PIN のチェックをON にすると、Management Key がPIN で保護され、CLI ツールで鍵ペアや証明書を生成する際にManagement Key ではなくPIN の入力が求められるようになります

※ Management Key は16進数(数字とa〜fの英字)、文字数は固定でAlgorithm の種類により異なる

3つとも変更したので、再度CLI ツールのコマンドを実行してみます。

% ykman piv info
PIV version: 5.4.3
PIN tries remaining: 3/3
Management key algorithm: AES256
Management key is stored on the YubiKey, protected by PIN.
CHUID:	No data available.
CCC: 	No data available.

変更前に表示されていた”WARNING” が表示されなくなりした。

GUI ツールを使ったPIN、PUK、Management Key の登録の解説はここまでです。参考としてCLI ツールのコマンドを載せておきます。

# PIN の変更
ykman piv access change-pin

# PUK の変更
ykman piv access change-puk

# Management Key の変更
ykman piv access change-management-key -a AES256 --protect

鍵の生成〜自己署名証明書の生成

1. 鍵の生成

YubiKey Manager のCLI ツールを使って鍵を生成します。

% ykman piv keys generate -a RSA2048 --touch-policy ALWAYS 9a pubkey.pem
Enter PIN:
 → ここで登録したPIVのPIN を入力

% ls -l
-rw-r--r--  1 Capybara staff   451  6 12 15:15 pubkey.pem

実行したコマンドの解説です。

  • -a RSA2048
    • 生成する鍵の公開鍵暗号の方式
    • RSA2048 以外に、RSA1024, ECCP256, ECCP384 を指定できる
  • –touch-policy ALWAYS
    • スロットにアクセスする際にYubiKey のタッチを常に求める
    • ALWAYS 以外に、DEFAULT, NEVER, CACHED を指定できる
  • 9a
    • 生成した鍵を格納するスロット
    • PIV のスロットは4つあるので、いずれかを指定します
      • Authentication (9a)
      • Digital Signature (9c)
      • Key Management (9d)
      • Card Authentication (9e)
    • 今回はSSH公開鍵認証で使うので9a を指定しましたが、他のスロットでもよいみたいです
  • pubkey.pem
    • カレントフォルダに生成する公開鍵のファイル名

このコマンドで秘密鍵がYubiKey の指定したスロットに、PEM形式の公開鍵ファイルがカレントフォルダに作成されます。

2. YubiKey 内に作成した秘密鍵の確認

YubiKey 内に作成した秘密鍵を確認する方法を調べてみました。

  • CLIツールのykman piv info
    • 表示されない
  • GUIツールの[Applications] > [PIV] > [Configure Certificates]
    • 表示されない
  • CLIツールのykman piv keys export 9a pubkey.pem
    • YubiKey 内の秘密鍵から生成した公開鍵ファイルがカレントフォルダに作成された

どうやら、3つ目のYubiKey 内の秘密鍵から公開鍵をエクスポートする方法しか、確認する方法はないようです。
ちなみに、エクスポートで作成される公開鍵ファイルは、1. 鍵の生成 でカレントフォルダに作成された公開鍵ファイル(PEM形式)と中身が同じでした。

3. 自己署名証明書の生成

YubiKey Manager のCLI ツールを使って自己署名証明書(X.509)を生成します。

% ykman piv certificates generate -d730 -s "Capybara" 9a pubkey.pem
Enter PIN:
 → ここで登録したPIVのPIN を入力
Touch your YubiKey...
 → YubiKey が点滅したらYubiKey をタッチ

実行したコマンドの解説です。

  • -d730
    • 有効期限までの日数(730日)
  • -s “Capybara”
    • Subject の名前
  • 9a
    • 暗号鍵が格納されているスロット。生成した証明書が格納される
  • pubkey.pem
    • 公開鍵のファイル名

このコマンドでYubiKey の指定したスロットに自己署名証明書が作成されます。

4. YubiKey 内に作成した証明書の確認

ykman piv info で証明書の情報が表示されました。

% ykman piv info
PIV version: 5.4.3
PIN tries remaining: 3/3
Management key algorithm: AES256
Management key is stored on the YubiKey, protected by PIN.
CHUID:	3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
CCC: 	No data available.
Slot 9a:
	Algorithm:	RSA2048
	Subject DN:	CN=Capybara
	Issuer DN:	CN=Capybara
	Serial:		410000000000000000000000000000000000000000000055
	Fingerprint:		5f000000000000000000000000000000000000000000000000000000000000ee
	Not before:	2022-06-12 06:17:05
	Not after:	2024-06-11 06:17:05

GUIツールでも証明書の情報が表示されています。

YubiKey Manager(GUI) PIV Certificates(登録済)

X.509 証明書の詳しい情報を確認する場合は下記のコマンドを実行します。

% ykman piv certificates export 9a - | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            22:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:ac
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Capybara
        Validity
            Not Before: Jun 12 06:17:05 2022 GMT
            Not After : Jun 11 06:17:05 2024 GMT
        Subject: CN=Capybara
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:d2:6c:c3:87:51:b0:0c:fd:9d:c2:0e:a9:07:4a:
                    〜〜 省略 〜〜
                    18:fd
                Exponent: 65537 (0x10001)
    Signature Algorithm: sha256WithRSAEncryption
         48:51:51:19:45:1f:c3:e0:68:8d:f6:cf:29:ad:4c:17:c0:de:
         〜〜 省略 〜〜
         84:89:d7:65
-----BEGIN CERTIFICATE-----
MIICsjCCAZqgAwIBAgIUIkBNq32J84S20CuA2NToSjyOs6wwDQYJKoZIhvcNAQEL
〜〜 省略 〜〜
XTR5/KdigsWVcH6f8Vo9zQ7fhInXZQ==
-----END CERTIFICATE-----

5. (補足) GUIツールで自己署名証明書を作成

GUIツールを使って作成することもできるので、画面を貼り付けておきます。

YubiKey Manager(GUI) PIV Certificates(登録)

[Applications] > [PIV] > [Configure Certificates] で証明書を作成するスロットを選択して[Generate] をクリック

YubiKey Manager(GUI) PIV Certificates(登録)Step1

“Self-signed certificate” を選択して[Next] をクリック

YubiKey Manager(GUI) PIV Certificates(登録)Step2

Algorithm を選択して[Next] をクリック

YubiKey Manager(GUI) PIV Certificates(登録)Step3

Subject を入力して[Next] をクリック

YubiKey Manager(GUI) PIV Certificates(登録)Step4

[Expiration date] を指定して[Next] をクリック

YubiKey Manager(GUI) PIV Certificates(登録)Step5

[Generate] をクリックするとYubiKey の指定したスロットに証明書が作成されます。

OpenSSH形式の公開鍵ファイル作成〜サーバに公開鍵を登録〜SSH接続

ここからはOpenSSH のコマンドを使った操作になります。

1. OpenSSH形式の公開鍵の作成

OpenSC に同梱されていたPKCS #11 のライブラリを指定して、OpenSSH 形式の公開鍵ファイルを作成します。

# コマンドの実行結果をターミナルに表示してエラーにならないことを確認する
$ ssh-keygen -D /opt/homebrew/opt/opensc/lib/opensc-pkcs11.so 
ssh-rsa AA0000000000000000000000000000000000000000000000000000000000000000000000kd PIV AUTH pubkey
 → エラーにならず公開鍵が出力された

# コマンドの実行結果をファイルに出力する
$ cd ~/.ssh
$ ssh-keygen -D /opt/homebrew/opt/opensc/lib/opensc-pkcs11.so >id_rsa_piv.pub

$ ls -l
-rw-r--r--  1 Capybara staff   397  6 12 15:28 id_rsa_piv.pub

2. 公開鍵をサーバにアップロード&登録

サーバに公開鍵をアップロードします。

scp id_rsa_piv.pub [email protected]:~/

サーバにSSHで接続して、接続ユーザの~/.ssh/authorized_keys公開鍵を登録します。

% ssh [email protected]

$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ cat id_rsa_piv.pub >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys

3. 公開鍵認証でサーバにSSH接続

SSH の公開鍵認証でサーバに接続できるか確認します。
実行するコマンドでは、OpenSC に同梱されていたPKCS #11 のライブラリを指定します。

$ ssh -I /opt/homebrew/opt/opensc/lib/opensc-pkcs11.so <ユーザ名>@<ホスト名>
Enter PIN for 'Capybara':
 → ここで登録したPIVのPIN を入力
 → YubiKey が点滅したらYubiKey をタッチ

PIN の手入力 + YubiKey をタッチ2要素認証でサーバに接続することができました。
鍵の生成でオプション–touch-policy ALWAYS を指定したのでYubiKey のタッチを求められましたが、このオプションを指定しない場合はPIN の入力のみになります。

4. クライアント側の設定でSSH接続コマンドの簡略化

クライアント側の~/.ssh/config に下記を記述します。

Host *
  HostName <ホスト名>
  User <ユーザ名>
  PKCS11Provider /opt/homebrew/opt/opensc/lib/opensc-pkcs11.so
  IdentitiesOnly no

上記の設定により、-I オプションを省略して接続できるようになります。

% ssh <ユーザ名>@<ホスト名>
Enter PIN for 'Capybara':
 → ここで登録したPIVのPIN を入力
 → YubiKey が点滅したらYubiKey をタッチ

5. パスワード認証を不許可に設定

SSHサーバの設定/etc/ssh/sshd_config でパスワード認証を不許可にすれば、登録した公開鍵を使った 認証しかできなくなります。

PubkeyAuthentication yes

Match User ubuntu
  PasswordAuthentication no
  AuthorizedKeysFile /home/ubuntu/.ssh/authorized_keys

systemctl reload sshd を実行して設定を反映します。

ssh-agent を使う

ssh-agent を使えばssh-agent にPIN を代理入力させて、YubiKey のタッチだけでSSH接続できるようだったので試してみましたが、ssh-agent に秘密鍵を登録するssh-add コマンドでエラーになりました。
エラーの原因や解消する方法が調べても分からなかったので、記録として残しておきます。

1. ssh-agentに秘密鍵の登録(失敗)

% ssh-add -s /opt/homebrew/opt/opensc/lib/opensc-pkcs11.so
Enter passphrase for PKCS#11:
Could not add card "/opt/homebrew/opt/opensc/lib/opensc-pkcs11.so": agent refused operation
 → 登録失敗
  • エラーの原因(仮定)
    • ssh-agent 起動時に参照するライブラリにPKCS #11 のライブラリがホワイトリストに登録されていないことによる
  • ホワイトリストに登録する方法
    • ssh-agent 起動時のパラメータは、/System/Library/LaunchAgents/com.openssh.ssh-agent.plist で定義されている
    • 上記plist ファイルを編集しようとしたが、readonly で更新できなかった(sudo vi で更新不可)
    • macOS Catalina から変更できなくなったという話があるが、解消方法は見つからなかった

以下、参照したサイト。

YubiKey のPIV を無効にする設定

YubiKey Manager にYubiKey のPIV を無効にする機能があったので、こちらもどのように機能するか試してみました。

  • GUIツールとCLIツールのどちらでも無効にすることはできます
  • この設定は前述のPIN の登録をしなくてもできます

1. YubiKey のFIDO を無効にする

GUIツールのメニューの[Interfaces] をクリックします。

YubiKey Manager(GUI) Interfaces PIV(有効)

左のUSB のPIV のチェックをOFF にして[Save Interfaces] をクリックします。

YubiKey Manager(GUI) Interfaces PIV(無効)

CLI ツールでPIV無効になっていることを確認します。

% ykman info
Device type: YubiKey 5 NFC
Serial number: 99999999
Firmware version: 5.4.3
Form factor: Keychain (USB-A)
Enabled USB interfaces: OTP, FIDO, CCID
NFC transport is enabled.

Applications	USB     	NFC
FIDO2       	Enabled 	Enabled
OTP         	Enabled 	Enabled
FIDO U2F    	Enabled 	Enabled
OATH        	Enabled 	Enabled
YubiHSM Auth	Disabled	Disabled
OpenPGP     	Enabled 	Enabled
PIV         	Disabled	Enabled

% ykman config usb --list
OTP
FIDO U2F
FIDO2
OATH
OpenPGP

16行目のPIV のUSB 欄がDisabled になっています。
また、18行目のコマンドの結果にPIV が出力されていないです。

2. PIV が無効の状態でSSH接続を試行

% ssh [email protected]
Enter PIN for 'OpenPGP card (User PIN)':
 → Ctl + C で中止

PIV のPIN ではなくOpenPGP のPIN の入力を求められたので、コマンドを中止しました。
ちなみに、YubiKey のOpenPGP は出荷時まま何も使用していない状態です。

今度はOpenPGP無効にしてコマンドを実行してみました。

% ssh [email protected]
[email protected]: Permission denied (publickey).

PIN の入力を求められることもなくエラーになりました。

この後、再度有効にして接続できるか試したら接続できました。
無効にしてもPIV の登録情報は削除されずに残ります。

参考まで、CLI ツールのPIV を無効・有効にするコマンドを載せておきます。

% ykman config usb -d PIV
Disable PIV.
Configure USB? [y/N]: y
 → 無効になる ※オプション[--disable] も同じ

% ykman config usb -e PIV
Enable PIV.
Configure USB? [y/N]: y
 → 有効になる ※オプション[--enable] も同じ
  • 上記のコマンドを実行するとYubiKey が点滅するのでタップしてみると、OTP のスロットに設定したYubico OTPの44文字が入力され「Error: invalid input」になった。点滅するけれどもタッチは不要です
  • GUIツールを開いた状態でCLIツールで有効・無効を変更してもGUIツールの表示は変わらない。変更をGUIツールの表示に反映するにはGUIアプリの再起動かYubiKey の再接続が必要

あとがき

PIV に関連して、気になっていることを2点記載しておきます。

YubiKey のPIV を使ったMac 本体のログイン

YubiKey のPIV を使ってMac 本体(OS)にログインするということもできるようです。

YubiKey Manager のGUI ツールのPIV の画面にある”Setup for macOS” をクリックして表示される画面に「macOSのアカウントとYubiKey のPIV に登録する証明書を紐づけて、macOS にYubiKey でログインできる」と書かれています。

YubiKey Manager(GUI) PIV Setup for macOS

この画面の[Setup for macOS] ボタンをクリックすると、YubiKey のPIV に必要な秘密鍵と証明書が作成されるようなのですが、上記Yubico のリンク先のページを見るとPIV を使ったMac 本体へのログインは、M1/Apple Silicon CPU では困難なことがあり非推奨となっていました。

M1 Mac users: not recommend

OS にログインできなくなってしまうと困るので、その困難なことが解消されるまでは試すのを保留にしておこうと思います。

マイナンバーカードの公的個人認証AP を使ったSSH公開鍵認証

マイナンバーカードには公的個人認証AP (JPKI-AP)という機能を備えていますが、これはYubiKey のPIV と同じように公開鍵暗号の秘密鍵とX.509 証明書を格納することができるので、これを使ってSSH サーバに公開鍵認証で接続することができるようです。

公的個人認証AP はマイナポータルなど対応しているサイトへのログイン時に利用されるものですが、このような活用方法があるというのはなんか面白いです。

カードリーダーを持っていれば試せるのですが、持っていないので残念です。

参考