YubiKey 在 Linux 以及 Mac 上要如何設定
How to Generate Keys with YubiKey
這部分請參考 GPG 與 YubiKey 的相遇之旅 | Shawn Hsu
Public Key Installation
我買 YubiKey 的重點,我想要能夠跨平台的使用 GPG key
所以接下來就是實測能不能跨平台使用
主要的概念其實很簡單 在使用的機器上必須要有 public key 就可以了
而要怎麼樣拿到 public key 呢?
手動匯入 public key 或者是透過 keyserver 直接拉下來
Manual Import
手動上傳的方式就是你必須有 public 的檔案(或文字)
取得 GPG public key 的方法是
1
$ gpg --export --armor xxxxxxxxx > gpg-public-key
然後在目標電腦上匯入
1
$ gpg --import /PATH/TO/gpg-public-key
Ubuntu Keyserver
你可以選擇將 public key 上傳到 keyserver(e.g. keyserver.ubuntu.com)
1
2
$ gpg --keyserver hkps://keyserver.ubuntu.com --send-keys xxxxxxxxx
$ gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys xxxxxxxxx
其中
xxxxxxxxx為 signature key id,你可以用$ gpg --card-status來取得
因為你上傳的是公鑰,所以它就算送到網路上也是安全的
像我的就會長這樣 https://keyserver.ubuntu.com/pks/lookup?search=7C4FA560330319BC5404972D7AD157320911F131&fingerprint=on&op=index

Note: 上傳到 keyserver 的 public key 是沒辦法被刪掉的哦
Setup YubiKey
Linux
Prerequisite
1
2
3
$ mkdir -p ~/.gnupg
$ sudo apt update && sudo apt install -y vim gnupg2 gnupg-agent scdaemon pcscd wget
$ cd ~/.gnupg && wget https://raw.githubusercontent.com/drduh/config/master/gpg.conf
1
2
3
4
5
6
7
8
9
10
11
# 啟用 GPG 對 SSH 的支援
$ echo enable-ssh-support >> ~/.gnupg/gpg-agent.conf
# 指定要用哪一把 key
# 這裡 key id 要用 40 bits 的 fingerprint
$ echo YOUR_GPG_KEY_ID >> ~/.gnupg/sshcontrol
# 指定 SSH 如何存取 GPG-agent
$ echo $'export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)\ngpgconf --launch gpg-agent' >> ~/.bashrc
$ echo $'export GPG_TTY=$(tty)' >> ~/.bashrc
$ source ~/.bashrc
Mac
MacOS 也差不多
1
$ brew install brew-cask-completion yubico-authenticator gnupg pinentry-mac
1
2
3
4
5
6
7
8
9
10
11
# 啟用 GPG 對 SSH 的支援
$ echo enable-ssh-support >> ~/.gnupg/gpg-agent.conf
# 指定要用哪一把 key
# 這裡 key id 要用 40 bits 的 fingerprint
$ echo YOUR_GPG_KEY_ID >> ~/.gnupg/sshcontrol
# 指定 SSH 如何存取 GPG-agent
$ echo $'export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)\ngpgconf --launch gpg-agent' >> ~/.bashrc
$ echo $'export GPG_TTY=$(tty)' >> ~/.bashrc
$ source ~/.bashrc
Mac 的部分建議是用 pinentry-mac

我一開始是直接把它改成 pinentry-tty
也就是直接在 terminal 輸入密碼,但我發現他很容易掛掉,導致你的 terminal 會需要重開
所以還是建議用 pinentry-mac
40 bits Fingerprint
40-bit 的 fingerprint 你可以用以下指令拿到
1
$ gpg --show-keys --with-fingerprint gpg-key.pub
其中 gpg-key.pub 的檔案內容為你的 gpg public key 公鑰
Debug
如果你發現照著做,但他依然沒反應
請記得 移除 YubiKey 再重新插入
請記得 移除 YubiKey 再重新插入
請記得 移除 YubiKey 再重新插入
搭配以下指令
1
2
3
4
alias gpg-restart="gpg-connect-agent updatestartuptty /bye > /dev/null"
# 然後在 terminal 就可以
$ gpg-restart
Test GPG sign works or not
為了要驗證是否可以進行簽名以及加密
考慮以下實驗
1
2
3
4
5
$ cd /tmp
$ echo test > gpg_test.txt
# 將 YubiKey 插入
$ gpg --clearsign -o gpg_test2.txt gpg_test.txt
$ gpg --verify
如果 GPG 成功簽名你會得到以下輸出
1
2
3
gpg: Signature made 廿廿二年三月十一日 (週五) 〇時〇分
gpg: using RSA key xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
gpg: Good signature from "Shawn Hsu (COMMENT) <TEST@TEST.COM>" [ultimate]
如果把金鑰拔掉,就無法正確進行簽名
Git with GPG
如果都設定好,那麼接下來就都挺簡單的了
1
2
$ git config --global commit.gpgsign true
$ git config --global user.signingkey xxxxxxxxxxxx
其中 xxxxxxxxxxxx 為你的 GPG fingerprint
這樣設定完成之後,之後所有的 commit 都會預設要求簽名
40-bit 的 fingerprint 你可以用以下指令拿到
1
$ gpg --show-keys --with-fingerprint gpg-key.pub
其中 gpg-key.pub 的檔案內容為你的 gpg public key 公鑰
基本上這樣就可以了
可以試著簽名簽看看
簽完你可以使用 verify-commit 查看是不是有正確的簽章
1
2
3
4
$ git verify-commit HEAD
gpg: Signature made 廿廿二年五月卅日 (週一) 十九時一�
gpg: using RSA key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
gpg: Good signature from "Shawn Hsu (COMMENT) <TEST@TEST.com>" [ultimate]
Add more Accounts to GPG

