Перейти к содержанию

Gerege eID — подключение к национальному CA (L1 CSR → цепочка)

По закону Gerege обязан выстраивать цепочку до национального корневого CA — то есть быть подчинённым CA, а не самостоятельным корнем. Итоговая иерархия:

Национальный корневой CA (государственный HSM)
  └── Gerege CA  (L1)  — национальный корень подписывает ТОЛЬКО его;  pathlen:1
        ├── Gerege Personal Issuing CA      (L2, pathlen:0) → сертификат физического лица
        └── Gerege Organization Issuing CA  (L2, pathlen:0) → сертификат юридического лица

Терминология eIDAS: Personal = Natural Person, Organization = Legal Person. Два отдельных выпускающих CA уровня L2 под L1 (разделены по назначению/политике) — проверено на реальном HSM (TestHSMProxyDualIssuingCA).

1. L1 CSR — содержимое (проверено на реальном HSM)

TestPrepareL1CSR в internal/crypto формирует L1 CSR ключом HSM (PoP):

Subject:             C=MN, O=Gerege Systems LLC, CN=Gerege eID CA
Public-Key:          RSA-2048  (церемония — июль 2048; 4096 примерно годом позже)
Requested Extensions:
  Basic Constraints: critical, CA:TRUE, pathlen:1     ← ОБЯЗАТЕЛЬНО для 2-уровневой схемы (L1→L2)
  Key Usage:         critical, Certificate Sign, CRL Sign
Signature:           sha256WithRSAEncryption  (проверка proof-of-possession OK)

Приведите Subject DN в соответствие с правилами именования национального CA (они могут требовать конкретные O/CN/organizationIdentifier). Приведённое выше — рекомендация.

2. (!) Что необходимо получить ПИСЬМЕННО от национального CA

Пункт Зачем
pathLenConstraint ≥ 1 Значение pathlen в итоговом сертификате L1 определяет национальный корень (CSR лишь запрашивает). Если будет 0, Gerege не сможет выпускать L2 → двухуровневая схема НЕ РАБОТАЕТ. Зафиксируйте это в соглашении о подчинённом CA.
Алгоритм / размер ключа RSA-2048 (сейчас) — должен быть совместим с их церемонией/CP-CPS
Срок действия L1 короче корневого
Правила DN / именования O/CN/organizationIdentifier
Правила CRL/OCSP Куда указывают URL AIA/CDP

3. КОГДА генерировать настоящий CSR

Настоящий ключ L1 генерируется на официальной церемонии ключей (июль, RSA-2048) с M-of-N хранителями, tamper-пакетами и свидетелями — hsm-thales-gerege/docs/eid-issuing-ca-key-ceremony-script.md. Демо-ключ использовать нельзя. Во время церемонии CSR формируется одним из двух способов:

A. Go (hsm-proxy, этот репозиторий): по метке ключа, созданного на церемонии,

HSMPROXY_E2E_URL=https://<proxy>:8443 HSMPROXY_E2E_CERT=admin.crt HSMPROXY_E2E_KEY=admin.key \
CSR_OUT=gerege-l1.csr  go test ./internal/crypto -run TestPrepareL1CSR -v
# (измените тест так, чтобы метка соответствовала ключу церемонии; ВНИМАНИЕ: демо удаляет ключ)

B. Нативный Luna (cmu, совместим со сценарием церемонии):

cmu requestcertificate -slot <issuing> -lco \
    -publichandle <ph> -privatehandle <prh> \
    -sha256withrsa -outputfile gerege-l1.csr \
    -cn "Gerege eID CA" -o "Gerege Systems LLC" -c MN

cmu не помещает расширения в CSR — pathlen/keyUsage национальный корень выставляет по договорённости.

