انتقل إلى المحتوى

Гадаад иргэний паспортын баталгаажуулалт (ICAO 9303 passive authentication)

Гадаад иргэн eID-д бүртгүүлэхдээ паспортын NFC чипээ уншуулдаг. Асуулт нэг: чипээс уншсан мэдээлэлд яагаад итгэх ёстой вэ? Хариулт нь EF.SOD — паспорт олгосон улсын гарын үсэг.

Хоёр горим

device-trust (хуучин) SOD passive auth (энэ баримт)
Тохиргоо SMARTID_KYC_PASSPORT_DEVICE_TRUST=true SMARTID_KYC_PASSPORT_CSCA_DIR=/app/csca
Хэн шалгадаг Апп ("би шалгасан" гэж хэлнэ) Сервер
Identity хаанаас Аппын илгээсэн JSON DG1 (MRZ) — гарын үсэг зурагдсан
Хуурах боломж Апп/сүлжээний талаас БОЛОМЖТОЙ Улсын CSCA хувийн түлхүүргүйгээр боломжгүй
Production ❌ (prodHardeningIssues зогсооно)

Сервер юу шалгадаг вэ

server/internal/kyc/emrtd (цэвэр Go, гадны CMS сан ашиглаагүй):

  1. EF.SOD → CMS SignedData задлана. [APPLICATION 23] ороолт, BER indefinite-length, задалсан OCTET STRING зэрэг чипийн бодит хэлбэрүүдийг normalize хийнэ.
  2. DS → CSCA гинж: Document Signer гэрчилгээг тохируулсан CSCA итгэлийн үндэс рүү гинжилнэ (хугацаа, CA флаг). Итгэлийн үндэсгүй бол ТАТГАЛЗАНА — anchor заагаагүй бол passive auth огт хийхгүй (fail-closed).
  3. SOD-ийн гарын үсэг: RSA PKCS#1 v1.5, RSASSA-PSS, ECDSA (SHA-1…SHA-512). signedAttrs байвал messageDigest нь eContent-тэй, contentType нь LDSSecurityObject-той тулгагдана.
  4. DG hash binding: аппаас ирсэн DG1/DG2-ийн түүхий байтын hash нь SOD доторх утгатай яг тохирох ёстой. Нэг байт зөрвөл бүртгэл зогсоно.
  5. Identity — DG1-ийн MRZ-г (TD1/TD2/TD3) check digit бүрийн хамт задалж, овог/нэр/ баримтын дугаар/иргэншил/төрсөн огноо/хүйс/дуусах хугацааг гаргана. Аппын илгээсэн citizen JSON зөвхөн лавлагаа — хэрэглэгдэхгүй.
  6. Зураг: DG2 ирсэн бол (hash нь баталгаажсан) царайг чипээс гаргаж liveness-ийн лавлагаа болгоно. DG2 нь JPEG2000 бол Go задалж чадахгүй тул аппын зураг руу буцаж унана — identity-д нөлөөлөхгүй (identity нь DG1-ээс).

Монгол иргэний (PNOMN) танилтыг энэ зам үргэлж татгалздаг (H-3 хамгаалалт хэвээр) — Монгол иргэн зөвхөн DAN/G-Sign-ээр бүртгүүлнэ.

Яагаад crypto/x509-д найддаггүй вэ

Go-ийн crypto/x509 нь web-PKI-д зориулагдсан — eMRTD-ийн бодит гэрчилгээнүүдийн 31%-ийг задалж чаддаггүй. 2026-07-21-ний ICAO Master List (581 бичлэг) дээр Go-ийн задлагч:

Шалтгаан Тоо
x509: invalid ECDSA parameters — ICAO Doc 9303 нь EC домэйн параметрийг explicit бичихийг шаарддаг, Go зөвхөн named-curve OID хүлээж авдаг 176
x509: negative serial number 4
x509: invalid basic constraints 2

Үүний үр дүнд 25 улсын (ОХУ, ХБНГУ, Швейцарь, Саудын Араб, АНЭУ, Латви, Бразил, Вьетнам, Беларусь…) итгэлийн үндэс бүрэн алдагдаж, тэдгээр улсын иргэн паспортаараа бүртгүүлэх боломжгүй болно. Цаашлаад 100 гэрчилгээ нь Brainpool муруй ашигладаг — Go-ийн elliptic нь a = −3 гэж хатуу үздэг тул Brainpool-ийг ЕРӨӨСӨӨ илэрхийлж чаддаггүй.

