pub fn init_pins() -> (Pkcs11, Slot) {
let pkcs11 = get_pkcs11();
// initialize the library
pkcs11.initialize(CInitializeArgs::OsThreads).unwrap();
// find a slot, get the first one
let slot = pkcs11.get_slots_with_token().unwrap().remove(0);
let so_pin = AuthPin::new(SO_PIN.into());
pkcs11.init_token(slot, &so_pin, "Test Token").unwrap();
{
// open a session
let session = pkcs11.open_rw_session(slot).unwrap();
// log in the session
session.login(UserType::So, Some(&so_pin)).unwrap();
session.init_pin(&AuthPin::new(USER_PIN.into())).unwrap();
}
(pkcs11, slot)
}
理解
PKCS11 定义了独立于HSM、HSE等安全模块平台等接口,对于遵循PKCS11标准的安全硬件,都可以使用PKCS11的接口管理和使用这些安全硬件。PKCS11中提出了Slot和Token的概念,这两个概念在使用中非常难以理解,如果不理解透彻,甚至在使用中会经常犯错。我也经常困惑于这两个概念,对于一些开源代码,也很好奇为什么他们都默认使用Slot 0,而不是用其他slot,为什么指定了Slot后,还需要初始化token。今天,我就按自己的理解,尝试将slot和token的关系说明白。 我们可以理解为PKCS11类似于规定了一排标准的HSM插槽,每个插槽也就是Slot都可以插入一个HSM/HSE等安全硬件模块(只要这些安全硬件模块等插口严格按照PKCS11的标准制造)。这样,我们在使用时,只要在插入安全硬件到某个slot后,就可以通过这个slot使用安全硬件模块。
图中的外框可以理解为PKCS11,PKCS11规定了每一个插槽的大小(操作API),只要HSM/HSE等制造商按照这个标准制造安全硬件模块,那么就可以插上PKCS11的框进行使用。而插入slot的安全硬件被PKCS11成为token,也就是令牌,不管是HSM还是HSE,都统一称为token。
使用
在pkcs11的示例代码如:cryptoki中,默认使用slot 0生成和存储密钥:
这是因为slot的使用有一个比较常见的原则(或者叫惯例?),如果系统中只有一个HSM/或者说token,那么通常使用slot 0插入这个token;如果存在多个token,那么可以根据需求自由选择使用的slot,并添加token标签进行管理。
疑问
但是,用于管理HSM的PIN码应该如何保存呢? HSM中存在两种管理者:安全管理者(Security Officer)和用户管理者(User Officer),他们分别都有一个PIN码。由于PIN码控制着对HSM的访问,因此需要妥善管理存放这两个PIN码。但是,对于单一HSM的环境,比如汽车的控制器上,如何保存PIN码我至今仍没有想到比较合理的方法。