如果你有多組 Email, 而他們都用同一組 GPG 的情況下
在 GitHub 上就會遇到即使你用了 GPG, 仍然是 Unverified 的情況
原因是因為你的 GPG 只有綁定一組 user id
以我的情況來說,我有兩組 email 需要使用(私人以及公司用)
所以正常情況下加一組 user id 就可以了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ gpg --edit-key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
gpg> adduid
# 然後輸入姓名,email, 註解, 密碼
Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
# 確認輸入
# 接著輸入 Yubikey 的密碼驗證
[ultimate] (1) Shawn Hsu <TEST@TEST.com>
[ unknown] (2). Shawn Hsu <TEST2@TEST2.com>
# 這裡它會列出目前的 user id
# 可以看到第一組是我原本的,已經被設定為永遠信任
# 接下來就是要把新的 user id 加入信任名單裡面
gpg> uid 2
# 選擇特定組別的 user id, 號碼是上面括號內的
[ultimate] (1) Shawn Hsu <TEST@TEST.com>
[ unknown] (2). Shawn Hsu <TEST2@TEST2.com>
# 選定的會用星號標示,如果要取消選擇就在輸入一次 uid 2 就會取消了(toggle)
gpg> trust
# 可以依照你的喜好決定要多信任這組 user id
# 我是選 5(亦即 ultimate trust)
[ultimate] (1) Shawn Hsu <TEST@TEST.com>
[ultimate] (2). Shawn Hsu <TEST2@TEST2.com>
gpg> save
# 最後存檔離開就可以了
最後記得要更新公鑰
因為你已經新增了一組 user id, 公鑰的內容也會改變
1
$ gpg --export --armor xxxxxxxxxx
其中 xxxxxxxxxx 是 GPG 公鑰的 fingerprint
然後把公鑰更新到 GitHub 上
用好之後在 GitHub 上面看就會是長這樣
從原本的只有一個 email

變成有兩個 email

另外要移除 user id 也是類似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ gpg --edit-key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[ultimate] (1) Shawn Hsu <TEST@TEST.com>
[ultimate] (2). Shawn Hsu <TEST2@TEST2.com>
gpg> uid 2
# 選定第二組 user id
gpg> revuid
# 選 4(no longer valid)
# 輸入密碼做確認即可以刪除
[ultimate] (1) Shawn Hsu <TEST@TEST.com>
[ revoked] (2). Shawn Hsu <TEST2@TEST2.com>
gpg> save
# 最後存檔離開就可以
也一樣要更新公鑰
Troubleshooting
Bad owner or permissions on ~/.ssh/config
我完成所有的步驟要測試 SSH 的時候遇到 Bad owner or permissions on ~/.ssh/config 這個問題
其實滿簡單的,因為 ssh config 算是滿機密的東西,如果被其他人可以改寫就不是太好
在底下的實例你也看到上面不小心將 write 權限給予 group 了
解決辦法也很簡單,用 chmod 把 file mode 改成 644 即可
1
2
3
4
5
6
7
8
$ ls -al
-rw-rw-r-- 1 ambersun ambersun 53 三 17 03:05 config
# 可以看到上面的 file mode 跑掉了
$ chmod 644 ./config
$ ls -al
-rw-r--r-- 1 ambersun ambersun 53 三 17 03:05 config
# 正確的 file mode 應該只有 owner 可以有 write 的權限
Error: gpg failed to sign the data
1
2
error: gpg failed to sign the data
fatal: failed to write commit object
如果說你在 sign 資料的時候出現這個錯誤
在 .bashrc 裡面寫入以下
1
export GPG_TTY=$(tty)
基本上就可以動了
你可以透過以下指令測試
1
$ echo "test" | gpg --clearsign
如果還是不行
那八成是 gpg-agent 因為不明原因壞掉
簡單來說,重啟 gpg-agent 就可以了
1
$ pkill gpg-agent
如果使用 pkill 仍然無法解決,我的話是暫時把 Yubikey 從 usb 移除,跑一次 pkill 就可以了
我試過 gpgconf, systemctl, clear gpg cache 全都沒用
Delay or Disable Yubikey OTP
我在用 Yubikey 其實用得很開心
唯一不開心的點在於說只要我稍微不小心碰到它,它就會產生 OTP
然後它就會自動貼上 OTP
雖然說 OTP 被洩漏不算太大的問題,但三不五時出來還是很討厭
Accidentally Triggering OTP Codes with Your Nano YubiKey 官方文件有提到可以關掉或者是延長 OTP 的時間
一種方法是直接關了
反正要再打開也挺容易的

ref: YubiKey Manager
另一種則是把 OPT 的 trigger 方式改成 按住 3 秒才啟動
也就是 long press(Swapping Yubico OTP from Slot 1 to Slot 2)
slot 1 指的是 short press
slot 2 指的是 long press
ref: [question] newbie: what is slot 1 and slot 2?

把 slot 改成 long touch 就設定好了
然後測試的方式也挺簡單的,按上去試試,它會有反應,但如果時間不夠長,它不會發 OTP
Failed connecting to the Yubikey. Make sure the application has the required permissions.
單純沒權限,要用 root
如果是 AppImage 就直接 sudo ./YubiKeyManager.AppImage 來啟動
YubiKey with USB Extension Cable
值得注意的是,如果你使用 USB 延長線可能會導致部份功能無法使用
根據我自己的實測顯示,延長兩段以上,YubiKey OTP 的功能在這個情況下是沒有反應的
不過 SSH 以及 GPG 的功能是正常的
比如說我的 GitHub 有使用 YubiKey 設定 MFA
在使用延長線的狀況下,你的金鑰會閃,但是你按上去是沒有反應的
Leave a comment