Тиймээс cert.go + eccurve.go:

  • эхлээд crypto/x509-ээр (хатуу зам), унавал өөрсдийн задлагчаар,
  • explicit ECParameters → мэддэг муруй руу тааруулна (NIST бол Go-ийн хурдан хэрэгжүүлэлт, Brainpool бол өөрсдийн арифметик; танихгүй бол ≥224 бит шаардаад ерөнхий арифметик),
  • дурын a-тай богино Вейерштрассын муруй дээрх ECDSA шалгалт (зөвхөн нийтийн өгөгдөл тул constant-time шаардлагагүй),
  • гинжийн шалгалт x509.Verify-аас өөрсдийн walk руу: нэрийн тохирол → хугацаа → CA флаг → гарын үсэг → итгэлийн үндэс. Шалгалт СУЛРААГҮЙ — зөвхөн web-PKI-ийн хамааралгүй дүрмүүд (EKU, name constraints) хасагдсан.

Үр дүн: 581/581 гэрчилгээ ачаалагдаж, 581/581 гарын үсэг шалгагдана (103 улс).

Оператор: CSCA итгэлийн үндэс тавих

1. ICAO Master List татах (браузераар, нэг удаа)

https://www.icao.int/icao-pkd/icao-master-list — хуудасны ЁРООЛД T&C-г зөвшөөрөх checkbox дарвал .ml файлын холбоос нээгдэнэ (холбоос нь JS-ээр гарч ирдэг тул curl/script-ээр татагдахгүй; T&C-г байгууллагын өмнөөс хүн зөвшөөрөх ёстой). 2026-07-15-ны хувилбар нь PKD гишүүн орнуудын 579 CSCA гэрчилгээ агуулдаг, 3 сар тутам шинэчлэгдэнэ.

  • Шинэ хувилбар гарахад мэдэгдэл авах: icao-pkd@icao.int-д имэйлээ өгнө.
  • ⚠️ Тэр хуудсанд Health Master List (Health_ML_*.ml) ч татагддаг — тэр нь COVID-ийн эрүүл мэндийн гэрчилгээний ТУСДАА итгэлийн домэйн бөгөөд паспортын CSCA БИШ. CSCA лавлахад тавихгүй (тавибал сервер эхлэхээс татгалзаж, шалтгааныг нэрлэж хэлнэ). Паспортын passive auth-д зөвхөн ICAO_ML_*.ml хэрэгтэй.
  • pkddownload.icao.int (LDIF, CAPTCHA-тай) нь DSC/CRL-ийг ч агуулдаг — гэхдээ passive authentication-д DSC хэрэггүй (DS гэрчилгээ нь EF.SOD дотроо ирдэг). CRL нь цуцлалт шалгахад хэрэгтэй ч бид одоогоор паспортын DS-ийн цуцлалт шалгадаггүй (доорх "Хязгаар").

2. Файлыг шалгах (сервер асаахаас ӨМНӨ)

Серверийнхтэй ЯГ ижил кодоор ачаалж, юу орсныг харна:

cd server
go run ./cmd/csca-inspect -dir ../deploy/secrets/csca -countries
# ✅ CSCA итгэлийн сан ачаалагдлаа: 579 гэрчилгээ, NN улс
#    ⚠ 2160h дотор дуусах: N …

Алдаа гарвал сервер ЯГ энэ мессежээр эхлэхээс татгалзана — тиймээс энэ багажийг эхлээд ажиллуул. ICAO улирлын шинэчлэлт хийх бүрд мөн ажиллуулна (хугацаа дууссан anchor хянах).

3. Хостод байрлуулж асаах

# 1) CSCA гэрчилгээ / ICAO PKD master list-ийг хостод байрлуулна
ssh root@<app-host>
mkdir -p /opt/smartid-go/deploy/secrets/csca
# *.pem | *.crt | *.cer | *.der  эсвэл  *.ml (ICAO CSCA Master List)
cp icao-pkd-masterlist.ml /opt/smartid-go/deploy/secrets/csca/

# 2) .env
SMARTID_KYC_PASSPORT_CSCA_DIR=/app/csca
SMARTID_KYC_PASSPORT_DEVICE_TRUST=false      # SOD горимд шаардлагагүй
# SMARTID_KYC_PASSPORT_ALLOW_SHA1=true       # зөвхөн хуучин (2015-аас өмнөх) паспорт хэрэгтэй бол

# 3) env унших тул recreate (restart хангалтгүй)
cd /opt/smartid-go/deploy && docker compose up -d app
docker logs deploy-app-1 | grep passive     # anchors=<тоо> харагдана

