#openpgp-card #pin #user #storage #state #devices

bin+lib openpgp-card-state

针对 openpgp-card 设备状态的实验性存储机制

6 个版本

0.2.1 2024 年 4 月 29 日
0.2.0 2024 年 4 月 23 日
0.1.0 2024 年 3 月 24 日
0.0.3 2024 年 3 月 11 日
0.0.2 2024 年 2 月 28 日

#5 in #openpgp-card

Download history 95/week @ 2024-05-03 6/week @ 2024-05-10 61/week @ 2024-05-17 148/week @ 2024-05-24 253/week @ 2024-05-31 67/week @ 2024-06-07 120/week @ 2024-06-14 47/week @ 2024-06-21 56/week @ 2024-06-28 8/week @ 2024-07-05 22/week @ 2024-07-12 18/week @ 2024-07-19 11/week @ 2024-07-26 19/week @ 2024-08-02 57/week @ 2024-08-09 23/week @ 2024-08-16

112 次每月下载
用于 8 个 crate(3 个直接使用)

MIT/Apache 许可协议

30KB
302

用于使用 OpenPGP 卡的应用程序的状态共享

此 crate 通过应用程序使用 OpenPGP 卡设备。

特别是,它允许应用程序在不要求用户输入 PIN 的情况下对硬件设备进行操作。相反,应用程序通过此库获取用户 PIN。

graph TB
    Application --> CARD["OpenPGP card device <br/> (performs cryptographic operations <br/> after User PIN presentation)"]
    Application --> STATE["openpgp-card-state library <br/> (config and PIN storage backend access)"]
    STATE --> PINS["PIN storage backend <br/> (makes User PINs available to applications)"]

此 crate 使用两种机制的组合

  • 常规配置文件:存储非敏感的卡元数据(例如,卡的可选昵称),并指定默认以及按卡使用的 PIN 存储后端。
  • PIN 存储后端:代表应用程序存储 OpenPGP 卡设备的(敏感)用户 PIN。存在不同类型的 PIN 存储后端(见下文)。用户可以根据其用例选择合适的后端。

使用和架构

此 crate 由应用程序用作库。该库简化了对配置文件和 PIN 存储后端的读写访问。一般来说,openpgp-card-state 库不需要长时间运行的过程(但是,某些 PIN 存储后端可能由长时间运行的过程组成)。

从用户的角度来看,openpgp-card-state 通常是应用程序的实现细节。然而,了解机制的工作原理可能会有所帮助,以形成一个良好的心理模型。

openpgp-card-state 中,卡片使用 "ident" 格式进行寻址,无论是访问配置文件中的元数据,还是存储和检索用户 PIN。

配置文件

openpgp-card-state 的配置文件存储在特定于平台的默认位置。在 Linux 系统上,通常是 $HOME/.config/openpgp-card-state/config.toml(配置文件由 directories crate 处理,它使用平台特定的标准位置,遵循 Linux 系统上的 XDG 规范)。

卡片的一个典型配置条目如下所示

[[cards]]
ident = "0000:01234567"
pin_storage = "Keyring"
nickname = "my purple card"

此配置条目指定具有 ident 0000:01234567 的卡片使用 "Keyring" PIN 存储后端来存储用户 PIN。此外,为该卡片定义了昵称 my purple card

背景、设计权衡和威胁建模

历史上,OpenPGP 卡设备通常通过 GnuPG 使用。

这个软件包作为非GnuPG应用程序使用OpenPGP卡的基础设施。

然而,为了理解设计空间,我们首先将查看OpenPGP卡使用的一些细节。特别是加密操作的授权。然后我们将概述GnuPG如何与OpenPGP卡交互。最后,我们讨论该软件包的概念和相关威胁建模。

OpenPGP卡和用户PIN

讨论的一个特别有趣的话题是“用户PIN”的处理。为了在卡上授权私钥操作(签名或解密),用户PIN必须提交给卡。

OpenPGP卡规范是OpenPGP卡设备上PIN处理的权威参考。规范文档将用户PIN称为“PW1”,并区分了使用PW1的两种模式:模式“81”用于签名操作,模式“82”用于所有其他用户操作(包括解密和身份验证)。

