如何在 gnupg 中使用多个智能卡?

信息安全 gnupg
2021-08-13 17:43:19

我有两张智能卡:SCard1 和 SCard2。相同的密钥存储在它们两者上。

我使用最多的功能之一是 SSH 身份验证来访问多个服务器。但是在同一台计算机上使用了第一张智能卡(不是同时)之后,我无法使用第二张。

显示以下消息:

请取出当前卡并插入带有序列号的卡
[包含 SCard1 识别号的长 ID]

重现问题的步骤

让我们准备一个干净的环境。

$ export GNUPGHOME=/tmp/gnupg
$ mkdir /tmp/gnupg && chmod go-rwx /tmp/gnupg
$ curl [public key URL] | gpg --import
gpg: keybox '/tmp/gnupg/pubring.kbx' created
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  6194  100  6194    0     0   2408      0  0:00:02  0:00:02 --:--:--  2408
gpg: /tmp/gnupg/trustdb.gpg: trustdb created
gpg: key 3D5DDE26A0B55831: public key imported
gpg: Total number processed: 1
gpg:               imported: 1

插入 SCard1

然后我插入我的 SCard 1。

$ ls /tmp/gnupg/private-keys-v1.d/
$ gpg --card-status
Reader ...........: Yubico Yubikey 4 OTP U2F CCID 00 00
Application ID ...: [SCard1 identification number]
blahblah
ssb>  rsa2048/467299D324A21B24  created: 2017-01-10  expires: 2018-01-10
                                card-no: [SCard1 identification number]
ssb>  rsa2048/11771A79F4B85B41  created: 2017-01-10  expires: 2018-01-10
                                card-no: [SCard1 identification number]
ssb>  rsa2048/F31D41149A84B062  created: 2017-01-10  expires: 2018-01-10
                                card-no: [SCard1 identification number]

最后一个密钥用于身份验证。

$ ls /tmp/gnupg/private-keys-v1.d/
somehash1.key somehash2.key somehash.3.key

我猜这些哈希来自我存储在智能卡上的密钥。

$ gpg -K
/tmp/gnupg/pubring.kbx
sec#  rsa4096 2017-01-10 [SC] [expires: 2019-01-10]
      [primary key ]
ssb>  rsa2048 2017-01-10 [S] [expires: 2018-01-10]
ssb>  rsa2048 2017-01-10 [E] [expires: 2018-01-10]
ssb>  rsa2048 2017-01-10 [A] [expires: 2018-01-10]
$ ssh example.com hostname
*** asked to enter pin
example.com

一切都按预期工作。

插入 SCard2

让我们拔下 SCard1 并插入 SCard2。

$ ssh example.com hostname

并显示以下消息:

请取出当前卡并插入带有序列号的卡
[包含 SCard1 识别号的长 ID]

请注意,当我先插入 SCard2,然后插入 SCard1 时,我得到了相同的结果。

解决方案的一部分

在 Internet 上进行的一些搜索使我了解到“密钥存根”存储在~/.gnupg/private-keys-v1.d/. 删除整个目录解决了这个问题。也许只是删除其中一个.key就可以了。

问题

是否可以在不删除任何文件的情况下同时使用这两个密钥?

4个回答

gpg --with-keygrip -K您将获得钥匙的钥匙扣标识符这些 id 对应于 private-keys 目录中的密钥桩。

如果您有 3 个子密钥(加密、签名和身份验证),您将在 GNUPGHOME/private-keys-v1.d(Linux 上的 ~/.gnupg/private-keys-v1.d)中拥有三个文件。

当使用具有相同密钥的不同智能卡时,标识符将相同,但文件的二进制内容会有所不同。

删除是一种选择,但您也可能无意中删除了其他私钥存根。

另一种选择是进行备份并在每次切换卡时将其切换出去(<id>.key.card1并将<id>.key.card2被复制到当前/活动<id>.key文件中)。