Лавлах хоосон/уншигдахгүй бол сервер эхлэхээс татгалзана (os.Exit(1)) — passive auth чимээгүй унтарч device-trust руу гулсахаас сэргийлсэн санаатай шийдэл.

Итгэлийн үндэс нь ICAO PKD-ээс (эсвэл хоёр талын дипломат солилцоогоор) ирнэ. Master list-ийн өөрийнх нь гарын үсгийг сервер шалгадаггүй — файлыг найдвартай сувгаар авч, root-only эрхтэй байрлуулах нь операторын хариуцлага.

Клиент тал

Апп чипээс уншсан түүхий байтуудыг дамжуулна:

POST /v3/kyc/dan/passport-init
{
  "sod": "<base64 EF.SOD>",
  "dataGroups": { "1": "<base64 DG1>", "2": "<base64 DG2>" },
  "citizen": { … },        // зөвхөн лавлагаа — сервер үл тоомсорлоно
  "image": "<base64 JPEG>" // DG2 задлагдвал сервер өөрийнхийг ашиглана
}

GET /v3/kyc/methods нь passportRequiresSOD талбар буцаана — апп үүнийг хараад SOD-гүй чипийн уншилтыг эрт таслан ойлгомжтой алдаа харуулна.

Гаргалтын дараалал: сервер дээр SMARTID_KYC_PASSPORT_CSCA_DIR-ийг асаахаас ӨМНӨ SOD илгээдэг аппын хувилбар (iOS/Android) дэлгүүрт гарсан байх ёстой. Хуучин апп SOD илгээдэггүй тул шууд асаавал тэдгээрт паспортын бүртгэл 400 өгнө.

Хязгаар (одоогоор хийгдээгүй)

  • DS цуцлалт (CRL/OCSP) шалгадаггүй. Цуцлагдсан Document Signer-ээр гарын үсэглэсэн SOD гинжээр давна. Бүрэн шийдэлд ICAO PKD-ийн CRL-ийг татаж, DS-ийн сериалыг тулгах хэрэгтэй.
  • Active Authentication / Chip Authentication хийдэггүй — өөрөөр хэлбэл passive auth нь "чипийн агуулга жинхэнэ" гэдгийг нотолно, "энэ чип хуулбар биш" гэдгийг нотлохгүй (клон чип ижил SOD-ийг агуулж чадна). Liveness (селфи ↔ DG2) энэ эрсдэлийг бууруулна.
  • DG2 JPEG2000 бол сервер зургийг задалж чадахгүй, аппын зураг руу буцаж унана (identity-д нөлөөгүй — identity нь DG1-ээс).

Тест

  • server/internal/kyc/emrtd — синтетик CSCA→DS→SOD гинж угсарч 16 тохиолдол шалгана: жам ёсны зам, өөрчлөгдсөн DG1, итгэмжлэгдээгүй CSCA, anchor-гүй, хугацаа дууссан DS, өөрчлөгдсөн SOD, ECDSA/PSS/signedAttrs-гүй, BER indefinite, SHA-1 бодлого, MRZ TD1/TD3, check digit, DG2 зураг, итгэлийн сан ачаалалт.
  • server/internal/kyc/emrtd/eccurve_test.go — ерөнхий EC арифметик нь Go-ийн хэрэгжүүлэлттэй тааарч байгааг (P-256/P-384 гарын үсгийг хөндлөн шалгах), Brainpool 5 муруй дээр гарын үсэг зурж-шалгах round-trip, RFC 5639-ийн тогтмолуудын бүрэн бүтэн байдал (G муруй дээр, n·G = ∞).
  • Жинхэнэ ICAO жагсаалт дээрх шалгалт (файл нь T&C-тэй тул repo-д байхгүй):
ML_PATH="/зам/ICAO_ML_20260721154956.ml" \
  go test ./internal/kyc/emrtd/ -run RealMasterList -v

2026-07-21-ний жагсаалт: 581/581 задарсан, 581/581 гарын үсэг шалгагдсан — RSA-2048…6144, NIST P-256/384/521, brainpoolP256r1/P384r1/P512r1 (100 ширхэг). - server/internal/service/passport — base64 → citizen map хөрвүүлэлт, fail-closed зан төлөв. - server/internal/httpapi — бүтэн HTTP зам: худал citizen JSON илгээсэн ч identity нь чипээс гарахыг шалгана; SOD/DG дутуу, өөр хүний DG хольсон тохиолдол 400.