Fedora 上使用硬體加密的 SSH 與 PGP

從一開始入手 Yubikey 4,後來換成 Yubikey 5 NFC,我已經很久沒有把 SSH 跟 PGP 的密鑰放在檔案系統裡過了。我最近新買了一隻 Yubikey 5 Nano,簡單設定後紀錄分享一下怎麼使用硬體加密的 SSH 和 PGP 簽章。

Yubikey 的原理是它有一個硬體的「安全元件 (secure element)」可以用來實做各種智慧卡 (smart card) 的功能,這裡我們關心的是它的 PIV (personal identity verification) 與 PGP 兩個智慧卡界面。

PIV 與 PKCS#11 與 PC/SC

PIV 是一種智慧卡的標準,定義了智慧卡需要支援的金鑰格式,演算法等等。Yubikey 的 PIV 支援標準的 9a, 9c, 9d, 9e 金鑰儲區,還有額外的 10 個以上的過期金鑰儲存位置。這些標準的金鑰儲存區分別用來「認證」、「簽章」、「加密」、「驗證」。雖然沒有強制規定這些金鑰要怎麼使用,通常 SSH 會設定為使用 9a 的「認證」用金鑰區來儲存 SSH 的私鑰。

SSH 不是直接使用 PIV 來使用智慧卡,而是支援另外一個標準 PKCS#11,這個標準定義了統一的抽象軟體界面來提供硬體的加密演算法功能。Yubico 有提供自己的 libykcs11.so 這個函式庫可以直接使用 Yubikey 上的 PIV 功能,而 Fedora, Debian 等系統則預設使用 OpenSC 的 opensc-pkcs11.so 這個函式庫。OpenSC 則仰賴 pcscd-lite 這個程式透過標準的 PC/SC 界面和各種不同的智慧卡溝通。

因為同一個系統上可以同時有多個不同的 PKCS#11 函式庫,Fedora 便用 p11-kit 的 p11-kit-proxy 來更簡單的使用不同的 PKCS#11 提供元。

PKCS#11 相關的軟體生態相當複雜,簡化為一張圖的話大概繪像這樣:

實際上因為用了 p11-kit 的關係,所以設定起來其實非常簡單。首先先用 ykman 產生私鑰(預設是 RSA 2048 bit)跟公鑰(包裝為 X.509 憑證格式):

然後就可以使用了,可以用 ssh-keygen 把公鑰弄出來,然後設定 ssh 預設用 p11-kit-proxy 來存取私鑰:

設定起來算是相當無腦(參考文章)。

GnuPG 與 scdaemon

我一開始用 Yubikey 主要就是為了它的硬體 PGP 智慧卡,搭配 GnuPG 可以實現簽章、加密、SSH 認證三個功能。這是一個常用的功能,而且網路上已經有許多的文件說明,這裡就不再重複。我想要紀錄的是如何讓 GnuPG 與 PIV 共存。

網路搜尋可以發現許多關於 gpg –card-status 不正常運作的問題:

這是因為 GnuPG 跟 OpenSC / pcscd 都需要透過 CCID 這個 USB 通訊協定跟智慧卡溝通,但是 GnuPG 用來實現這個功能的工具程式 scdaemon 預設會開啟獨占模式,不允許其他的程式也使用系統上的智慧卡,理由是 scdaemon 會暫時快取一些狀態在記憶體裡面,如果其他程式也同時使用智慧卡的話,有可能會造成狀態不一致的錯誤。相關的討論中如 T6218T2440 可以看到 GnuPG 的開發者並不願意改變這個預設行為。

網路上有許多很久以前的解法,甚至 pcsc-lite 的作者都有一篇 blog 說明這個問題。我測試後現在可以暫時解決這個問題的方法是強制 scdaemon 以共享模式使用 pscsd 的資源:

這樣就可以讓 gpg 幾乎都可以正常運作。如果還是有問題,跑指令

也幾乎都可以解決。

基於現在 Debian 還是只能用 PGP 來認證上傳的套件,希望 GnuPG 可以改善 scdaemon 的預設行為,跟其他軟體和平相處。▞