gerege-token-kit — SPM-пакет для USB-токенов FEITIAN¶
gerege-token-kit — пакет Swift Package Manager для локального взаимодействия
(офлайн, напрямую с подключённым устройством) с USB-токенами FEITIAN
(криптоустройствами в форм-факторе смарт-карты). Он позволяет генерировать ключи на токене,
входить по 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 |
Загружает middleware FEITIAN Castle (libcastle*.dylib) через dlopen и вызывает функции C_* |
FEITIAN Castle FTSmartToken |
| Низкоуровневый (APDU) | BioPassDriver |
Отправляет APDU ISO 7816-4 напрямую и после mutual-auth использует Secure Messaging (3DES) | BioPass2003 / ePass2003 (апплет EnterSafe-FIPS) |
Дополнительные вспомогательные компоненты:
TokenManager— обнаружение считывателей и управление сессиями на базеCryptoTokenKit(TKSmartCard).APDUCommand/APDUResponse/APDUTransceiver— движок сборки и передачи APDU.SecureMessaging— защищённый канал 3DES для ePass2003 (mutual auth, wrap/unwrap APDU).CSR— построитель PKCS#10 CSR (EC P-256 + ECDSA-SHA256).TokenError—enumс текстами ошибок на монгольском языке.
2. Установка¶
Подключается по локальному пути (пакет поставляется в том же репозитории):
Затем подключите его к своему таргету:
.target(name: "MyApp", dependencies: [
.product(name: "GeregeTokenKit", targets: ["GeregeTokenKit"])
])
Импорт пакета:
Информация о пакете (Package.swift):
- Имя / продукт:
GeregeTokenKit - Платформы: macOS 14+, iOS 17+ (поскольку путь PKCS#11 через
dlopenтребует настоящего USB-middleware, на практике он работает на macOS — см. §5 ниже). - swift-tools-version: 5.9
3. Публичный API¶
PKCS11Module (стандартный путь)¶
Исходник: Sources/GeregeTokenKit/PKCS11Module.swift.
Пути к middleware по умолчанию (defaultLibraryPaths):
/usr/local/lib/libcastle.1.0.0.dylib, /usr/local/lib/libcastle.dylib,
/Library/OpenSC/lib/opensc-pkcs11.so.
Низкоуровневые функции:
| Функция | Назначение |
|---|---|
static open(libraryPath:) |
Загружает .dylib/.so через dlopen и находит символы 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:) |
Чтение сырой точки EC из CKA_EC_POINT |
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:) |
Запись сертификата X.509 через C_CreateObject |
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:) |
Разблокировка заблокированного User PIN с помощью SO PIN |
BioPassDriver (низкоуровневый путь / APDU)¶
Исходник: Sources/GeregeTokenKit/BioPassDriver.swift.
Работает напрямую с TKSmartCard (Swift-порт card-epass2003.c из OpenSC).
Основные функции:
| Функция | Назначение |
|---|---|
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:) |
Полная инициализация токена (стирание + transport key + файловая система 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:)— возвращает PKCS#10 CSR (DER + PEM) из 65-байтовой несжатой точки EC и замыкания-подписанта.
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загружает нативный.dylib-middleware черезdlopen, поэтому на практике применяется на macOS. ХотяPackage.swiftобъявляет и iOS 17, путь PKCS#11 на iOS не заработает — там нет реального USB-токена и middleware. - Поддерживаемые токены:
- PKCS#11: FEITIAN Castle FTSmartToken (
libcastle.1.0.0.dylib); в пути по умолчанию включён также OpenSCopensc-pkcs11.so. - APDU: BioPass2003 / ePass2003 (апплет EnterSafe-FIPS).
- Криптография: основной путь — EC P-256 (ECDSA-SHA256); RSA поддерживается
BioPassDriver/PKCS11Module, но построитель CSR работает только с P-256. - Provisioning разрушителен.
fullProvision/initToken/initializePINстирают все ключи и сертификаты на токене.
6. Связь с десктопным приложением macOS¶
Этот пакет используется десктопным приложением macOS (RP-клиентом
eID Mongolia для macOS): приложение оборачивает GeregeTokenKit.TokenManager.shared и
BioPassDriver в собственный Core/Token/TokenManager.swift и реализует экспериментальный
сценарий подписания PDF с помощью USB-токена.
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