4. После получения сертификата L1

  1. Импортируйте сертификат L1, подписанный национальным корнем, в HSM Gerege (сертификат публичный, это безопасно).
  2. Внутри Gerege создайте два отдельных выпускающих CA уровня L2 (каждый подписан L1):
  3. Personal (Natural Person) — метка ключа, например gerege-personal-issuing-ca
  4. Organization (Legal Person) — метка ключа, например gerege-org-issuing-ca У каждого pathlen:0. В листовом сертификате организации — organizationIdentifier (OID 2.5.4.97, например NTRMN-<регистр>).
  5. Конфигурация Go-сервера (один сервер загружает оба выпускающих CA одновременно):
  6. SMARTID_PKI_CA_PROVIDER=hsmproxy
  7. Personal: SMARTID_HSMPROXY_KEY_LABEL=<ключ Personal L2>, SMARTID_HSMPROXY_ISSUING_CERT=<сертификат Personal L2>
  8. Organization (опционально): SMARTID_HSMPROXY_ORG_KEY_LABEL=<ключ Org L2>, SMARTID_HSMPROXY_ORG_ISSUING_CERT=<сертификат Org L2>
  9. Автоматический выбор: по префиксу ETSI — PNOMN-… → Personal CA, NTRMN-… → Organization CA (domain.SubjectTypeForEtsi + store.caFor). Если Org не сконфигурирован, происходит fallback на Personal.
  10. к листовому сертификату прикрепляется полная цепочка (L2+L1); якорь доверия = национальный корень.

Проверено на реальном HSM: - TestHSMProxy3LayerChain — национальный корень → L1 (pathlen:1) → L2 (pathlen:0) → лист. - TestHSMProxyDualIssuingCA — L1 → {Personal, Organization} issuing CA → два листа, обе цепочки проверяются успешно.

Failover на Cloud HSM (автоматическое переключение при отказе on-prem Luna)

Чтобы регистрация и печать не останавливались при обрыве сессии on-prem Luna (slot ... not found / CKR_SESSION_HANDLE_INVALID), можно настроить резервный hsm-proxy (за Thales DPoD Luna Cloud HSM). Тот же ключ CA (с той же меткой) должен быть склонирован в раздел DPoD через backup/restore (конфигурация раздела должна совпадать с prodpart1 — hsm-thales-gerege/docs/ceremony-rehearsal-results.md).

SMARTID_HSMPROXY_FALLBACK_URL=https://<dpod-proxy>:8443     # hsm-proxy на базе Cloud HSM
SMARTID_HSMPROXY_FALLBACK_CLIENT_CERT=/app/hsmproxy/dpod-client.crt  # если пусто, берётся от primary
SMARTID_HSMPROXY_FALLBACK_CLIENT_KEY=/app/hsmproxy/dpod-client.key
SMARTID_HSMPROXY_FALLBACK_SERVER_CA=/app/hsmproxy/dpod-proxy-ca.crt
SMARTID_HSMPROXY_PREFER=primary   # "fallback" ставит Cloud НА ПЕРВОЕ место (on-prem выбирается как резерв вручную)
  • Поведение: если primary недоступен или возвращает 5xx (slot/session) → автоматический переход на fallback; при 4xx (неверная метка) failover не выполняется. Подпись проверяется публичным ключом сертификата выпускающего CA (fallback с неверным ключом → fail-closed). Правило одинаково действует для Personal и Organization issuing CA, а также для клиента e-Seal.
  • Ручное переключение: SMARTID_HSMPROXY_PREFER=fallback (с перезапуском) — делает Cloud основным.
  • Тесты: TestHSMProxyFailover_* (IssuingCA/PreferFallback/BothDown/4xxNoFailover/SealClientEC).

Включение Organization issuing CA в продакшене (на этапе БЕЗ национального корня)

