Aller au contenu

gerege-token-kit — FEITIAN USB токений SPM сан

gerege-token-kit нь FEITIAN USB токен (smart-card хэлбэрийн крипто төхөөрөмж)-тэй локал (offline, шууд утсаар залгасан) харьцах Swift Package Manager сан. Токен дээр түлхүүр үүсгэх, PIN-аар нэвтрэх, ECDSA/RSA гарын үсэг зурах, сертификат унших/бичих, PKCS#10 CSR үүсгэх боломжийг өгнө.

Хараат сан байхгүй (dependency-free). Гуравдагч талын package огт ашиглахгүй — зөвхөн Apple-ийн системийн framework (Foundation, CryptoTokenKit, CommonCrypto, os) дээр тулгуурладаг. Эх сурвалж: desktop/gerege-token-kit/Package.swift.

Локал зориулалттай (local-only). Энэ сан нь зөвхөн залгасан USB токентэй шууд харьцана — RP-API эсвэл сүлжээний ямар ч дуудлага хийхгүй. Токен дээр үүссэн CSR/гарын үсгийг серверт хүргэх нь дуудагч аппын (жишээ нь macOS desktop) хариуцлага.

1. Юу хийдэг вэ

Сан нь хоёр түвшний хандалт өгдөг:

Түвшин Type Аргачлал Токен
Стандарт (PKCS#11) PKCS11Module FEITIAN Castle middleware (libcastle*.dylib)-г dlopen-оор ачаалж C_* функц дуудна FEITIAN Castle FTSmartToken
Доод (APDU) BioPassDriver ISO 7816-4 APDU-г шууд илгээж, mutual-auth дараа Secure Messaging (3DES) ашиглана BioPass2003 / ePass2003 (EnterSafe-FIPS applet)

Нэмэлт туслах бүрэлдэхүүн:

  • TokenManagerCryptoTokenKit (TKSmartCard) дээр суурилсан reader илрүүлэлт, session удирдлага.
  • APDUCommand / APDUResponse / APDUTransceiver — APDU бүтээх/дамжуулах engine.
  • SecureMessaging — ePass2003 3DES secure channel (mutual auth, APDU wrap/unwrap).
  • CSR — PKCS#10 CSR (EC P-256 + ECDSA-SHA256) бүтээгч.
  • TokenError — монгол хэл дээрх алдааны текст бүхий enum.

2. Суулгах

Локал path-аар нэмнэ (санг repo дотор нэг зэрэг ирдэг):

// Package.swift
dependencies: [
    .package(path: "../gerege-token-kit")
]

Дараа target-даа холбоно:

.target(name: "MyApp", dependencies: [
    .product(name: "GeregeTokenKit", targets: ["GeregeTokenKit"])
])

Санг импортлох:

import GeregeTokenKit

Package мэдээлэл (Package.swift):

  • Нэр / product: GeregeTokenKit
  • Платформ: macOS 14+, iOS 17+ (PKCS#11 dlopen зам нь бодит USB middleware шаардах тул практикт macOS-д ажиллана — доорх §5-г үзнэ үү).
  • swift-tools-version: 5.9

3. Public API

PKCS11Module (стандарт зам)

Эх сурвалж: Sources/GeregeTokenKit/PKCS11Module.swift.

Middleware-ийн default path-ууд (defaultLibraryPaths): /usr/local/lib/libcastle.1.0.0.dylib, /usr/local/lib/libcastle.dylib, /Library/OpenSC/lib/opensc-pkcs11.so.

Доод түвшний функцүүд:

Функц Үүрэг
static open(libraryPath:) .dylib/.sodlopen-оор ачаалж C_* тэмдэгтүүдийг олно
initialize() / finalize() C_Initialize / C_Finalize
getSlotList(tokenPresent:) Токен залгасан slot-уудын ID
openSession(slotId:readWrite:) / closeSession(_:) Session нээх/хаах
login(session:pin:userType:) / logout(_:) C_Login (CKU_USER/CKU_SO) / C_Logout
findPrivateKey(session:label:) / findPublicKey(session:label:) Label-аар түлхүүр олох
signECDSA(session:privateKey:hash:) ECDSA гарын үсэг — буцаах: r‖s
readECPoint(session:publicKey:) CKA_EC_POINT-оос raw EC цэг унших
initToken(slotId:soPIN:label:) C_InitToken — factory reset + SO PIN
initPIN(session:userPIN:) / setPIN(session:oldPIN:newPIN:) User PIN тогтоох/солих
generateECKeyPair(session:label:keyID:) Токен дээр EC P-256 keypair үүсгэх
writeCertificate(session:certificateDER:label:keyID:subjectDER:) X.509 сертификат C_CreateObject-оор хадгалах
listObjects(session:) Токен дээрх бүх object-ыг TokenObjectInfo-оор жагсаах
destroyObject(session:handle:) Object устгах (C_DestroyObject)

Дээд түвшний туслах функцүүд (slot сонгох, login, logout автоматаар хийж, session өөрөө хаагдана):

Функц Үүрэг
signECDSA(pin:keyLabel:hash:) PIN-аар нэвтэрч, label-аар түлхүүр олж, гарын үсэг зурна
generateCSR(pin:keyLabel:subject:) Токен дээрх түлхүүрээр PKCS#10 CSR (DER+PEM) үүсгэнэ
fullProvision(soPIN:userPIN:label:keyLabel:keyID:) Factory reset + SO/User PIN + EC keypair (⚠ бүх өмнөх түлхүүр устана)
listObjects(pin:) Нэвтэрч бүх object жагсаах
importCertificate(pin:label:certificateDER:keyID:) Сертификат импортлох
deleteObject(pin:idHex:kind:) idHex+kind-ээр object устгах
generateSigningKey(pin:label:keyID:) EC P-256 гарын үсгийн keypair үүсгэх
changeUserPIN(oldPIN:newPIN:) / changeSOPIN(oldPIN:newPIN:) PIN солих
unlockUserPIN(soPIN:newUserPIN:) Түгжигдсэн User PIN-г SO PIN-ээр тайлах

BioPassDriver (доод/APDU зам)

Эх сурвалж: Sources/GeregeTokenKit/BioPassDriver.swift. TKSmartCard-тай шууд ажилладаг (OpenSC card-epass2003.c-ийн Swift порт). Гол функцүүд:

Функц Үүрэг
selectApplet(card:) EnterSafe-FIPS applet сонгох
establishSecureSession(card:...) Mutual auth → Secure Messaging session тогтоох
verifyPIN(_:reference:card:) User/SO PIN шалгах (буруу бол pinVerifyFailed(retriesLeft:))
getTokenInfo(card:) ATR, label, 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:) Токен бүрэн initialize (erase + transport key + PKCS#15 файлын систем + PIN)

TokenManager (reader/session)

Эх сурвалж: Sources/GeregeTokenKit/TokenManager.swift.

  • TokenManager.shared — singleton
  • getReaderNames() -> [String], hasToken() -> Bool
  • withSession(readerIndex:_:) — session нээж operation гүйцэтгээд автоматаар хаана
  • getATR(readerIndex:)

CSR

Эх сурвалж: Sources/GeregeTokenKit/CSR.swift.

  • CSR.Subject(commonName:organization:country:email:)
  • CSR.buildP256(subject:publicKeyPoint:signer:) — 65 байт uncompressed EC цэг + гарын үсэг зурах closure-аас PKCS#10 CSR (DER + PEM) буцаана.

4. Ашиглалтын жишээ

Reader байгаа эсэхийг шалгах

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 байт */
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 middleware ачаалдаг тул практикт macOS-д ашиглагдана. Package.swift-д iOS 17-г бас зарласан ч бодит USB токен
  • middleware байхгүй тул iOS дээр PKCS#11 зам ажиллахгүй.
  • Дэмждэг токен:
  • PKCS#11: FEITIAN Castle FTSmartToken (libcastle.1.0.0.dylib); мөн OpenSC opensc-pkcs11.so default path-д багтсан.
  • APDU: BioPass2003 / ePass2003 (EnterSafe-FIPS applet).
  • Крипто: EC P-256 (ECDSA-SHA256) үндсэн зам; RSA-г BioPassDriver/PKCS11Module дэмждэг боловч CSR builder нь зөвхөн P-256.
  • Provisioning нь эвдэх үйлдэл. fullProvision / initToken / initializePIN нь токен дээрх бүх түлхүүр, сертификатыг устгана.

6. macOS desktop апптай холбоо

Энэ санг macOS desktop апп (eID Mongolia macOS RP клиент) хэрэглэдэг: тухайн апп GeregeTokenKit.TokenManager.shared болон BioPassDriver-ийг өөрийн Core/Token/TokenManager.swift-д wrap хийж, USB токеноор PDF-д гарын үсэг зурах туршилтын урсгалыг гүйцэтгэдэг.

7. Холбоос