YubiKey4 我踩过的那些坑

讲道理,我觉得再一再二不能再三,踩坑踩的太多了就不能再踩了,不然智商都没了……

背景

说到踩坑,其实我在 Yubikey 里踩的坑那可谓数不胜数:

第一次买了Key,找了个很渣的教程,上去直接 newcardkey 就生成了一个,存卡里不说,还没法备份,导致直接用这个key用了很久,然后很悲剧的被同学“物理损坏”了(

后面不甘心,又买了个,这回我可是百般呵护啊:单独生成 Key ,准备了加密备份,断网操作,丢到可移动存储设备里,写卡,发布正可谓一气呵成(

然后还是难逃命运的巨轮:备份物理损坏,过了一段时间后,这个 key 莫名其妙的无法签名 & 加密数据。哇~ 从小到大哪里受过这个气,排除很多问题后依旧无法解决((

然后就产生了下面的这个对话:

就这样,为了防止自己继续踩坑,我打算用此文祭奠我那可怜的卡……和 Key……们……

介绍

先上个 Wikipedia 的 link 吧。

GNU Privacy Guard (GnuPG or GPG) is a free software replacement for Symantec’s PGP cryptographic software suite.[5] GnuPG is compliant with RFC 4880, which is the IETF standards track specification of OpenPGP. Modern versions of PGP are interoperable with GnuPG and other OpenPGP-compliant systems.

GnuPG is part of the GNU Project, and has received major funding from the German government.[6]

关于这个,千万别和 PGP 搞混了:

Pretty Good Privacy (PGP) is an encryption program that provides cryptographic privacy and authentication for data communication. PGP is used for signing, encrypting, and decrypting texts, e-mails, files, directories, and whole disk partitions and to increase the security of e-mail communications. Phil Zimmermann developed PGP in 1991.[2]

PGP and similar software follow the OpenPGP standard (RFC 4880) for encrypting and decrypting data.

上刀

本文的目的有两个,一个是防止自己再踩坑,另一个是写出来给大家看的(弱

显然,看标题都知道要把 Key 丢到 Yubikey 里(或者别的什么 SmartCard 里)。

材料准备

你需要准备以下材料才能继续调配黑魔法药水……

  • 能上网的电脑
  • Linux / MacOS 操作系统(别问我为啥不用 Windows)
  • 😩 一张苦逼的脸
  • 能拔掉的网线(你用WiFi就关闭WiFi好了)
  • 一个物理存储器(U盘),方便存备份密钥
  • 一张由人类生产的靠谱的智能卡(SmartCard)
  • 一颗能折腾的心💖

调配药水前的准备工作

首先联网,装好 GnuPG 软件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# CentOS
sudo yum -y install gpg

# Debian / Ubuntu
sudo apt install gpg

# Arch Linux
sudo pacman -S gpg

# MacOS
brew install gpg

# Fedora
sudo dnf install gnupg

不过关于 Mac,还有个很方便的 Suite 可以用:GPGTools

如果装了 GPGTools 就不用再用 brew 装了。

生成 KeyPair

嗯,这才是正片环节。

接下来的步骤请断网操作。

Step I. 生成密钥对
1
gpg --gen-key

显示欢迎信息,并提示选择 key 类型

1
2
3
4
5
6
7
8
9
10
gpg (GnuPG/MacGPG2) 2.2.0; Copyright (C) 2017 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
Your selection?

当然果断选1啦~

1
2
RSA keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048)

这里说下,Yubikey4 最高支持 4096 位的Key,所以这里生成当然可以直接用 4096 位。

1
2
3
4
5
6
7
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0)

有效期嘛,看你心情了,反正又不是不能改。

1
2
3
4
5
6
7
GnuPG needs to construct a user ID to identify your key.

Real name: FirstName LastName
Email address: [email protected]
Comment: Comment Here
You selected this USER-ID:
"FirstName LastName (Comment Here) <[email protected]>"

格式列在上面了,生成出来的 Key 会遵照这个格式显示的。

这里呢,输入一个足够强的私钥保护密码就可以了。记住了,不能丢。

1
2
3
4
5
6
public and secret key created and signed.
(pub开头是主密钥 密钥格式+长度/KeyID 生成时间 密钥功能)
pub rsa4096/0x0000000000000000 2017-10-07 [SC]
FFFFFFFFFFFFFFFF0000000000000000(这个是Key指纹)
uid FirstName LastName (Comment Here) <[email protected]> (这是用户ID信息)
sub rsa4096/0x0000000000000000 2017-10-07 [E]

关于功能的解释如下:

  • 签名(S, Sign)
  • 证书(C, Certificate)
  • 加密(E, Encryption)
  • 认证(A, Authenticate)

之后你的密钥对就生成好了,存放在 Keyring 里。

Step II. 生成子密钥
1
2
3
gpg --expert --edit-key [KeyID]

gpg> addkey

过程和第一步差不多,一共生成三个子密钥,长度都是 4096 位就可以。

先是生成一个签名 RSA (sign only) 用的。

然后再运行一次,生成一个加密 RSA (encrypt only) 用的。

然后再运行一次,生成一个认证 RSA (set your own capabilities) 用的。

这一步有点不同,大致过程是这样的,照葫芦画瓢就行:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Please select what kind of key you want:
(3) DSA (sign only)
(4) RSA (sign only)
(5) Elgamal (encrypt only)
(6) RSA (encrypt only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
Your selection? 8

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Sign Encrypt

(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished

Your selection? s

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Encrypt

(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished

Your selection? e

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions:

(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished

Your selection? a

Possible actions for a RSA key: Sign Encrypt Authenticate
Current allowed actions: Authenticate

(S) Toggle the sign capability
(E) Toggle the encrypt capability
(A) Toggle the authenticate capability
(Q) Finished

Your selection? q

剩下的步骤都一样。
之后呢,保存退出。

1
gpg> save
Step III. 吊销凭证

建议生成一个对应的吊销凭证,一般来说,新版的 GPG 会自动生成好,存放到 ~/.gnupg/openpgp-revocs.d 目录里, 并且会在刚才生成时候告诉你:

1
asgpg: revocation certificate stored as '~/.gnupg/openpgp-revocs.d/[FINGERPRINT].rev'

当然你也可以手动生成一个

1
gpg --ken-revoke [KeyID]
Step IV. 导出密钥

这步很关键,拿出准备好的物理存储器,插上,然后执行导出命令

1
2
gpg --armor --output public.gpg.asc --export [KeyID]
gpg --armor --output private.gpg.asc --export-secret-keys [KeyID]

然后把这两个文件存到你的存储器里。

你也可以把第三步的吊销凭证也放进去,以防万一。

Step V. 上传
如果你有硬件Key,这里不要急着插网线上网,暂且跳过这一步,等做完写卡操作后,再回到这边继续上传。

这里请拔出你的存储器,重新插上你的网线,然后继续。

上传就很简单了,一个命令的事情。

1
gpg --send-keys [KeyID]

当然你要想上传到其他的服务器,也是可以的:

1
gpg --keyserver hkp://subkeys.pgp.net --send-keys [KeyID]

我个人习惯用 hkp://pgp.mit.edu

Step VI. 配置 Yubikey

唉,总算到了本文一开始写的目的这里了。

插入你的 Yubikey,先做一下初始化:

1
gpg --card-edit

首次使用一定要先配置一下卡密码(PIN Code),一共有三组 PIN,分别为:

  • PIN (签名常用的 默认 123456)
  • Admin PIN (配置卡用的 默认 12345678)
  • Reset Code (重置Sign PIN用的)

这三个 PIN 可以是字母和数字。

  • PIN 码是平时最常用的密码,如果输错三次就会被锁定,需要使用 Reset Code 来解锁,Reset Code 输错三次,只能物理重置
  • Admin PIN 是管理卡信息(如添加密钥、修改密码)使用的密码,不能短于 8 位,输错三次则管理功能被锁定,只能物理重置。 __记住,千万不要在需要输入 Admin PIN 的时候输入短于 8 位的密码,这样会直接锁定__。

修改方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
gpg/card> admin
Admin commands are allowed

gpg/card> passwd
gpg: OpenPGP card no. Dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx detected

1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit

Your selection?

分别执行 1,3,4然后退出就可以。

你可以继续设置一些其他信息,比如持卡人姓名、公钥的URL等等,也可以下次再弄。修改这些信息,需要用到 Admin PIN。

Step VII. 存入密钥

先说一句:__不推荐把主密钥放进 YubiKey 里__,因为主密钥还有一个重要功能就是维持社交关系,时间流逝,子密钥可能经常变化,而别人只需要记住你的主密钥ID就可以随时更新。如果把主密钥放进 YubiKey 里,万一丢了,那么你就无法证明你是你了。

先编辑刚刚的 Key:

1
gpg --edit-key [KeyID]

然后使用 key [X] 来选中需要操作的子密钥。

Yubikey 有三个 Slot,分别可以存 S, A, E三种密钥。

选好 Key 后,使用 keytocard 命令存入卡的对应位置。

最后保存

1
gpg> save

从此,你的私钥 Key 再也无法备份保存了。

原理大致是这样的:GPG 将私钥存入卡后,向私钥添加了一个标志位,说明此私钥受到卡保护,需要插入卡才能解锁私钥使用。所以你即使现在导出私钥,也是导出了带有卡保护标志位的私钥,丢失卡后照样无法使用私钥。

这时候执行 gpg -K 可以发现你的 Key 多出一行内容:Card serial no. = xxxx xxxxxxxx,这个就是卡的序列号了,说明私钥受到卡保护。

Step VIII. 测试

你可以用这种方法测试一下卡签名功能:

1
echo foo | gpg --clearsign

正常来说应该会弹出输入PIN的地方,输入PIN后会完成签名,并把结果打印在屏幕上。

Step IX. 奇技淫巧
  • 如果你在第六步末尾设置了公钥URL,那么以后你就可以在其他电脑/设备上插入 Yubikey,在 gpg --card-edit 中执行 fetch 命令快速取回公钥并存入 Keyring 中。
  • 当然,如果你觉得签名/加密/认证操作不够酷炫,Yubico 有一个 ykman 工具可以让 Yubikey 仅在手指按后才会执行签名/加密/认证操作。
Step X. SSH 认证

第二步生成的子密钥里有一个认证(A)用的密钥还记得么?

这里可以用于 SSH 认证。

首先确认下有没有装 gpg-agent:

1
2
3
gpg-agent

gpg-agent[7002]: gpg-agent running and available

没有的话就装一个咯

1
brew install gpg-agent

将以下脚本加入到 shell 的 rc 里。我用的是 zsh,在 ~/.zshrc

1
2
3
4
5
6
if [ -f "${HOME}/.gpg-agent-info" ]; then
. "${HOME}/.gpg-agent-info"
export GPG_AGENT_INFO
export SSH_AUTH_SOCK
export SSH_AGENT_PID
fi

将以下内容添加到 ~/.gnupg/gpg-agent.conf (其他OS用户请参照文档自行替换PINEntry)

1
2
3
4
5
pinentry-program /usr/local/MacGPG2/libexec/pinentry-mac.app/Contents/MacOS/pinentry-mac
default-cache-ttl 600
max-cache-ttl 7200
enable-ssh-support
write-env-file

然后执行下面这个我找了半天文档没找到,还Bug巨多的命令:

1
/usr/local/MacGPG2/bin/gpgkey2ssh [KeyID]

会生成一个符合 OpenSSH 标准的 SSH Public Key 给你,把这个 Key 放服务器 authorized_keys 里就可以用 Yubikey 实现登录服务器了。

__然而__,我死活找不到这个工具了……

找了半天,发现官方发了个声明

gpgkey2ssh has gone, –export-ssh-key is here.

gpgkey2ssh was more or less a debugging tool but turned out to be useful to many. However, it was pretty limited and did not support modern ssh keys. An easier solution to export OpenPGP’s public keys in the SSH public key format is by adding a command to gpg.

怪不得没文档还一堆Bug,原来就是个调试工具啊(

那行了,现在的新方法是使用 --export-ssh-key 参数来生成

1
gpg --export-ssh-key [KeyID]

将输出的内容贴到服务器的authorized_keys 里,愉快的玩耍吧(

其他玩法

sudo Pam.d 认证

简单点说,就是使用 yubikey 去授权你的登录与 sudo 操作,我做了个 gif 可以看看效果:

实现的话其实也不是很难,先说 MacOS:

注如果你的设备启动了FDE(FileValut, Full Disk Encryption, 全盘加密),请不要使用除sudo之外的玩法,因为在首次登录前,你的 u2f 文件是无法被系统读取到的。
准备工作
  1. Time Machine Backup - 刚道理啊,这个很重要的,万一改错了还能回来呢……岂不美哉(
  2. Fido U2F Yubikey - 别买 NFC 的,iOS 还不支持,Yubikey 4 就可以用
    Update: Yuubikey 5 支持 NFC 了,是可以用的
  3. Homebrew for OS X (or higher) - 需要装个 pam-u2f 。没装过 Homebrew 可以先 安装 Homebrew
安装组件

安装很简单,就一行: brew install pam-u2f

1
2
3
4
5
6
7
8
9
10
11
12
==> Downloading https://homebrew.bintray.com/bottles/pam-u2f-1.0.4.yosemite.bott
Already downloaded: /Library/Caches/Homebrew/pam-u2f-1.0.4.yosemite.bottle.tar.gz
==> Pouring pam-u2f-1.0.4.yosemite.bottle.tar.gz
==> Caveats
To use a U2F key for PAM authentication, specify the full path to the
module (/usr/local/Cellar/pam-u2f/1.0.4/lib/pam/pam_u2f.so) in a PAM
configuration. You can find all PAM configurations in /etc/pam.d.

For further installation instructions, please visit
https://developers.yubico.com/pam-u2f/#installation.
==> Summary
🍺 /usr/local/Cellar/pam-u2f/1.0.4: 10 files, 78.5K

(可选) 在 pam 里设置绝对路径也是可以用的,我是这么设置的。版本号不一样可以自己改下:

注意:如果你的设备已经关闭了[SIP (System Integrity Protection)](https://support.apple.com/HT204899) [Wikipedia](https://en.wikipedia.org/wiki/System_Integrity_Protection),才可以免完整路径使用,否则请填写完整路径。
1
ln -s /usr/local/Cellar/pam-u2f/1.0.4/lib/pam/pam_u2f.so /usr/lib/pam/
设置U2F授权
需要在插入key下完成下列步骤,执行下列步骤时可能会卡住屏幕输出,这时有可能是需要你按下U2F的按钮来完成认证,如果你的U2F指示灯闪烁,按一下就好了。

先在你的终端跑一下 pamu2fcfg,不出意外,应该会在屏幕上打印出一个你的 用户名:hash 的东西。复制下来存到 ~/.config/Yubico/u2f_keys 中即可。

zsh 应该会在打印后输出一个 `%` 在结尾,复制的时候要注意别复制到这个字符。

初次创建,建议使用以下操作:

1
2
3
mkdir -p ~/.config/Yubico/
pamu2fcfg > ~/.config/Yubico/u2f_keys
cat ~/.config/Yubico/u2f_keys # should output <your username>:<really long hash>

执行后应该看到生成的结果。

如果有多个U2F Key, 不能直接在u2f_mappings里放两行, 同一个用户名只能放一行, 按以下格式, 以 : 分隔:

1
2
<username1>:<KeyHandle1>,<UserKey1>:<KeyHandle2>,<UserKey2>:...
<username2>:<KeyHandle1>,<UserKey1>:<KeyHandle2>,<UserKey2>:...
配置sudo U2F授权
此时,建议多开一个窗口去 `sudo su`,以防文件改错,测试挂掉的话无法把文件改回来。

先sudo编辑文件 /etc/pam.d/sudo

1
2
3
4
5
# sudo: auth account password session
auth required pam_opendirectory.so
account required pam_permit.so
password required pam_deny.so
session required pam_permit.so

在第一行之后新插入一行,可以按需填写以下内容:

1
2
3
4
5
6
# 指纹授权,建议 MacBook Pro 有指纹款使用
auth sufficient pam_tid.so
# 手表授权,编译模块后可以引用
auth sufficient pam_watchid.so
# U2F授权
auth sufficient /usr/local/opt/pam-u2f/lib/pam/pam_u2f.so cue

以上配置效果是和gif一样的,先尝试指纹授权,如果失败则请求U2F授权,如果依旧失败则采用密码授权。配置中,指纹与U2F都是可选项目(可以跳过),但是密码授权则是在上述授权失败的情况下必须使用。

如果要改为U2F与密码同时通过才放行,可以将 sufficient 改为 required

Pro MacBook Pro Tip: have a Touch Bar with Touch ID? If you edit /etc/pam.d/sudo and add the following line to the top…

auth sufficient pam_tid.so

…you can now use your fingerprint to sudo!

Apr 17 2019, Update:
由于苹果的策略有修改,在 iTerm 中使用苹果自带的 pam_tid.so 会有兼容性问题,参考Gitlab Issue #7527

Jul 22 2019, Update:
按照之前的说法,#7527 似乎被解决了,但是我仍在使用自己编译的版本。持续观望中(

配置锁屏 U2F授权
无论何时,请先使用 `sufficient` 做测试,之后再切换到 `required` 。

文件是 /etc/pam.d/screensaver

1
2
3
4
5
# screensaver: auth account
auth sufficient pam_u2f.so
auth optional pam_krb5.so use_first_pass use_kcminit
...
... and so on

然后保存,测试锁屏即可。

因为使用了 `sufficient`,即使key不在也可以用密码登录。 点亮屏幕后,仍然需要输入空密码(就是直接回车)然后再根据U2Fkey提示去按下key。
如果改为 `required`,密码与U2F需要都通过认证才可以登录系统。
配置登录 U2F授权
无论何时,请先使用 `sufficient` 做测试,之后再切换到 `required` 。

文件是 /etc/pam.d/authorization

修改时候建议先创建一个新的admin账户,方便登录后可以免于被锁在电脑外。还一个方法是使用 `sufficient` 做测试,之后再切换到 `required`
1
2
3
4
5
# authorization: auth account
auth sufficient pam_u2f.so
auth optional pam_krb5.so use_first_pass use_kcminit
...
... and so on

然后保存,重启后测试登录即可。

关于Debug

在结尾加个 debug 就可以输出调试信息了。

1
auth       sufficient     pam_u2f.so debug

参考链接

没有你们的帮助,我也写不出这么多东西,在此表示感谢

YubiKey4 我踩过的那些坑

https://blog.dwx.io/yubikey4/

Author

Jason

Posted on

07/10/17

Updated on

10/12/20

Licensed under

Comments

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×