3.9 硬件特征对象:密码设备独有的“特异功能“
硬件特征对象概述
PKCS#11规范第4.3节定义了一种特殊对象类型——硬件特征对象(CKO_HW_FEATURE),代表密码设备(Token)的硬件特性。
硬件特征对象分类:
CKO_HW_FEATURE(硬件特征对象类)
├── CKH_CLOCK 时钟对象(实时时钟)
├── CKH_MONOTONIC_COUNTER 单调计数器对象
└── CKH_USER_INTERFACE 用户界面对象
与其他对象的区别:
| 特性 | 普通对象 | 硬件特征对象 |
|---|---|---|
| 创建方式 | C_CreateObject | 由Token自动创建 |
| 存储位置 | Token存储区 | 直接代表硬件功能 |
| 数量 | 可创建多个 | 每类通常只有1个 |
| 查找行为 | 默认可见 | 需显式指定CKA_CLASS |
查找约束:使用C_FindObjectsInit查找时,硬件特征对象不会被返回,除非模板中显式指定:
CK_OBJECT_CLASS hwClass = CKO_HW_FEATURE;
CK_ATTRIBUTE template[] = {
{CKA_CLASS, &hwClass, sizeof(hwClass)}
};
rv = C_FindObjectsInit(hSession, template, 1);
// 只有指定CKO_HW_FEATURE才会返回硬件特征对象
设计意图:保护旧版本应用程序不会“意外“发现不理解的新对象类型。
时钟对象(Clock Object)
时钟对象(CKH_CLOCK)代表Token上的实时时钟。
时钟对象架构:
┌─────────────────────────────────┐
│ Token(HSM硬件) │
│ │
│ ┌───────────────────────────┐ │
│ │ 实时时钟(RTC) │ │
│ │ - 硬件时钟芯片 │ │
│ │ - 电池供电(断电保持) │ │
│ │ - 高精度时间源 │ │
│ └───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────┐ │
│ │ Clock对象 │ │
│ │ CKA_HW_FEATURE_TYPE │ │
│ │ = CKH_CLOCK │ │
│ │ CKA_VALUE = 时间字符串 │ │
│ └───────────────────────────┘ │
│ │ │
│ ▼ │
│ CK_TOKEN_INFO.utcTime │
│ (同一时钟源) │
└─────────────────────────────────┘
属性:
| 属性 | 数据类型 | 含义 |
|---|---|---|
| CKA_HW_FEATURE_TYPE | CK_HW_FEATURE_TYPE | CKH_CLOCK |
| CKA_VALUE | CK_CHAR[16] | 当前时间字符串 |
时间格式:YYYYMMDDhhmmssxx
格式分解:
YYYY - 年份(4字符)
MM - 月份(2字符,01-12)
DD - 日期(2字符,01-31)
hh - 小时(2字符,00-23)
mm - 分钟(2字符,00-59)
ss - 秒(2字符,00-59)
xx - 保留字段(2字符,表示时区偏移,如'00'=UTC、'+08'=东八区)
示例:2023121514305300
→ 2023年12月15日 14:30:53
修改时间:
CK_CHAR newTime[16] = "2024010100000000";
CK_ATTRIBUTE setTime = {CKA_VALUE, newTime, 16};
/* 设置时间需要登录 */
rv = C_SetAttributeValue(hSession, hClock, &setTime, 1);
if (rv == CKR_USER_NOT_LOGGED_IN) {
// 可能需要SO权限
rv = C_Login(hSession, CKU_SO, soPin, soPinLen);
rv = C_SetAttributeValue(hSession, hClock, &setTime, 1);
}
安全约束:
- 设置时间需要登录Session
- 某些Token要求SO(Security Officer)权限
- 返回CKR_USER_NOT_LOGGED_IN表示权限不足
单调计数器对象(Monotonic Counter)
单调计数器(CKH_MONOTONIC_COUNTER)代表硬件计数器,每次读取值都会增加。
单调计数器特性:
读取前:counter_value = 12345
读取后:counter_value = 12346(或更大)
关键特性:
- 保证每次读取都增加
- 增加量不一定为1(取决于硬件)
- 不能设置、不能回退、不能重置(除非C_InitToken)
属性:
| 属性 | 数据类型 | 含义 |
|---|---|---|
| CKA_HW_FEATURE_TYPE | CK_HW_FEATURE_TYPE | CKH_MONOTONIC_COUNTER |
| CKA_RESET_ON_INIT | CK_BBOOL | C_InitToken时是否重置 |
| CKA_HAS_RESET | CK_BBOOL | 是否曾被重置 |
| CKA_VALUE | Byte array | 当前计数值(大端序) |
重要约束:CKA_VALUE只能读取,不能设置!
/* 读取计数器 */
CK_BYTE counterValue[8];
CK_ATTRIBUTE getValue = {CKA_VALUE, counterValue, sizeof(counterValue)};
rv = C_GetAttributeValue(hSession, hCounter, &getValue, 1);
/* 尝试设置会失败 */
CK_BYTE newValue[8] = {0};
CK_ATTRIBUTE setValue = {CKA_VALUE, newValue, sizeof(newValue)};
rv = C_SetAttributeValue(hSession, hCounter, &setValue, 1);
// 返回CKR_ATTRIBUTE_READ_ONLY
单调计数器的安全意义
单调计数器是防御重放攻击的关键工具。
重放攻击场景:
攻击者截获消息:
Message_1 = {command: "解锁车门", counter: 100, signature: ...}
攻击者重放:
Message_2 = {command: "解锁车门", counter: 100, signature: ...}
↑ 相同计数器值 → 重放!
防御机制:
每次收到消息,检查counter是否大于上次记录的值:
- counter > last_counter → 接受,更新last_counter
- counter <= last_counter → 拒绝,疑似重放攻击
车载应用场景:
车载安全消息序列:
┌───────────────────────────────────────┐
│ Host应用程序 │
│ │
│ 1. 读取HSM单调计数器 │
│ counter = 1001 │
│ │
│ 2. 构造安全消息 │
│ message = { │
│ command: "解锁车门", │
│ counter: 1001, │
│ timestamp: 当前时间 │
│ } │
│ │
│ 3. HSM签名 │
│ signature = Sign(privateKey, │
│ message) │
│ │
│ 4. 发送消息 │
│ → {message, signature} │
└───────────────────────────────────────┘
接收端验证:
- 检查counter是否递增
- 检查签名有效性
- 防止攻击者重放旧消息
CKA_RESET_ON_INIT与CKA_HAS_RESET
这两个属性控制计数器的“生命周期“:
计数器重置场景:
场景1:正常使用(不重置)
┌─────────────────┐
│ Token初始化 │
│ C_InitToken │ → 计数器保持原值
└─────────────────┘
CKA_RESET_ON_INIT = FALSE
CKA_HAS_RESET = FALSE(从未重置)
场景2:强制重置
┌─────────────────┐
│ Token重新初始化 │
│ C_InitToken │ → 计数器重置为初始值
└─────────────────┘
CKA_RESET_ON_INIT = TRUE(支持重置)
CKA_HAS_RESET = TRUE(已被重置)
安全考虑:
- 如果CKA_RESET_ON_INIT = FALSE,计数器值跨Token初始化保持,提供更强的防重放能力
- 如果CKA_RESET_ON_INIT = TRUE,每次C_InitToken会重置,可能削弱安全性
用户界面对象(User Interface)
用户界面对象(CKH_USER_INTERFACE)代表Token的人机交互能力。
用户界面对象适用场景:
传统HSM:
- 无显示屏、无键盘
- 通过Host计算机操作
智能卡/USB Token:
- 可能带有PIN输入键盘
- 可能带有小型显示屏
- 用于安全PIN输入
ATM/POS终端:
- 大屏幕显示
- 键盘输入
- 用户交互界面
属性:
| 属性 | 数据类型 | 含义 |
|---|---|---|
| CKA_PIXEL_X | CK_ULONG | X轴像素分辨率(如1280) |
| CKA_PIXEL_Y | CK_ULONG | Y轴像素分辨率(如1024) |
| CKA_RESOLUTION | CK_ULONG | DPI像素密度 |
| CKA_CHAR_ROWS | CK_ULONG | 字符显示行数(如24) |
| CKA_CHAR_COLUMNS | CK_ULONG | 字符显示列数(如80) |
| CKA_COLOR | CK_BBOOL | 是否支持彩色显示 |
| CKA_BITS_PER_PIXEL | CK_ULONG | 每像素位数 |
| CKA_CHAR_SETS | RFC2279 string | 支持的字符集 |
| CKA_ENCODING_METHODS | RFC2279 string | 支持的编码方法 |
| CKA_MIME_TYPES | RFC2279 string | 支持的MIME类型 |
车载HSM的硬件特征对象配置
车载HSM通常支持以下硬件特征对象:
车载HSM硬件特征:
时钟对象(CKH_CLOCK)
├── 用途:安全消息时间戳
├── 来源:HSM内部RTC
├── 特性:断电保持(电池供电)
└── 精度:通常±1秒/天
单调计数器(CKH_MONOTONIC_COUNTER)
├── 用途:防重放攻击
├── 特性:每次读取自增
├── 存储:Flash(持久化)
└── 重置:C_InitToken后可能重置
用户界面对象(CKH_USER_INTERFACE)
├── 车载HSM通常:无显示屏
├── Host MCU:承担显示职责
└── 因此:通常不支持此对象
典型车规级HSM的配置:
车规级HSM硬件特征支持:
时钟对象:
- 通常支持
- 可通过APDU指令读取/设置
- 与安全消息签名关联
单调计数器:
- 通常支持
- 用于防重放序列号
- 集成在安全消息协议中
用户界面:
- 不支持(无显示屏)
小结:硬件特征对象的价值
硬件特征对象代表密码设备“超越密码“的特异功能:
核心价值回顾:
时钟对象
├── 安全时间戳来源
├── 证书有效期验证参考
├── 审计日志时间基准
└── 与CK_TOKEN_INFO.utcTime共享时钟源
单调计数器
├── 防重放攻击的关键工具
├── 保证序列号唯一递增
├── 硬件级别的不可回退
└── 安全消息协议必备
用户界面对象
├── 安全PIN输入通道
├── 独立于Host的交互能力
├── 防止Host端截获PIN
└── 智能卡/USB Token常用
设计哲学:
- 硬件特征对象"映射"真实硬件能力
- 不是虚拟对象,而是硬件接口
- 扩展PKCS#11的能力边界
- 从"密码计算"到"安全设备"
这些硬件特征对象,让HSM不仅仅是“密码计算器“,而是完整的“安全设备“。 下一节,我们将学习初始化函数——看PKCS#11的启动流程。
【下集预告】
C_Initialize做什么?C_Finalize做什么?
C_GetSlotList怎么用?C_InitToken怎么初始化?
初始化顺序是什么?
下一节,初始化与Slot管理函数。