Текущий продуктивный Personal CA (eidmongol-issuing-ca-v1) самоподписан (национальный L1 ещё не существует). Organization CA настраивается так же — новый ключ + самоподписанный сертификат в HSM:

  1. На хосте HSM (церемония — hsm-thales-gerege/docs/eid-issuing-ca-key-ceremony-script.md):
    cmu generatekeypair -slot <issuing> -lco \
        -keytype rsa -modulusbits 4096 -publicexponent 65537 -mech prime \
        -labelpublic "eidmongol-org-issuing-ca-v1" -labelprivate "eidmongol-org-issuing-ca-v1" \
        -sign 1 -verify 1 -encrypt 0 -decrypt 0 -wrap 0 -unwrap 0 -derive 0
    
    (метки public/private ОДИНАКОВЫ — hsm-proxy ищет по метке; соблюдайте соглашение ключа Personal.)
  2. Выпустите сертификат удалённо с хоста приложения (возвращаться на хост HSM не нужно) — cmd/hsmca-selfsign создаёт самоподписанный сертификат CA через /pubkey и /sign-digest прокси:
    hsmca-selfsign -url https://hsm-proxy:8443 -label eidmongol-org-issuing-ca-v1 \
      -client-cert client.crt -client-key client.key -server-ca proxy-ca.crt \
      -subject "CN=eID Mongolia Organization Issuing CA, O=Gerege, C=MN" \
      -years 20 -out org-issuing-ca.crt        # в deploy/secrets/hsmproxy/
    
  3. .env (хост приложения): SMARTID_HSMPROXY_ORG_KEY_LABEL=eidmongol-org-issuing-ca-v1, SMARTID_HSMPROXY_ORG_ISSUING_CERT=/app/hsmproxy/org-issuing-ca.crtdocker compose up -d app.
  4. Проверка: в логе запуска «HSM-proxy Organization CA enabled», GET /crl/org возвращает 200, а при выпуске сертификата печати из админки издателем указан Organization CA.

Позже, когда национальный корень будет готов, оба CA будут переподписаны L1 (см. §2 выше).

Превращение e-Seal в QSCD (листовой ключ печати в HSM)

По умолчанию листовой ключ e-Seal генерируется на сервере (программный HSM, AES-GCM в БД), поэтому его уровень — QUALIFIED. Чтобы получить настоящий QSCD (QcSSCD + политика QCP-l-qscd), каждый ключ печати должен оставаться внутри HSM, а закрытый ключ никогда не должен попадать на сервер. Модель та же, что и у выпускающего CA: ключ создаётся на HSM в ходе церемонии, а сервер работает только через /pubkey и /sign-digest.

Модель: e-Seal — это управляемая (контрактная) услуга, как у SK: оператор проводит отдельную церемонию ключей HSM для каждой организации (организация сама ключ печати не создаёт).

  1. На хосте HSM (для каждой организации, EC P-256): метка = <префикс><регистрационный код> (префикс по умолчанию eseal-; например, регистр 1234567 → eseal-1234567):
    cmu generatekeypair -slot <issuing> -lco \
        -keytype ec -curve prime256v1 \
        -labelpublic "eseal-1234567" -labelprivate "eseal-1234567" \
        -sign 1 -verify 1 -encrypt 0 -decrypt 0 -wrap 0 -unwrap 0 -derive 0
    
    (метки public/private ОДИНАКОВЫ; hsm-proxy ищет по метке. Префикс меняется через SMARTID_SEAL_KEY_PREFIX.)
  2. .env (хост приложения): SMARTID_SEAL_QSCD=true (CA-провайдер hsmproxy и учётные данные HSMPROXY должны быть уже настроены — иначе сервер выполнит fail-fast и остановится, чтобы не объявлять QSCD ложно). Если префикс другой — SMARTID_SEAL_KEY_PREFIX=eseal-.
  3. Выпуск сертификата печати (админ или RP): сервер получает публичный ключ метки eseal-<код> этой организации через /pubkey и выпускает сертификат через Organization CA. Закрытый ключ остаётся в HSM.
  4. Проставление печати: POST /v3/seal/{orgEtsi} — сервер подписывает дайджест через /sign-digest (ключ HSM) и возвращает подпись, проверенную публичным ключом сертификата.
  5. Проверка: у сертификата печати certificateLevel=QSCD; на экране «Organization CA» в админке — «QSCD (QcSSCD + QCP-l-qscd)»; в openssl x509 — statement QcSSCD и политика 0.4.0.194112.1.3.

Если попытаться выпустить сертификат печати для организации, для которой церемония НЕ проводилась, сервер получит от /pubkey ответ 404 и вернёт ошибку (fail-closed) — он не станет молча переключаться на программный ключ, объявляя при этом QSCD.