无缝执行此操作的最佳选择是使用 @Jens Erat 建议的 udev。添加智能卡后,备份当前的密钥桩 ( <id>.key.<cardid>) 并重新创建(或<id>.key在现有备份的情况下复制回)您想要的密钥桩。娱乐就像跑步一样容易gpg --card-status

如何使用 udev 进行设置:

  • udevadm monitor --environment'
  • 现在添加智能卡并观察输出,以便建立匹配
  • 构建匹配规则(因此匹配一次)并在添加时运行脚本。
  • 引用 udev 规则中的脚本以使魔术发生(分离脚本)

下一个示例适用于 yubikey 5 in /etc/udev/rules.d/99-gpg-smartcard.rules

    # /etc/udev/rules.d/99-gpg-smartcard.rules
    # helpful commands:
    # udevadm monitor --environment --udev --kernel
    # udevadm info -a -n <device-path>
    # udevadm test $(udevadm info -q path -n device_name) 2>&1
    # udevadm control --log-priority=debug
    # udevadm control --reload-rules && udevadm trigger
    SUBSYSTEM=="usb", ACTION=="add", \
    ATTRS{idProduct}=="0407", ATTRS{idVendor}=="1050" ,  \
    ATTRS{manufacturer}=="Yubico", ATTRS{product}=="YubiKey OTP+FIDO+CCID", \                                                    
    SYMLINK+="yubikey",  \
    RUN+="/usr/bin/at now -f /home/USER/bin/gpg-smartcard.txt"

        # Since nested quotes are not possible in RUN (outer double quotes
        # and inner single quotes) and cannot be escaped, we need to make sure
        # there are no nested quotes.
        # Furthermore, we need to detach our script from udevd for it to be able
        # to use the device (smartcard), since the RUN command
        # is blocking the daemon and the device is not yet ready, therefore we
        # are using the 'at' command to completely detach the job from udevd.
        # Since we need to use 'su' with the correct USER in the command
        # and multiple arguments (/bin/bash with the scriptname)
        # we cannot use the full command here when using 'echo' to 
        # pipe it to 'at'. 
        # So we are stuck reading the command from a textfile when using 'at'.
        # In the textfile is the following command:
        # su -l USER -c "/bin/bash /home/USER/bin/gpg-smartcard.sh"

在 /home/USER/gpg-smartcard.txt

su -l USER -c "/bin/bash /home/USER/bin/gpg-smartcard.sh"

在 /home/USER/bin/gpg-smartcard.sh 中:

keys=( \
  <ENCRYPTION>.key \
  <SIGNING>.key
  <AUTHENTICATION>.key \
  )
original=~/.gnupg/private-keys-v1.d
target=${original}/backup
mkdir -p ${target}
now=$(date +'%Y-%m-%d-%M:%S')
for i in "${keys[@]}"; do
  mv ${original}/$i ${target}/$i.bak.${now}
done;
sleep 1
# gpg --card-status will also work
# use 'gpg-connect' and then 'help' to find out the commands
gpg-connect-agent "scd serialno" "learn --force" /bye >> $log 2>&1

我已经写了一个HOWTO 在这里设置你的 yubikey

资料来源:

新版本应该可以解决这些问题。

2.3.0 版包括,除其他外,

  • scd:改进对多个读卡器和令牌的支持。

https://lists.gnupg.org/pipermail/gnupg-announce/2021q2/000458.html

GnuPG 将包含密钥的卡的序列号存储在密钥的存根中,每个密钥只能设置一张卡

对于同一个密钥,您只有一个密钥存根——因此删除“其中一个”将无济于事。您唯一可能幸运的事情是使用 UDEV 获得插入智能卡的通知,并切换或重写密钥存根以指向提供的智能卡。

从问题中不清楚您使用智能卡启用的 yubikeys 来做什么,除了 SSH。但我建议一起跳过 gnupg 并直接在 OpenSSH 中使用 PKCS11 支持。这将使用 pkcs11 库并直接与卡对话。

如果你做其他需要 gnupg 的事情,你可以放心地忽略这个答案。