2022年07月05日更新:gnupg-agent配置
手上的Yubikey 5 NFC一直以来都是我2FA的设备之一,这阵子也偶然了解到CanoKey这款产品,也是和Yubikey比较类似,看了不少关于GPG/PGP相关的文章,于是乎想要自己实践一下。
比较让人熟知的Yubikey,或者硬件密钥的用法都是U2F、TOTP/HOTP之类的。我手上的这款Yubikey 5 NFC也支持PIV和OpenPGP标准。值得注意的是,PIV和OpenPGP的密钥存储区不共享,分别是X.509和GPG密钥。X.509和OpenPGP两者即使能互相转换,也不应该混为一谈,OpenPGP对S/MIME的X.509有一些支持,但不能逐字使用X.509 PrivateKey。在我看来X.509和OpenPGP在使用上的区别主要体现在,X.509被设计成有一套严格的层次化的证书颁发机构,即为CA,机构背书下的绝对信任。而OpenPGP是任何人都可以签名,从而证明其他人密钥证书的有效性,是属于比较偏社交化的。
在Windows上和PIV以及OpenPGP进行交互都不是那么的方便,这边推荐OpenSC
这个库,来帮助实现简单的证书读取、链接等功能。
列出密钥
gpg --fingerprint --keyid-format long -K
创建密钥
生成主密钥
gpg --full-gen-key --expert
在这一步中,会选择密钥的算法、有效期、UserID、Email等信息。
在这一步中比较重要的是,选择主密钥的功能。大家有不同的分配。一个密钥可以担任Encr、Auth、Sign、Certify,这四种功能,分别为加密、鉴权、签名、认证。我的做法是,主密钥仅保留认证C功能,然后分别签发出E、A、S三种子密钥,存放在硬件密钥中。主密钥做好脱机备份,大部分时间的物理隔离即可。
生成子密钥
gpg --quick-add-key <fingerprint> rsa3072 encr 2y
gpg --quick-add-key <fingerprint> rsa3072 auth 2y
gpg --quick-add-key <fingerprint> rsa3072 sign 2y
<fingerprint>
需要填写的是主密钥的指纹,这个可以通过列出密钥来查看。
后面依次指定子密钥的加密算法、用途、有效时长。
导出备份
上述所有步骤都是在本机上进行的,也可以直接使用OpenPGP Card规范中,在硬件中生成密钥的功能。
我们需要导出公钥以及各密钥的私钥,以便进行其他工作。
# 公钥
gpg -ao public-key.pub --export <fingerprint>
# 主密钥,请务必保存好。
# 注意<fingerprint>后面的 !
# 表示只导出这一个私钥,若没有的话默认导出全部私钥。
gpg -ao sec-key.asc --export-secret-key <fingerprint>!
# 子密钥
gpg -ao sign-key.asc --export-secret-key <fingerprint>!
gpg -ao auth-key.asc --export-secret-key <fingerprint>!
gpg -ao encr-key.asc --export-secret-key <fingerprint>!
导入OpenPGP Card
# 查看智能卡设备状态
gpg --card-status
# 写入GPG
gpg --edit-key <fingerprint> # 主密钥
# 选中第一个子密钥
key 1
# 写入到智能卡
keytocard
## 依次进行,注意选择各个插槽以及密钥用途的对应。
# 保存修改并退出
save
# 再次查看设备状态,可以看到相关槽位有密钥信息了。
gpg --card-status
OpenPGP导出用于SSH用途(方案一)
在继续行文之前,也要提一下,本节内容具有一定争议。主要体现在以下两点:
- OpenPGP密钥是否可以和SSH所用的密钥进行互换?
- 操作是否具有一定的安全风险?
对于上述第一个问题,SSH认证一般都使用的是RSA密钥,但从目前的OPENSSL以及OPENSSH支持范围来看,无论是ECC还是RSA算法,都是支持的。此外和X.509体系不同的是,PGP和SSH密钥「这里使用了非标准的表述方式」都是解决主观或客观无背书下的相互信任。
第二个问题,有人认为,PGP体系的公钥公开会影响安全。但拥有公钥并不能推导出私钥。
但两种情况下我认为会在某些角度影响安全性。
- 主私钥泄密情况下,公钥吊销是否能及时同步到目标机上?答案是否,目前SSH还不是这个机制
- 在多处使用同一个私钥是否会导致问题?
我个人硬件密钥想要解决的是场景是,使用非可信设备进入可信区进行操作的问题,所以只要控制好私钥副本的传播即可(硬件密钥本来就无法拷出私钥)。
使用openpgp2ssh工具,位于monkeysphere包内,Linux和MacOS均有提供。
key=FFFFFFFF # 指纹
# 导出gpg格式私钥
gpg --export-secret-key "$key" > id_rsa.bak
# 记得移除私钥密码
# * gpg --edit-key "$key"
# * Issue passwd and remove the password
# * Quit, and save changes
# 导出
gpg --export "$key" | openpgp2ssh "$key" > ~/.ssh/id_rsa.pub
gpg --export-secret-key "$key" | openpgp2ssh "$key" > ~/.ssh/id_rsa
# Then, we change the password for the SSH secret key
ssh-keygen -f ~/.ssh/id_rsa -p
# Now reimport the original key (deletion is required or for some reason it fails to reimport as encrypted)
gpg --delete-secret-key "$key"
gpg --import < id_rsa.bak
rm id_rsa.bak
或者下述更容易理解的方式
请注意,openpgp2ssh工具目前无法处理加密的私钥,会提示:We cannot handle encrypted secret keys. Skipping!
gpg --edit-key FFFFFFFF # 我们需要先移除密钥上的密码
gpg --export FFFFFFFF | openpgp2ssh FFFFFFFF > id_rsa.pub # generating public key
gpg --export-secret-key FFFFFFFF | openpgp2ssh FFFFFFFF > id_rsa # generating private key
gpg --delete-secret-key FFFFFFFF # cleanup
通过GPG直接导出
gpg --export-ssh-key FFFFFFFF
使用OpenPGP私钥创建X.509
本节内容使用了Yubikey的PIV功能,存储先前所述的子密钥,用于部分验证场景。
由于在Win平台上,部分软件并不能调用OpenPGP Card,只能调用PIV区域的密钥,所以gpg-agent
就略显手足无措。
创建X.509请求
openssl req -new -key auth_rsa.key -out auth_crt.csr
期间会需要输入一些证书信息,这些本质上是给CA用于签发的,我们按需填写即可。
自行签发
openssl x509 -req -days 3650 -in auth_crt.csr -signkey auth_rsa.key -out auth_rsa.crt
在SSH中使用
Putty SSH 等原生软件
公钥导出在先前内容中都有提到,不再阐述。
$ cat ~/.gnupg/gpg-agent.conf
default-cache-ttl 1800
enable-ssh-support
enable-putty-support
use-standard-socket
write-env-file
killall gpg-agent # kill as you need
gpg-agent --daemon --enable-ssh-support
export SSH_AUTH_SOCK="`gpgconf --list-dirs agent-ssh-socket`"
需要将输出的结果放入环境变量,使用起来如下图,就很Nice
我们可以很轻而易举的在SSH、Git等场景下使用。
在xShell中使用
需要用到PIV区,以及WinCryptSSHAgent软件
(https://github.com/buptczq/WinCryptSSHAgent/)
XShell官方的方法是使用PCKS#11验证,要装插件来实现,本节就不再阐释了。
请注意导入的密钥位数,PIV区支持的密钥位数和OpenPGP不一致,一般最大只支持2048,子密钥都是3072的就只能干瞪眼了。
WinCryptSSHAgent需要在XShell打开前启动
# 导入证书文件 9a 槽位是用于认证的
yubico-piv-tool -s 9a -a import-certificate -i mykey.crt
# 导入密钥文件,触摸策略是每次都touch,可选never、cached
yubico-piv-tool -s 9a -a import-key --touch-policy=always -i private.key
上述操作的主要目的是向槽位分别写入公钥与私钥。若写入后提示无法使用该智能卡,可能是在写入时有问题,可以尝试清空9a槽后重新执行导入操作。
新电脑使用
sudo apt install gpg
sudo apt install scdaemon
gpg --card-status
# ~/.zshrc
export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/gnupg/S.gpg-agent.ssh"
# ~/.gnupg/gpg-agent.conf
default-cache-ttl 1800
enable-ssh-support
enable-putty-support
use-standard-socket
Git 签名配置
git config --global user.signingkey XXXXXXXX
git config --global commit.gpgsign true
后记
本文主要记录了Yubikey这类硬件密钥配合SSH场景认证的使用方式,事实上Yubikey的部分功能并不是智能卡和OpenPGP Card的完整实现,部分gpg/card
内的功能并不能百分百匹配上,作为认证场景使用,对我来说可能是目前Yubikey最主要的一个用处了。
本文标题:Yubikey硬件密钥 与 SSH认证
本文连接:https://blog.dextercai.com/archives/173.html
除另行说明,本站文字内容采用创作共用版权 CC-BY-NC-ND 4.0 许可协议,版权归本人所有。
除另行说明,本站图片内容版权归本人所有,任何形式的使用需提前联系。