Canokey 应用之 GPG
引言
最近新购入了新版的 Canokey Canary(之前是 Pigeon),抢了个首发版本,也算是对国产的小小支持。
本来早早就想再买个 Canokey 作为双备份,但听闻有 Type-C 版本的要上架,且对 NFC 有改善,因此蹲到了现在。
恰好,既然是作为备份,那么就要重新导入一遍私钥,也借此机会简单记录一下,针对 GPG 签名、认证的一些用法。
尤其是,如何把一个私钥导入到多个 Canokey 中,操作起来有些细节还是挺费事的。
如果对 Bitlocker PIV 的用法感兴趣,可以看我写的前篇。
配置硬件
查看卡状态
首先查看硬件,确保能检测到 Canokey:
1 | gpg --card-status |
输出如下,代表 Canokey 正常连接:
卡片初始化
接下来,对 canokey 进行编辑,输入:
1 | gpg --card-edit |
进入到交互模式,随后,输入 admin
以允许执行管理命令,如下图:
密码修改
新卡到手第一步,修改 PIN 和 PUK 码。
输入 passwd
,得到一个菜单:
分别选择 1、3,修改常用的两个 Pin 码——“用户 PIN” 和 “管理员 PIN”
对于 4,是用来清除卡数据的密码,使用默认即可,我们不用去动它。
完成后按下 Q
退出。
信息设定(可选)
硬件上的 GPG 可以设置持卡人等信息。
如图,分别输入
name
,url
,login
,lang
,salutation
,可以对姓名、公钥网址、登录用户名、语言偏好、称呼进行配置。
在修改信息的过程中,可能会要求输入
Admin PIN
,即上一步中修改的第3项,注意和用户 PIN
区分开。
完成后,再次输入
list
,可以看到此次很多信息都被更新了:
用户交互配置(可选)
输入 uif 1 on
和
uif 3 on
,为“签名”和“认证”操作启用“触摸确认”的功能,防止后台应用偷偷调用。
密钥迁移
注意事项
此步骤会将子密钥移动到 Canokey,移动之后子密钥会在电脑的 GPG 里永久消失。
因此,如果你想让子密钥导入到多个 key,或者不想让其永久消失,就一定要将其导出到电脑里进行备份。
一些建议
通常,我们会使用子密钥进行加解密 / 签名操作,而不是主密钥。这是因为主密钥可以随时吊销子密钥,并生成新的子密钥。仅使用子密钥,可以最大程度确保安全。
对于主密钥,我们应该将其保存至一个冷备份容器中(比如开了 Bitlocker 的磁盘/虚拟磁盘)。
有关密钥生成,导入/导出的各种操作可以参考我之前的这篇文章。
开始操作
开始前,请确认你已经完成了密钥的备份操作(注意事项中的内容)。
下面正式开始迁移操作,首先进入密钥编辑模式:
1 | gpg --edit-key 52838AC66F9C7F0E 【替换为你自己的】 |
进入编辑模式的情景如下图,这里稍微有点不同,我的界面上有
card-no: F1D0 013135E1
,因为之前我将它导入过另一个
canokey,且将私钥从电脑上删除了:
因此,需要有一些额外的步骤(如果无此情况请跳过),否则 GPG 会一直认为私钥在先前的卡中,导致:
- 无法使用
keytocard
转移到新的卡(提示KEYTOCARD failed: Unusable secret key
),因为密钥环中实际上不存在私钥。 - 也无法将私钥删除(
--delete-secret-keys
提示delete key failed: Not found
)。 - 无法从磁盘上重新导入私钥(提示 unchanged/not changed),使用
--edit-key
查看发现仍然绑定原先的卡(无法解除绑定)。 - 使用
--delete-keys
删除后重新导入,也并不能解绑。
要解决问题,核心思路为:
- 告诉 GPG Agent :“这个私钥和原先的卡不绑定”。
- 重新把私钥从硬盘导入进密钥环(独立存在)。
- 使用编辑功能,把私钥转移到新的硬件中去。
实际上,笔者认为 GPG 应该提供切换智能卡的命令选项,尤其是对于硬件密钥意外损坏,需要更换的情况,能省事不少。但就目前看来,这似乎还没有实现。
总之,经过多方查找,笔者终于得到了解决方案,有两种方法:
该方法仅需要:你在磁盘上拥有子密钥的私钥。
首先执行:
1 | gpg --with-keygrip -k 52838AC66F9C7F0E |
得到下图:
随后,根据这些
keygrip
,找到并删除这个路径下全部对应的文件,以清除缓存的绑定关系:
1 | ~/.gnupg/private-keys-v1.d/[KEYGRIP].key |
删除完文件后,需要重启一下 agent:
1 | gpgconf --kill gpg-agent |
随后,再从磁盘上重新导入子密钥的私钥:
1 | gpg --allow-secret-key-import --import ~/xxx_sec.key |
此时的私钥就变得普普通通,不再和硬件相关联。
该方法成功的前提:你在磁盘上拥有完整的私钥链。
完整私钥链是指,你曾经对主密钥进行过导出,且导出时没有在密钥 ID
后面加上 !
。
例如,使用如下命令所导出的私钥,在接下来的操作步骤中是可用的。
1 | gpg -a -o /path/to/gpg_all_sec.key --export-secret-keys 52838AC66F9C7F0E |
操作步骤如下:
进入到 key 编辑模式。
分别执行
key 1
,key 2
,key 3
,选中三个子密钥。执行
delkey
将它们删除。输入
save
保存。重新导入私钥,使用命令:
1
gpg --allow-secret-key-import --import /path/to/gpg_all_sec.key
此时,所有私钥被重新导入,且清除了绑定关系。
===== 手动分割 =====
处理完额外的步骤,接下来就比较简单了,主要就是“选定密钥,并将其迁移”,可以在编辑模式下使用
key N
这样的命令对密钥选中。
如前文所说,我们只需将子密钥导入到 Canokey
即可。因此,我们首先选中第一个子密钥,即输入
key 1
(主密钥编号是
0)。这里我们看到,框中的部分多了一个小星号,表示被选中:
选中完成后,输入 keytocard
,即可永久将私钥移动到 Canokey
中,再次提醒,如有需要请做好备份!
执行时,会让你选取将密钥存储在哪个槽位,我们按 GPG 密钥的实际用途选就可以了(加密、签名和认证),如下图:
接下来,重复执行上面的步骤:
- 首先再次输入
key 1
,取消选中。 - 输入
key 2
选中下一个私钥。(每次只选中一个) - 再次输入
keytocard
,进行迁移。
最后,在迁移完所有私钥后,可以输入 save
保存对密钥的修改。(Tips:如果你要一次性导入密钥到多个
Canokey,此时可以不 save,直接退出,这样私钥不会被删除。导完最后一个
canokey 以后再执行保存,以建立私钥到智能卡的映射)
后续检查
完成密钥保存后,使用 gpg --card-status
读取 Canokey
确认密钥情况如下图:
可见,私钥已经正确导入到了智能卡中,接下来可以把主私钥删除(做好冷备份的前提下),提高安全性:
1 | gpg --delete-secret-keys 52838AC66F9C7F0E |
删除后,再次运行命令,确认密钥状态:
1 | gpg --list-key 52838AC66F9C7F0E |
如图,主密钥从sec
变为pub
,代表仅存储了主密钥的公钥;而子密钥从ssb
变成了sub
,也代表了子密钥只有公钥。
查看私钥,发现其带有 #
标记,表示私钥迁移到了硬件中:
至此,密钥迁移完成,可以愉快使用了。
参考
以下文章可能也会对你有所帮助:
- 生成GPG密钥并导入到Yubikey
- GPG 物理密钥从安装到日常使用
- gpg2: How to get rid of "Please insert card with serial number", getting the same key from a different card / Yubikey