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

Gerege eID — идентификаторы (ETSI ID и регистрационный номер)

В системе есть два основных номера для идентификации человека или организации: ETSI-идентификатор (стандартный ключ в сертификате) и регистрационный номер (РД) (монгольский номер гражданина). Этот документ описывает их структуру и назначение.


1. ETSI-идентификатор — etsi_identifier

ETSI = European Telecommunications Standards Institute. Наш etsi_identifier — это «semantics identifier» по стандарту ETSI EN 319 412-1, то есть международный стандартный формат записи национального номера в сертификат. Он соответствует eIDAS и совместим на уровне протокола с semanticsIdentifier эстонского Smart-ID (мы его адаптировали).

Формат

PNOMN-95103015
└┬┘└┬┘ └───┬──┘
 │  │      └── сам номер (для физлица — civil_id, только цифры, не РД)
 │  └── страна — ISO 3166-1 alpha-2 (MN = Монголия)
 └── тип субъекта (3 символа)
Префикс Значение Владелец Пример
PNO Person Number (национальный персональный номер) физическое лицо (Natural Person) PNOMN-95103015
NTR National Trade Register организация (Legal Person) NTRMN-1234567

Зачем

  • Стабильный ключ: устройства / сертификаты / сессии каждого гражданина связываются именно этим ID (users.etsi_identifier — первичный ключ).
  • Соответствие стандартам: это принятый способ записи национального ID в квалифицированный eIDAS-сертификат; европейские RP его понимают.
  • Тип зашит в префиксе: PNONTR различают физлицо и организацию → используется для автоматического выбора выпускающего CA (domain.SubjectTypeForEtsi, Personal/Organization CA).
  • Внутреннее значение = civil_id (только цифры), а не РД: поле сертификата SERIALNUMBER — это X.509 PrintableString, поэтому оно не может содержать кириллический РД. Отсюда физлицо получает PNOMN-<civil_id> (etsi = "PNOMN-" + civilID); РД — отдельный атрибут в users, в сертификат он НЕ попадает.

В коде: persistence.UserAccount.EtsiIdentifier, domain.SubjectTypeForEtsi, формирование ETSI в crypto_wired.go ("PNOMN-" + civilID).


2. Регистрационный номер (РД) — registration_number

Регистрационный номер гражданина Монголии: 2 буквы кириллицы + 8 цифр (например, УБ95103015).

Структура (номинально)

У Б 9 5 1 0 3 0 1 5
└┬┘ └──────┬──────┘
 │         └── 8 цифр (номинально ГГММДД + порядковый номер)
 └── первые буквы имени отца и собственного имени (2)

Дата рождения и пол — источник и вывод из РД

date_of_birth и gender в первую очередь приходят напрямую от поставщика KYC (DAN/eMongolia) (service.KycResult.DateOfBirth, .Gender; из callback DAN через NormalizeGender).

Некоторые источники (G-Sign) их не возвращают — subject сертификата даёт только идентичность. В этом случае система выводит их из РД (util.BirthAndGenderFromRegNo, gsign/kycverifier.go): - Дата: первые 6 цифр = ГГММДД. Месяц 21..32 → после 2000 года (год 2000+ГГ, месяц ММ-20); месяц 01..12 → до 2000 года (год 1900+ГГ). Некорректная календарная дата → nil. - Пол: 2-я цифра с конца нечётная → "M", чётная → "F" (независимо от даты).

Если цифры отсутствуют или искажены, каждое значение остаётся пустым (nil/"") — пустое лучше, чем неверная догадка.


3. Другие связанные номера

Поле Описание Источник
civil_id Номер удостоверения личности гражданина (может не совпадать с РД) KYC (KycResult.CivilID)
Регистрационный номер организации Государственная регистрация юрлица → etsi NTRMN-<...>, organizationIdentifier (OID 2.5.4.97) KYC (KycResult.OrgRegister)
document_number Уникальный UUID каждого устройства (не содержит РД — приватность). Это documentNumber из Smart-ID генерируется сервером
certificates.serial_number Серийный номер X.509 (десятичный); в OCSP/CRL — шестнадцатеричный CA

Принцип: атрибуты идентичности гражданина/организации (civil_id, регистр организации, имя) всегда приходят от поставщика KYC (DAN/eMongolia) — их не выводят и не выдумывают из номеров. Если источник ничего не дал, значение остаётся пустым. (Дата рождения и пол обычно приходят из KYC, но если источник их не возвращает — выводятся из РД, см. §2.)


Итог

  • ETSI-идентификатор = «стандартный формат записи национального номера в сертификат» (PNOMN-… — физлицо, NTRMN-… — организация). Название непривычное, но смысл простой.
  • РД = номер гражданина вида «2 буквы + 8 цифр». Дата рождения и пол обычно приходят напрямую из источника KYC; иначе выводятся из РД (util.BirthAndGenderFromRegNo).

§Case — ПРАВИЛО регистра для текста идентичности

Правило: каноническая форма текста идентичности в БД — НИЖНИЙ РЕГИСТР; любой поиск, фильтрация и сравнение выполняются в нижнем регистре; отображение — в стандартной форме. Пользователь может вводить регистрационный номер в любом регистре.

Охваченные поля (текст идентичности, введённый человеком или полученный из KYC): users.registration_number (РД), civil_id, given_name, surname, full_name.

Действие Правило Реализация
Сохранение trim + lower (каноническая форма в нижнем регистре) util.NormalizeIdentity; recordUserAndCert; KYC normalizeRegNo=lower
Поиск / выборка / сравнение привести ввод к нижнему регистру, затем сравнивать (без учёта регистра) pg FindByIdentifier/Search reg_no → lower; inmem уже в lower; сопоставление в callback DAN lower-lower
Отображение РД → ВЕРХНИЙ РЕГИСТР (util.DisplayRegNo); имя на кириллице → Title Case (util.TitleCaseName) PersonBlock, PersonSummary, admin userView, предпросмотр KYC

НЕ охвачено (имеет собственную каноническую форму протокола/PKI — не трогать): - etsi_identifier — канон ETSI EN 319 412-1 (PNOMN-…/NTRMN-…); выборка/сравнение в ВЕРХНЕМ РЕГИСТРЕ. - SERIALNUMBER / subject DN сертификата, given_name_latin/surname_latin — ICAO/eIDAS ВЕРХНИЙ РЕГИСТР. - document_number (UUID), хеш API-ключа, org_register организации (цифры), name организации (имя собственное).

Почему: каждый источник KYC возвращает свой регистр (DAN «ЭРДЭНЭБАТ», G-Sign «баярсайхан»), а пользователь пишет РД как «УБ…» или «уб…». С единой канонической формой (нижний регистр) выборка и дедупликация работают последовательно; для отображения значение приводится к стандартной форме. У латиницы / etsi / сертификата собственный канон, поэтому это правило на них не распространяется.