通常,用户PIN只需要提交给卡一次,然后在整个连接期间有效。作为例外,可以将卡配置为用户PIN提交仅对单个签名操作有效,要求用户每次签名操作都输入用户PIN。我们将这个特殊情况放在一边,以下讨论。

通过主机计算机输入PIN与通过带有PIN键盘的卡读卡器输入PIN

从历史上看,OpenPGP卡设备通常是实际物理智能卡,它们在单独的读卡器设备中使用。

一些读卡器具有物理PIN键盘,用于输入(数字)PIN。这种设置可以保护PIN不受主机计算机的侵害:只有读卡器本身可以看到卡主人在读卡器上输入的PIN。在这种情况下,主机计算机不知道PIN。

另一方面,现代OpenPGP卡设备几乎完全转向了不同的硬件:将作为带有插入OpenPGP卡的智能卡读卡器呈现给主机计算机的USB令牌(例如,在开源硬件设计上运行的免费软件Gnuk,或Nitrokey或Yubico的各种商业设备)。使用此类设备时,无法以主机计算机无法访问的方式向“卡”提交用户PIN。

GnuPG的架构

GnuPG是一个历史悠久的软件套件。其根源可以追溯到1997年。它开创了为终端用户使用智能卡进行私钥操作的做法。

其架构由多个进程组成,这些进程通过“assuan”(一个GnuPG特定的IPC协议)相连。以下图显示了GnuPG的多进程架构以及一些应用程序软件以及它如何访问GnuPG

graph TB
    GPGME["GPGME <br/> (GnuPG access library)"] --> GPG
    GPG["GnuPG <br/> (CLI tool)"] --> GA["gpg-agent <br/> (long running: private key operations)"]
    GA --> SCD["scdaemon <br/> (long running: smart card access)"]
    GA --> pinentry["pinentry <br/> (prompts users for PINs and other secrets)"]

    GIT[Git] -.-> GPG
    SSH["SSH <br/> (can use OpenPGP cards via gpg-agent)"] -.-> GA
    TB[Thunderbird] -.-> GPGME

classDef application fill:#404040,stroke-dasharray: 5 5;
class TB,GIT,SSH application;

scdaemon是处理对OpenPGP卡设备访问的GnuPG子系统。它被设计成与任何OpenPGP卡保持永久和独占的连接[^pcscshared]。

[^pcscshared]:scdaemon的较新版本提供对“共享”连接到OpenPGP卡的可选支持。

这种设计具有有用的特性,尤其是在与带有物理PIN键盘的物理智能卡一起使用时:如果不保持与这些设备的持续连接,用户就需要在读取器的物理PIN键盘上反复重新输入PIN,可能每次操作都要输入一次,这在许多情况下都是不可行的。

在这种情况下,与卡保持永久连接是获得良好用户体验的必要条件。

然而,这种设计的缺点是,除了GnuPG的scdaemon之外,没有其他应用程序可以合理地使用这些卡,因为GnuPG保持它们开启并假定独占访问(用户已经采取了措施来处理这一影响的后果。有些人编写了shell脚本来战略性地kill scdaemon进程作为解决方案,以便能够从其他应用程序访问他们的卡)。

使用openpgp-card-state存储用户PIN

相比之下,GnuPG的方法(如上所述)进行了不同的权衡,并追求不同的目标。

我们的主要设计目标是

  • 使多个应用程序能够直接使用OpenPGP卡,而无需通过某个长时间运行的过程进行中介。
  • 提供流畅的用户体验。
  • 简单性。

如今,大多数用户不使用外部PIN键盘。这意味着没有充分的理由保持与卡的永久连接。请注意,现代OpenPGP卡的使用本身就要求向主机计算机披露用户PIN。因此,主机计算机可以始终将用户PIN发送到卡上以授权操作。

有关威胁模型讨论的更多内容,请参阅以下内容。

