eID Mongolia — iOS SDK (GeregeSmartID)¶
GeregeSmartID бол eID платформын iOS Swift SDK — иргэний утсан дээр distributed
keygen, 2-of-2 threshold ECDSA гарын үсэг, App Attest, Keychain хадгалалтыг гүйцэтгэнэ.
Крипто нь Go серверийн internal/crypto-той байт-нийцтэй (golden-vector-аар батлагдсан),
тиймээс threshold-ECDSA / Paillier / Schnorr / PDL урсгал хоёр талд яг таарна.
Эх код:
ios/ios-sdk/Sources/GeregeSmartID/—GeregeSmartIDClient.swift(orchestrator),SecureKeyStore.swift(Keychain + PIN),PhoneCrypto.swift,Paillier.swift,Proofs.swift,AppAttestManager.swift.
Дугаарын нэр томьёо
Иргэн бүр нэг documentNumber (төхөөрөмжийн UUID)-тай ба ХОЁР тусдаа threshold
түлхүүртэй: authentication (PIN1, нэвтрэх, clientAuth) ба signing (PIN2, гарын
үсэг, non-repudiation). SDK-д эдгээр нь PINSlot.auth / PINSlot.sign (docs/IDENTIFIERS.md,
docs/EID_2CERT_MILESTONE.md).
1. Товч танилцуулга¶
GeregeSmartIDClient нь backend (жишээ нь rp-api.eidmongolia.mn)-ийн enrollment ба
threshold-signing endpoint-уудтай харьцаж, App Attest + крипто урсгалыг зохицуулна.
Гол чадвар:
| Үйлдэл | Тайлбар |
|---|---|
| enroll | DAN KYC consent код + PIN-ээр distributed keygen хийж, сертификат авч хадгална. authPin өгвөл хоёр keygen (auth + sign) зэрэг хийнэ (eID 2-cert). |
| approve | RP-ийн QR/push session-ийг PIN-ээр зөвшөөрч, 3-round threshold ECDSA гарын үсэг угсарна. |
| changePIN / verifyPIN | PIN-ийг локал шалгах/солих (сервер PIN-ийг ХЭЗЭЭ Ч хардаггүй). |
| pending / activity / sessionInfo | Хүлээгдэж буй session poll, түүх, session мэдээлэл. |
Хувийн түлхүүр нэг газар бүрэн орших нь үгүй: нэг хагас утсан дээр (PIN-ээр шифрлэгдэж Keychain-д), нэг хагас серверт.
2. Урьдчилсан нөхцөл¶
- iOS 14.0+ (SDK), macOS 12.0+ —
Package.swiftдахьplatforms. (ҮндсэнeIDMongoliaапп нь iOS 15.0+ тавьсан.) - App Attest симулятор дээр ажиллахгүй. Симулятор/emulator дээр App Attest / Secure Enclave
байхгүй тул Go серверийг
SMARTID_REQUIRE_ATTESTATION=false(dev default)-оор ажиллуулна. Production-д (=true) бодит төхөөрөмж + App Attest шаардана. - Backend URL нь тохиргоогоор тавигдана (hardcode биш) —
GeregeSmartIDClient(baseURL:)-д дамжуулна. Жишээ production суурь:https://rp-api.eidmongolia.mn. - BigInt dependency (attaswift/BigInt) — threshold
протоколын raw EC scalar/point + Paillier (2048-бит) арифметикт шаардлагатай (CryptoKit
эдгээрийг ил гаргадаггүй).
swift buildүед автоматаар татагдана.
TLS pinning
SDK бүх backend холболтоо CertPinner (public-key pinning)-ээр шалгадаг. Хэрэв сервер нь
хүлээгдсэн CA (Let's Encrypt)-аас өөр гэрчилгээ өгвөл холболт NSURLErrorCancelled (-999)-ээр
цуцлагдана.
3. Суулгах (Swift Package Manager)¶
Package нэр: GeregeSmartID, product: GeregeSmartID (ios/ios-sdk/Package.swift).
Монорепо доторх апп (XcodeGen project.yml) нь SDK-г локал path-аар авдаг:
Гадны төслөөс SPM dependency-гээр авах бол Package.swift-д:
dependencies: [
.package(url: "https://github.com/gerege-systems/eid-platform-mn.git", branch: "main"),
// эсвэл SDK-г тусад нь host хийсэн repo-гоос
],
targets: [
.target(name: "MyApp", dependencies: [
.product(name: "GeregeSmartID", package: "eid-platform-mn")
])
]
4. Үндсэн ашиглалт¶
4.1 Client үүсгэх¶
import GeregeSmartID
let client = GeregeSmartIDClient(
baseURL: URL(string: "https://rp-api.eidmongolia.mn")!,
account: "default") // Keychain доторх бүртгэлийн нэр (default)
account нь Keychain slot-ийн нэр. SDK signing-ийг account, authentication-ийг
account + ".auth" доор хадгална (init(baseURL:account:)).
4.2 Бүртгэл (enroll)¶
enroll нь DAN KYC consent код + PIN-ээр distributed keygen хийж, сертификат авч Keychain-д
хадгалаад documentNumber (UUID) буцаана. authPin өгвөл хоёр keygen (auth + sign)
хийж, signing-ийг pin-ээр, authentication-ийг authPin-ээр тус тусын slot-д хадгална;
authPin == nil бол зөвхөн signing cert (хуучин зан).
@discardableResult
public func enroll(danAuthCode: String, pin: String, authPin: String? = nil,
pushToken: String,
reviewLatin: LatinNameReview? = nil,
progress: ProgressHandler? = nil) async throws -> String
Жишээ (eID 2-cert — хоёр PIN):
let documentNumber = try await client.enroll(
danAuthCode: danState, // DAN-аас баталгаажсан consent код (state)
pin: "1234", // PIN2 → signing (гарын үсэг)
authPin: "5678", // PIN1 → authentication (нэвтрэх); nil бол зөвхөн signing
pushToken: apnsToken)
reviewLatin callback-аар латин галигийг иргэнд харуулж засуулж болно (LatinNameProposal
→ засварласан (givenNameLatin, surnameLatin)). progress нь round бүрийг монгол label-аар
UI-д харуулна (ProgressHandler = @MainActor (String) -> Void).
DAN KYC урсгал
enroll-д өгөх danAuthCode нь DAN баталгаажуулалтын state. Урьдчилан:
danInit(registrationNumber:) → verify URL нээх → danStatus(state:)-аар poll → баталгаажвал
enroll(danAuthCode: state, …). (kycMethods()-оор боломжит арга: DAN / G-Sign / passport /
citizen card.)
4.3 Session зөвшөөрөх (approve)¶
RP-ийн QR / push-аас авсан sessionId-ийг PIN-ээр зөвшөөрнө. authentication: true
(нэвтрэх flow) үед authentication түлхүүр (PIN1, .auth slot), эс бөгөөс signing түлхүүр
(PIN2) ашиглагдана — серверийн сонгосон түлхүүртэй таарна. flowType-ийг урьдчилан
sessionInfo(sessionId:)-оор мэднэ.
@discardableResult
public func approve(sessionId: String, pin: String,
authentication: Bool = false,
confirmVc: String? = nil,
progress: ProgressHandler? = nil) async throws -> String
Жишээ:
// Нэвтрэх (authentication) session
let status = try await client.approve(
sessionId: sessionId, pin: "5678", authentication: true) // "OK"
// Гарын үсэг (signature) session
let status = try await client.approve(
sessionId: sessionId, pin: "1234") // authentication: false (default)
approve нь дотроо 3-round threshold ECDSA хийнэ: commit → prove → finish
(/v3/mobile/session/{id}/sign/{commit,prove,finish}). Гарын үсгийг серверт ИЛГЭЭХЭЭСЭЭ
ӨМНӨ утас session-ий мессежийг (SIGN: digest; AUTH: ACSP_V2(rpChallenge, өөрийн SPKI))
бие даан тооцоолж, эцсийн (r,s)-г өөрийн сертификатын public key-д ECDSA-verify хийнэ
(transcript binding — WYSIWYS). Хурдасгахын тулд presign(sessionId:documentNumber:)-ээр
PIN шаардахгүй nonce round-уудыг урьдчилан бэлдэж болно.
4.4 PINSlot ба PIN удирдлага¶
public enum PINSlot { case auth, sign }
public func verifyPIN(slot: PINSlot, pin: String) -> Bool // локал шалгалт
public func changePIN(slot: PINSlot, oldPIN: String, newPIN: String) throws
public func deleteRegistration() // локал устгах
verifyPIN— хадгалсан identity-г PIN-ээр тайлж үзнэ (сервер рүү хандахгүй).changePIN— хуучин PIN-ээр тайлж, шинэ PIN-ээр дахин шифрлэнэ; гэрчилгээ + public key өөрчлөгдөхгүй. Буруу хуучин PIN →SDKError.wrongPIN.deleteRegistration— зөвхөн ЛОКАЛ устгана (signing + auth slot хоёулаа); серверийн сертификатыг revoke хийхгүй (тэр нь админ үйлдэл).
4.5 Алдаа (SDKError)¶
public enum SDKError: Error {
case crypto(String) // криптограф алдаа
case http(String) // сүлжээ / сервер алдаа
case wrongPIN // PIN буруу (түлхүүр задрахгүй)
case locked // хэт олон буруу PIN → бүртгэл устгагдсан (дахин бүртгүүлэх)
}
SDKError нь LocalizedError тул errorDescription монголоор бодит шалтгааныг өгнө.
5. Keychain / Secure Enclave / биометр¶
Утасны нууцуудыг SecureKeyStore (SecureKeyStore.swift) удирдана:
- PIN → PBKDF2 (HMAC-SHA256, 210,000 iteration) → AES-GCM шифрлэлт, дараа нь Secure Enclave-ийн P-256 түлхүүрээр ECIES wrap (hardware binding). PIN сервер рүү ХЭЗЭЭ Ч очдоггүй.
- Хадгалах формат:
[salt(16) | iv(12) | ciphertext | tag(16)]→ SE wrap →[1 | wrapped]. Бодит төхөөрөмж дээр SE боломжгүй бол хатуу алдаа (SDKError.crypto); зөвхөн симулятор дээр[0 | blob](hardware-binding-гүй, dev-only) зөвшөөрнө. - Биометр (H8): SE wrap түлхүүр нь
.userPresenceaccess-control-той (Face ID / Touch ID эсвэл passcode). Signing key-г unwrap хийх (= PIN-ээр identity задлах) үед биометр prompt гарна; хэрэглэгч цуцалбал unwrap болохгүй → signing зогсоно. - Brute-force хамгаалалт: дараалсан 10 буруу PIN хэтэрвэл шифрлэгдсэн бүртгэлийг УСТГАНА
(
SDKError.locked). Тоологч нь blob устсан ч Keychain-д тогтвортой үлдэнэ. - Accessibility: бүх зүйл
kSecAttrAccessibleWhenUnlockedThisDeviceOnly— энэ төхөөрөмжид холбогдоно, iCloud-д sync хийгдэхгүй. - Device-binding token:
/v3/mobile/*хүсэлт бүрдX-Device-Token-оор илгээх PIN-гүй bearer credential (pending/activity polling нь PIN-ээс өмнө хэрэгтэй) — мөнThisDeviceOnly.
Keychain namespace
GeregeSmartIDKeychain.service нь брэндийн namespace (eIDMongolia → "mn.eidmongolia.smartid").
Апп startup-д НЭГ УДАА тавина. Аль хэдийн хэрэглэгчтэй апп-д БҮҮ СОЛЬ — өмнөх нэрийн доорх
бүртгэл уншигдахгүй болно.
6. Үндсэн апп (eIDMongolia) build хийх¶
eIDMongolia (ios/eIDMongolia/) нь энэ repo-гийн цорын ганц core / reference апп (XcodeGen
project.yml, bundle mn.eidmongolia.dan). Дэлгэрэнгүй:
ios/README.md.
brew install xcodegen
cd ios/eIDMongolia
export GEREGE_BACKEND_URL=https://rp-api.eidmongolia.mn # эсвэл AppConfig default-оор
xcodegen # eIDMongolia.xcodeproj үүсгэнэ
open eIDMongolia.xcodeproj # Xcode-оос Run
Холбогдсон төхөөрөмж рүү CLI-аар build + суулгах (automatic signing, -scheme ашиглана,
-target биш):
xcodebuild -project eIDMongolia.xcodeproj -scheme eIDMongolia \
-configuration Debug -destination 'id=<DEVICE_ID>' \
-allowProvisioningUpdates build
xcrun devicectl device install app --device <DEVICE_ID> <path>/eIDMongolia.app
Backend URL эрэмбэ (eIDMongolia/App/AppConfig.swift): Xcode scheme env
(GEREGE_BACKEND_URL) → Info.plist (project.yml build setting) → код default
(AppConfig.defaultBackendURL).
SDK-г CLI-аар шалгах (iOS simulator target):
cd ios/ios-sdk
swift build --sdk "$(xcrun --sdk iphonesimulator --show-sdk-path)" \
--triple arm64-apple-ios16.0-simulator
(swift build дангаараа macOS руу build хийж App Attest API дээр зогсоно — энэ хэвийн,
SDK iOS-only.)
7. App Attest урсгал (товч)¶
AppAttestManager нь backend руу явах эхний хүсэлтэд төхөөрөмжийг батална:
- Эхний хүсэлт:
generateKey→attestKey→ headerType: attest(сервер keyId / pubkey / counter бүртгэнэ). - Дараагийн хүсэлт бүр:
generateAssertion→ headerType: assert+KeyId(сервер counter хатуу өсөхийг шалгана).
Сервер хариунд X-Next-Attestation-Nonce header өгдөг тул апп тусдаа challenge GET
(GET /v3/attestation/challenge)-ийг алгасч хурдасна.
8. Backend endpoint-ууд (SDK ашигладаг)¶
Бүгд Go серверийн internal/httpapi-д таарна:
| Endpoint | Зориулалт |
|---|---|
GET /v3/attestation/challenge |
App Attest nonce |
POST /v3/enrollment/init · /complete |
distributed keygen + сертификат |
GET /v3/mobile/session/{id} · /v3/mobile/pending/{doc} |
session мэдээлэл / pending poll |
POST /v3/mobile/session/{id}/sign/{commit,prove,finish} |
2-of-2 threshold ECDSA (3 round) |
9. Холбоос¶
- SDK эх код:
ios/ios-sdk/Sources/GeregeSmartID/ - SDK README:
ios/ios-sdk/README.md - Апп + build заавар:
ios/README.md - Идентификаторууд:
docs/IDENTIFIERS.md· 2-cert:docs/EID_2CERT_MILESTONE.md - RP интеграц (серверийн тал):
docs/RP_INTEGRATION.md