gerege-token-kit —— FEITIAN USB 令牌 SPM 包¶
gerege-token-kit 是一个 Swift Package Manager 包,用于本地(离线、直接插接)
与 FEITIAN USB 令牌(智能卡形态的加密设备)交互。它提供在令牌上生成密钥、
使用 PIN 登录、生成 ECDSA/RSA 签名、读写证书以及生成 PKCS#10 CSR 的能力。
无第三方依赖。 完全不使用任何第三方包 —— 仅依赖 Apple 的系统框架 (
Foundation、CryptoTokenKit、CommonCrypto、os)。源码:desktop/gerege-token-kit/Package.swift。仅限本地。 本包只与已插入的 USB 令牌直接交互 —— 不会调用 RP-API, 也不发起任何网络请求。将令牌上生成的 CSR / 签名送达服务器,是调用方应用 (例如 macOS 桌面端)的职责。
1. 功能概述¶
本包提供两个访问层级:
| 层级 | 类型 | 方式 | 令牌 |
|---|---|---|---|
| 标准(PKCS#11) | PKCS11Module |
通过 dlopen 加载 FEITIAN Castle 中间件(libcastle*.dylib)并调用 C_* 函数 |
FEITIAN Castle FTSmartToken |
| 底层(APDU) | BioPassDriver |
直接发送 ISO 7816-4 APDU,在完成 mutual-auth 后使用 Secure Messaging(3DES) | BioPass2003 / ePass2003(EnterSafe-FIPS 小程序) |
其他配套组件:
TokenManager—— 基于CryptoTokenKit(TKSmartCard)的读卡器检测与会话管理。APDUCommand/APDUResponse/APDUTransceiver—— APDU 构造与传输引擎。SecureMessaging—— ePass2003 的 3DES 安全通道(mutual auth、APDU 封装 / 解封装)。CSR—— PKCS#10 CSR(EC P-256 + ECDSA-SHA256)构造器。TokenError—— 错误文案为蒙古语的enum。
2. 安装¶
通过本地路径引入(该包与主仓库一同发布):
随后链接到您的 target:
.target(name: "MyApp", dependencies: [
.product(name: "GeregeTokenKit", targets: ["GeregeTokenKit"])
])
引入包:
包信息(Package.swift):
- 名称 / 产品:
GeregeTokenKit - 平台:macOS 14+、iOS 17+(由于 PKCS#11 的
dlopen路径需要真实的 USB 中间件, 实际上只在 macOS 上可用 —— 详见下文 §5)。 - swift-tools-version:5.9
3. 公开 API¶
PKCS11Module(标准路径)¶
源码:Sources/GeregeTokenKit/PKCS11Module.swift。
默认中间件路径(defaultLibraryPaths):
/usr/local/lib/libcastle.1.0.0.dylib、/usr/local/lib/libcastle.dylib、
/Library/OpenSC/lib/opensc-pkcs11.so。
底层函数:
| 函数 | 作用 |
|---|---|
static open(libraryPath:) |
通过 dlopen 加载 .dylib/.so 并查找 C_* 符号 |
initialize() / finalize() |
C_Initialize / C_Finalize |
getSlotList(tokenPresent:) |
已插入令牌的插槽 ID |
openSession(slotId:readWrite:) / closeSession(_:) |
打开 / 关闭会话 |
login(session:pin:userType:) / logout(_:) |
C_Login(CKU_USER/CKU_SO)/ C_Logout |
findPrivateKey(session:label:) / findPublicKey(session:label:) |
按标签查找密钥 |
signECDSA(session:privateKey:hash:) |
ECDSA 签名 —— 返回 r‖s |
readECPoint(session:publicKey:) |
从 CKA_EC_POINT 读取原始 EC 点 |
initToken(slotId:soPIN:label:) |
C_InitToken —— 恢复出厂设置 + SO PIN |
initPIN(session:userPIN:) / setPIN(session:oldPIN:newPIN:) |
设置 / 修改用户 PIN |
generateECKeyPair(session:label:keyID:) |
在令牌上生成 EC P-256 密钥对 |
writeCertificate(session:certificateDER:label:keyID:subjectDER:) |
通过 C_CreateObject 写入 X.509 证书 |
listObjects(session:) |
以 TokenObjectInfo 列出令牌上的全部对象 |
destroyObject(session:handle:) |
删除对象(C_DestroyObject) |
高层辅助函数(自动选择插槽、登录并登出,会话会自行关闭):
| 函数 | 作用 |
|---|---|
signECDSA(pin:keyLabel:hash:) |
用 PIN 登录、按标签查找密钥并签名 |
generateCSR(pin:keyLabel:subject:) |
使用令牌上的密钥生成 PKCS#10 CSR(DER+PEM) |
fullProvision(soPIN:userPIN:label:keyLabel:keyID:) |
恢复出厂 + SO/User PIN + EC 密钥对(⚠ 之前的所有密钥都会被清除) |
listObjects(pin:) |
登录并列出全部对象 |
importCertificate(pin:label:certificateDER:keyID:) |
导入证书 |
deleteObject(pin:idHex:kind:) |
按 idHex+kind 删除对象 |
generateSigningKey(pin:label:keyID:) |
生成 EC P-256 签名密钥对 |
changeUserPIN(oldPIN:newPIN:) / changeSOPIN(oldPIN:newPIN:) |
修改 PIN |
unlockUserPIN(soPIN:newUserPIN:) |
使用 SO PIN 解锁被锁定的 User PIN |
BioPassDriver(底层 / APDU 路径)¶
源码:Sources/GeregeTokenKit/BioPassDriver.swift。
直接操作 TKSmartCard(OpenSC card-epass2003.c 的 Swift 移植)。主要函数:
| 函数 | 作用 |
|---|---|
selectApplet(card:) |
选择 EnterSafe-FIPS 小程序 |
establishSecureSession(card:...) |
Mutual auth → 建立 Secure Messaging 会话 |
verifyPIN(_:reference:card:) |
校验 User/SO PIN(错误时返回 pinVerifyFailed(retriesLeft:)) |
getTokenInfo(card:) |
ATR、标签、是否 FIPS(TokenInfo) |
signECDSA(hash:card:) / signRSA(data:card:) |
签名 |
generateECKeyPair(keyID:card:) / generateRSAKeyPair(keyID:keySize:card:) |
生成密钥(需要 SM) |
readCertificate(fileID:card:) / writeCertificate(data:fileID:card:) |
读写证书 |
initializePIN(pin:puk:card:) |
完整初始化令牌(擦除 + 传输密钥 + PKCS#15 文件系统 + PIN) |
TokenManager(读卡器 / 会话)¶
源码:Sources/GeregeTokenKit/TokenManager.swift。
TokenManager.shared—— 单例getReaderNames() -> [String]、hasToken() -> BoolwithSession(readerIndex:_:)—— 打开会话、执行操作并自动关闭getATR(readerIndex:)
CSR¶
源码:Sources/GeregeTokenKit/CSR.swift。
CSR.Subject(commonName:organization:country:email:)CSR.buildP256(subject:publicKeyPoint:signer:)—— 依据 65 字节的未压缩 EC 点 与一个签名闭包,返回 PKCS#10 CSR(DER + PEM)。
4. 使用示例¶
检查是否存在读卡器¶
import GeregeTokenKit
let mgr = TokenManager.shared
if mgr.hasToken() {
print("Reader-ууд:", mgr.getReaderNames())
let atr = try await mgr.getATR()
print("ATR:", bytesToHex(atr))
}
使用 PKCS#11 签名(高层)¶
let hash = /* SHA-256 digest, 32 bytes */
let p11 = try PKCS11Module.open() // 加载 libcastle*.dylib
let signature = try p11.signECDSA( // 返回 r‖s
pin: "12345678",
keyLabel: "gerege",
hash: hash
)
使用令牌上的密钥生成 CSR¶
let p11 = try PKCS11Module.open()
let subject = CSR.Subject(commonName: "Бат-Эрдэнэ", country: "MN")
let (der, pem) = try await p11.generateCSR(
pin: "12345678",
keyLabel: "gerege",
subject: subject
)
// 将 pem 提交给 CA 以获取证书(不在本包范围内)
在 APDU 层操作(BioPassDriver)¶
let driver = BioPassDriver()
try await TokenManager.shared.withSession { card in
_ = try await driver.selectApplet(card: card)
try await driver.establishSecureSession(card: card) // 3DES SM
try await driver.verifyPIN("12345678", card: card)
let sig = try await driver.signECDSA(hash: hash, card: card)
return sig
}
5. 限制¶
- 仅限本地。 本包不向网络发送任何数据 —— 只与已插入的令牌交互。
- 平台。
PKCS11Module通过dlopen加载原生.dylib中间件,因此实际使用场景为 macOS。虽然Package.swift同时声明了 iOS 17,但 iOS 上没有真实的 USB 令牌与中间件, PKCS#11 路径无法工作。 - 支持的令牌:
- PKCS#11:FEITIAN Castle FTSmartToken(
libcastle.1.0.0.dylib);默认路径中也包含 OpenSC 的opensc-pkcs11.so。 - APDU:BioPass2003 / ePass2003(EnterSafe-FIPS 小程序)。
- 密码学: 主路径为 EC P-256(ECDSA-SHA256);
BioPassDriver/PKCS11Module支持 RSA, 但 CSR 构造器仅支持 P-256。 - provisioning 具有破坏性。
fullProvision/initToken/initializePIN会清除令牌上的所有密钥与证书。
6. 与 macOS 桌面应用的关系¶
本包被 macOS 桌面应用(eID Mongolia 的 macOS RP 客户端)使用:
该应用在自身的 Core/Token/TokenManager.swift 中封装了
GeregeTokenKit.TokenManager.shared 与 BioPassDriver,
并实现了使用 USB 令牌签署 PDF 的实验性流程。
7. 链接¶
- 包:
desktop/gerege-token-kit/Package.swift - PKCS#11:
Sources/GeregeTokenKit/PKCS11Module.swift - APDU 驱动:
Sources/GeregeTokenKit/BioPassDriver.swift - 会话 / 读卡器:
Sources/GeregeTokenKit/TokenManager.swift - APDU 引擎:
Sources/GeregeTokenKit/APDUEngine.swift - Secure Messaging:
Sources/GeregeTokenKit/SecureMessaging.swift - CSR 构造器:
Sources/GeregeTokenKit/CSR.swift - 错误定义:
Sources/GeregeTokenKit/TokenError.swift