用户不需要手动输入他们的用户PIN以执行每个操作,因此用户PIN需要以某种方式在主机计算机上可用,以便为应用程序使用。作为用户PIN的保管者是此openpgp-card-state仓库的核心目标。

威胁模型

如上所述,此仓库主要处理主机计算机可以访问用户PIN(至少间歇性)的设置。

这意味着用户PIN不需要对主机计算机具有巨大保护的威胁模型。处理用户PIN的两种可能的方法类别是

  • 在主机计算机上持久化用户PIN。
  • 在长时间运行的过程中保持用户PIN可用(对于某些可能有限的持续时间),但不在磁盘上持久化。

持久化用户PIN

此仓库允许用户选择处理用户PIN的不同方法。我们将其称为“PIN存储后端”。

我们建议,对于大多数用户来说,通过特定于平台的通用秘密存储机制持久化用户PIN是合理且实用的。我们的默认后端使用“Keyring”用户PIN存储后端(基于https://crates.io/crates/keyring),该后端实现了这种方法。它在Linux上由“secret-service”支持,在Mac上由“keychain”支持,在Windows上由“credential manager”支持。

这种方法并不适用于所有情况。然而,我们认为它在大多数情况下是合适的。用户PIN主要在物理OpenPGP卡设备被盗的情况下提供保护,而没有同时丢失或损坏主机计算机。

另一方面,当针对远程攻击者进行保护时,“触摸确认”对于加密操作是最有用的防御线,使用现代OpenPGP卡设备。在主机计算机远程受侵害的情况下,用户PIN最多只是一种薄弱的防御。

临时用户PIN缓存

对于无法在磁盘上持久化用户PIN且不想为每个操作输入用户PIN的用户,需要某种长时间运行的过程。在我们的架构中,这将是一个作为临时用户PIN存储后端的长运行进程,由用户的各个应用程序共享。

openpgp-card-storage的临时PIN存储后端尚未准备好,但它在我们的路线图上。

PIN存储后端

此仓库的主要目的之一是存储和获取OpenPGP卡设备的用户PIN,特别是为了让用户PIN可用于本地应用程序。

不同的用户可能有不同的用户PIN存储需求或优先级。因此,此仓库支持不同的PIN存储机制,供用户选择。

"Keyring":特定于平台的受保护持久存储

默认情况下,此crate使用“Keyring”PIN存储后端。它基于https://crates.io/crates/keyring crate,并将用户PIN持久保存在平台特定的受保护存储中。

  • Linux:secret-service(这需要一个像GNOME Keyring这样的服务来提供secret-service功能)。
  • macOS:使用“keychain”子系统。
  • Windows:使用“凭据管理器”子系统。

“直接”:在配置文件中存储明文。

某些用户可能不需要由安全意识子系统来处理他们的用户PIN,并且可能更喜欢避免使用此类子系统带来的额外复杂性。在这种情况下,用户PIN可以另存为明文直接存储在配置文件中。

这种模式在不需要保护用户PIN的环境中特别方便,例如CI测试。

将提供更多PIN存储后端

通常请求的功能是一个短暂的PIN存储后端,该后端仅在RAM中保留用户PIN,而不会将它们持久保存在磁盘上。一个额外的短暂PIN存储后端即将推出。

默认用户PIN存储后端

配置文件可以显式定义一个默认PIN存储后端。如果存在此设置,新卡的User PIN将使用指定的default_pin_storage后端存储。

default_pin_storage = "Direct"

[[cards]]
ident = "0000:01234568"
nickname = "my yellow card"

[cards.pin_storage]
Direct = "123456"

应用开发者使用此库

此库主要面向想要实现OpenPGP卡支持的软件开发者。有关如何使用此库的讨论,请参阅此处

注意:请注意,此库较新,在稳定之前可能会经历一些迭代。

CLI工具

有关附带CLI工具的描述,该工具主要用于调试目的,请参阅此处

资金

此项目部分资金来自NGI Assure,该基金由NLnet建立,并获得欧洲委员会下一代互联网计划的财政支持。

NGI Assure Logo

依赖关系

~2–12MB
~88K SLoC