КриптоПро УЦ 2.0 — Полная техническая документация¶
1. Требования к серверу¶
1.1. Программное обеспечение¶
| Компонент | Версия | Назначение |
|---|---|---|
| .NET | 9.0 x64 | Runtime бэкенда 1Формы |
| КриптоПро CSP | 5.0+ | Криптопровайдер ГОСТ (хранилище ключей, CAPI) |
| КриптоПро УЦ | 2.0 | REST API удостоверяющего центра |
| Windows Server | 2016+ | Хостинг IIS, хранилище сертификатов |
1.2. Сертификаты в хранилище Windows¶
В хранилище LocalMachine\My (или CurrentUser\My) должен быть установлен сертификат администратора УЦ с приватным ключом. Этот сертификат используется для:
- mTLS — клиентская аутентификация при HTTP-запросах к REST API УЦ
- PKCS#7 подпись — подписание запросов на выпуск/отзыв сертификатов (ГОСТ 34.10-2012)
Thumbprint этого сертификата записывается в поле Certificate таблицы CryptoProCertificationCenters.
1.3. Таблица CryptoProCertificationCenters¶
Создана миграцией v2.162. Содержит настройки подключения к УЦ.
| Поле | Тип | Описание |
|---|---|---|
Id |
int IDENTITY | PK, используется как raId во всех вызовах |
Name |
nvarchar(max) | Название УЦ (для отображения) |
Address |
nvarchar(max) | Базовый URL REST API УЦ, например https://ca.example.com |
UsersFolder |
nvarchar(max) | Папка для регистрации пользователей в УЦ |
Certificate |
nvarchar(max) | Thumbprint сертификата администратора (из хранилища Windows) |
Guid |
uniqueidentifier | Уникальный идентификатор записи |
Настройка: Администрирование → CryptoPro УЦ (через dbadmin-дерево).
1.4. Библиотека CryptoProCA в SmartScripts¶
Lua-библиотека CryptoProCA поставляется миграцией v2.264 (GUID: A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D). Вставляется в таблицу SmartScripts с IsLibrary = true.
1.5. Плагины ЭП на клиенте¶
Для операций, выполняемых в браузере (генерация CSR, установка сертификата): - КриптоПро ЭЦП Browser plug-in — работает через cadesplugin - Рутокен плагин — альтернативный вариант (PKCS#11)
Выбор плагина настраивается через настройки ЭП задачи (EdsPluginType).
2. Архитектура¶
┌─────────────────────────────────────────────────────────────┐
│ БРАУЗЕР │
│ │
│ Кнопка МТФ → JS: tcCryptoLogic.newRequest() │
│ tcCryptoLogic.installCertificate() │
│ tcCryptoLogic.signFiles() │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ CryptoPro ЭЦП │ │ Рутокен плагин │ │
│ │ Browser plug-in │ │ │ │
│ └─────────────────┘ └─────────────────┘ │
└────────────────────────────┬────────────────────────────────┘
│ HTTP API
┌────────────────────────────┼────────────────────────────────┐
│ СЕРВЕР 1Форма │
│ │
│ Lua скрипт (SmartScript) │
│ │ │
│ ├── include("...CryptoProCA...") ← Lua-библиотека │
│ │ └── CryptoProCA.issue_certificate(...) │
│ │ │
│ ├── CRYPTO:send_request() ← CryptoScriptApi (C#) │
│ │ └── CryptoRequestService.SendRequest() │
│ │ ├── mTLS (клиентский сертификат) │
│ │ └── PKCS#7 подпись через Win32 CAPI │
│ │ │
│ ├── CRYPTO:parse_cert() ← парсинг X509 │
│ └── CRYPTO:get_thumbprint() ← SHA-1 отпечаток │
│ │
│ ↓ HTTP/TLS 1.2 │
│ КриптоПро УЦ 2.0 REST API │
│ /api/ra/users │
│ /api/ra/certRequests │
│ /api/ra/certificates │
│ /api/ra/revRequests │
└─────────────────────────────────────────────────────────────┘
2.1. Слои¶
| Слой | Компонент | Ответственность |
|---|---|---|
| Lua | CryptoProCA (библиотека) |
Бизнес-логика: polling, обработка ошибок, чтение/запись ДП |
| C# API | CryptoScriptApi |
Мост Lua↔C#: конвертация LuaTable↔Dictionary, обход SEHException |
| C# сервис | CryptoRequestService |
HTTP-транспорт: mTLS, PKCS#7 подпись, логирование |
| JS/SPA | tcCryptoLogic (window global) |
Клиентские операции: генерация CSR, установка сертификата, подпись файлов |
3. Дополнительные параметры (ДП) на форме задачи¶
Для полного цикла работы с сертификатами нужны следующие ДП:
3.1. Обязательные ДП¶
| ДП | Тип | Заполняется | Описание |
|---|---|---|---|
| nameAttributes | Строка (JSON) | Вручную или скриптом | JSON с атрибутами субъекта сертификата. Формат: {"2.5.4.3":"Иванов Иван Иванович","1.2.643.3.131.1.1":"000000000000","2.5.4.6":"RU"} |
| userId УЦ | Строка | CryptoProCA.register_or_update_user() |
UUID пользователя в УЦ. Заполняется автоматически при первой регистрации, далее используется для обновления |
| PKCS#10 запрос | Строка (Base64) | tcCryptoLogic.newRequest() (браузер) |
CSR в формате Base64. Генерируется криптоплагином на клиенте |
| certRequestId | Строка | CryptoProCA.issue_certificate() |
UUID запроса на сертификат в УЦ. Заполняется автоматически |
| Сертификат | Строка (Base64) | CryptoProCA.issue_certificate() |
rawCertificate в Base64. Заполняется автоматически при выпуске |
| Thumbprint | Строка | CryptoProCA.get_thumbprint() |
SHA-1 отпечаток сертификата. Заполняется автоматически |
| Имя ЦС | Строка | Вручную (опционально) | authorityName — имя центра сертификации, если в УЦ их несколько |
3.2. OID-ы для nameAttributes¶
Важно: REST API КриптоПро УЦ 2.0 требует обязательное наличие полей Country (
2.5.4.6) и Locality (2.5.4.7) вnameAttributesпри регистрации пользователя (POST /api/ra/users). Без них запрос вернёт ошибку.
| OID | Атрибут | Обязательность | Пример значения |
|---|---|---|---|
2.5.4.3 |
CN (Common Name) | Обязательный | Иванов Иван Иванович |
2.5.4.6 |
C (Country) | Обязательный (REST API v2.0) | RU |
2.5.4.7 |
L (Locality) | Обязательный (REST API v2.0) | Москва |
2.5.4.4 |
SN (Surname) | Рекомендуемый | Иванов |
2.5.4.42 |
GN (Given Name) | Рекомендуемый | Иван Иванович |
2.5.4.8 |
ST (State) | Опционально | 77 Москва |
2.5.4.10 |
O (Organization) | Опционально | ООО "Компания" |
2.5.4.11 |
OU (Org Unit) | Опционально | Отдел разработки |
1.2.643.3.131.1.1 |
ИНН | Опционально | 000000000000 |
1.2.643.100.1 |
ОГРН | Опционально | 0000000000000 |
1.2.643.100.3 |
СНИЛС | Опционально | 00000000000 |
2.5.4.12 |
Title | Опционально | Генеральный директор |
1.2.840.113549.1.9.1 |
E (Email) | Опционально | user@example.com |
Минимальный JSON для nameAttributes:
{
"2.5.4.3": "Иванов Иван Иванович",
"2.5.4.6": "RU",
"2.5.4.7": "Москва"
}
Полный JSON (рекомендуемый):
{
"2.5.4.3": "Иванов Иван Иванович",
"2.5.4.4": "Иванов",
"2.5.4.42": "Иван Иванович",
"2.5.4.6": "RU",
"2.5.4.7": "Москва",
"2.5.4.8": "77 Москва",
"2.5.4.10": "ООО \"Компания\"",
"1.2.643.3.131.1.1": "000000000000",
"1.2.643.100.1": "0000000000000",
"1.2.643.100.3": "00000000000",
"1.2.840.113549.1.9.1": "user@example.com"
}
3.3. Формат атрибутов CSR для клиентской генерации (кнопка МТФ)¶
Поля Country и Locality также должны присутствовать в CSR-атрибутах, иначе сертификат не будет содержать эту информацию.
[
{"rdn": "commonName", "cpn": "CN", "value": "Иванов Иван Иванович"},
{"rdn": "country", "cpn": "C", "value": "RU"},
{"rdn": "localityName", "cpn": "L", "value": "Москва"},
{"rdn": "surname", "cpn": "SN", "value": "Иванов"},
{"rdn": "givenName", "cpn": "G", "value": "Иван Иванович"},
{"rdn": "organization", "cpn": "O", "value": "ООО Компания"},
{"rdn": "inn", "cpn": "1.2.643.3.131.1.1", "value": "000000000000"},
{"rdn": "snils", "cpn": "1.2.643.100.3", "value": "00000000000"}
]
rdn — имя атрибута для Рутокена
- cpn — имя атрибута для КриптоПро ЭЦП Browser plug-in
4. Справочник функций библиотеки CryptoProCA¶
Подключение:
include("[cryptopro] CryptoPro CA 2.0 — REST API library")илиinclude(ID)где ID — числовой идентификатор скрипта в SmartScripts. Бэкенд:Valhalla.Scripting/Engine/Api/CryptoScriptApi.cs,Valhalla.Scripting/Engine/Api/CryptoRequestService.cs
4.1. CryptoProCA.get_thumbprint¶
Получает SHA-1 Thumbprint сертификата, записывает в ДП и оставляет silent-комментарий.
Заменяет C#-смарт: 9d636137-2525-4d87-905c-018fe81f982c — «Get Thumbprint»
CryptoProCA.get_thumbprint(taskId, epCertificateId, epThumbprintId)
| # | Параметр | Тип | Обязательный | Описание |
|---|---|---|---|---|
| 1 | taskId |
number | да | ID задачи. Обычно CONTEXT.Id |
| 2 | epCertificateId |
number | да | ID ДП (тип «Строка»), содержащего сертификат в формате Base64 (rawCertificate) |
| 3 | epThumbprintId |
number | да | ID ДП (тип «Строка»), куда будет записан SHA-1 Thumbprint |
Возвращает: string — Thumbprint (SHA-1, hex, uppercase)
Побочные эффекты:
- Записывает Thumbprint в ДП epThumbprintId от имени системного робота
- Добавляет silent-комментарий в задачу: Thumbprint: ABC123...
Пример:
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
local tp = CryptoProCA.get_thumbprint(CONTEXT.Id, 503, 505)
-- tp = "A1B2C3D4E5F6..."
4.2. CryptoProCA.register_or_update_user¶
Регистрирует нового или обновляет существующего пользователя в УЦ.
Заменяет C#-смарт: dcc83d14-39bd-4779-9192-a4c21e0b1d7c — «CryptoPro CA - new or update user»
CryptoProCA.register_or_update_user(raId, taskId, epNameAttrsId, epToSaveUserId)
| # | Параметр | Тип | Обязательный | Описание |
|---|---|---|---|---|
| 1 | raId |
number | да | ID записи в таблице CryptoProCertificationCenters (настройки подключения к УЦ) |
| 2 | taskId |
number | да | ID задачи. Обычно CONTEXT.Id |
| 3 | epNameAttrsId |
number | да | ID ДП (тип «Строка») с JSON nameAttributes. Обязательные поля JSON: 2.5.4.3 (CN), 2.5.4.6 (Country), 2.5.4.7 (Locality) — см. раздел 3.2 |
| 4 | epToSaveUserId |
number | да | ID ДП (тип «Строка») для чтения/записи UUID пользователя в УЦ. Если пуст — создание, если заполнен — обновление |
Возвращает: string — UUID пользователя в УЦ
REST API вызовы:
- Создание: POST /api/ra/users с телом { nameAttributes: {...}, folder: "..." }
- Обновление: POST /api/ra/users/{userId} с телом { nameAttributes: {...} }
Пример:
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
-- ДП 200 содержит: {"2.5.4.3":"Иванов Иван","2.5.4.6":"RU","2.5.4.7":"Москва"}
-- ДП 201 пуст (новый пользователь) или содержит UUID (обновление)
local userId = CryptoProCA.register_or_update_user(1, CONTEXT.Id, 200, 201)
Отличие от старого C#-смарта:
| Старый | Новый | |
|---|---|---|
| Формат данных | XML (HtmlDecode) | JSON (nameAttributes) |
| Протокол | SOAP через RALogic.RegisterUserXml() |
REST POST /api/ra/users |
| Обязательные поля | CN | CN, Country, Locality |
4.3. CryptoProCA.issue_certificate¶
Выпуск сертификата: submit + accept через двойную подпись PKCS#7, polling, получение rawCertificate.
Заменяет C#-смарт: C872CA74-03ED-4C94-96B9-A5C8E4F5E1AE — «CryptoPro CA - Issue certificate»
CryptoProCA.issue_certificate(raId, taskId, epUserId, epRequestId,
epToSaveRequestId, epToSaveCertificateId, epAuthorityId, maxPollAttempts)
| # | Параметр | Тип | Обязательный | Описание |
|---|---|---|---|---|
| 1 | raId |
number | да | ID записи в CryptoProCertificationCenters |
| 2 | taskId |
number | да | ID задачи. Обычно CONTEXT.Id |
| 3 | epUserId |
number | да | ID ДП (тип «Строка») с UUID пользователя в УЦ (результат register_or_update_user) |
| 4 | epRequestId |
number | да | ID ДП (тип «Строка») с PKCS#10 запросом в Base64 (результат tcCryptoLogic.newRequest) |
| 5 | epToSaveRequestId |
number | да | ID ДП (тип «Строка») — сюда будет записан certRequestId (UUID запроса в УЦ) |
| 6 | epToSaveCertificateId |
number | да | ID ДП (тип «Строка») — сюда будет записан rawCertificate (Base64) |
| 7 | epAuthorityId |
number | да | ID ДП (тип «Строка») с именем центра сертификации (authorityName). Может быть пустым — если в УЦ один ЦС |
| 8 | maxPollAttempts |
number | нет | Количество попыток polling (по умолчанию 10). Каждая попытка = пауза 2 сек + GET-запрос |
Возвращает: LuaTable — полный объект сертификата из УЦ (содержит rawCertificate, id, status и др.)
REST API вызовы (последовательно):
1. POST /api/ra/certRequests — submit + accept, двойная PKCS#7 подпись
2. GET /api/ra/certificates?certRequestId=... — polling (до maxPollAttempts раз)
3. GET /api/ra/certificates/{id} — полная форма с rawCertificate
Пример:
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.issue_certificate(
1, -- raId
CONTEXT.Id, -- taskId
500, -- ДП: userId в УЦ
501, -- ДП: PKCS#10 запрос
502, -- ДП: certRequestId (запись)
503, -- ДП: rawCertificate (запись)
504 -- ДП: имя ЦС (может быть пустым)
)
Отличие от старого C#-смарта:
| Старый | Новый | |
|---|---|---|
| Протокол | SOAP RALogic.IssueCertificate() |
REST POST /api/ra/certRequests |
| Подпись | X509Certificate2.SignData() |
Win32 CAPI CryptSignMessage (ГОСТ) |
| Ожидание | Синхронно (внутри COM) | Polling (2сек × N попыток) |
| PEM-заголовки | Не обрабатывает | Автоматически удаляет -----BEGIN/END...----- |
4.4. CryptoProCA.revoke_certificate¶
Отзыв сертификата через REST API с двойной подписью.
Заменяет C#-смарт: bc2c3efa-1295-4eda-8542-1cc543fe3cbb — «CryptoPro CA - revoke certificate»
CryptoProCA.revoke_certificate(raId, taskId, epCertificateId, revocationReason, fromTimestamp)
| # | Параметр | Тип | Обязательный | Описание |
|---|---|---|---|---|
| 1 | raId |
number | да | ID записи в CryptoProCertificationCenters |
| 2 | taskId |
number | да | ID задачи. Обычно CONTEXT.Id |
| 3 | epCertificateId |
number | да | ID ДП (тип «Строка») с сертификатом в Base64 |
| 4 | revocationReason |
number | нет | Код причины отзыва (0–5, по умолчанию 0). См. таблицу ниже |
| 5 | fromTimestamp |
number|nil | нет | Unix timestamp даты начала отзыва. Если > текущего времени — отложенный отзыв с RD=yyyy-MM-ddTHH:mm:ss |
Возвращает: string — серийный номер отозванного сертификата
REST API вызов:
- POST /api/ra/revRequests — двойная PKCS#7 подпись, кодировка UTF-16LE без BOM
Коды причин отзыва:
| Код | Константа | Описание |
|---|---|---|
| 0 | Unspecified | Не указана |
| 1 | KeyCompromise | Компрометация ключа |
| 2 | CACompromise | Компрометация УЦ |
| 3 | AffiliationChanged | Изменение принадлежности |
| 4 | Superseded | Замена (выпущен новый) |
| 5 | CessationOfOperation | Прекращение деятельности |
Пример:
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
-- Немедленный отзыв по причине "Замена"
local sn = CryptoProCA.revoke_certificate(1, CONTEXT.Id, 503, 4)
-- Отложенный отзыв (с 01.02.2027)
CryptoProCA.revoke_certificate(1, CONTEXT.Id, 503, 0, 1801526400)
Отличие от старого C#-смарта:
| Старый | Новый | |
|---|---|---|
| Протокол | SOAP RALogic.RevokeCertificate() |
REST POST /api/ra/revRequests |
| Причина отзыва | C# enum RevocationReason |
Числовой код 0–5 |
| Кодировка подписи | Определяется COM | UTF-16LE без BOM (явно) |
| Формат даты | DateTime |
Unix timestamp → ISO 8601 (24-часовой формат, исправлен баг hh→HH) |
4.5. CryptoProCA.pause_certificate¶
Приостановка сертификата. SOAP fallback — REST API КриптоПро УЦ 2.0 не поддерживает RR=6.
Заменяет C#-смарт: af7d2931-1f04-4731-aa59-52589e8cd969 — «CryptoPro CA - pause certificate»
CryptoProCA.pause_certificate(taskId, raId, epCertificateId, fromTimestamp, toTimestamp, revocationReason)
| # | Параметр | Тип | Обязательный | Описание |
|---|---|---|---|---|
| 1 | taskId |
number | да | ID задачи. Обычно CONTEXT.Id |
| 2 | raId |
number | да | ID записи в CryptoProCertificationCenters |
| 3 | epCertificateId |
number | да | ID ДП (тип «Строка») с сертификатом в Base64 |
| 4 | fromTimestamp |
number | да | Unix timestamp даты начала приостановки |
| 5 | toTimestamp |
number | да | Unix timestamp даты окончания приостановки |
| 6 | revocationReason |
number | да | Код причины (обычно 6 — CertificateHold) |
Реализация: делегирует в старый C#-смарт через SMART:execute_action("af7d2931-...", ...). Когда REST API добавит поддержку — будет переписана на REST без изменения сигнатуры.
Пример:
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
-- Приостановить на месяц
CryptoProCA.pause_certificate(CONTEXT.Id, 1, 503, 1780000000, 1782000000, 6)
4.6. CryptoProCA.resume_certificate¶
Возобновление приостановленного сертификата. SOAP fallback — REST API не поддерживает RR=8.
Заменяет C#-смарт: b1e6bdf5-0c99-4d7e-97f2-312330828ed2 — «CryptoPro CA - resume certificate»
CryptoProCA.resume_certificate(taskId, raId, epCertificateId)
| # | Параметр | Тип | Обязательный | Описание |
|---|---|---|---|---|
| 1 | taskId |
number | да | ID задачи. Обычно CONTEXT.Id |
| 2 | raId |
number | да | ID записи в CryptoProCertificationCenters |
| 3 | epCertificateId |
number | да | ID ДП (тип «Строка») с сертификатом в Base64 |
Реализация: делегирует в старый C#-смарт через SMART:execute_action("b1e6bdf5-...", ...).
Пример:
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.resume_certificate(CONTEXT.Id, 1, 503)
5. Справочник низкоуровневых C#-функций CRYPTO:*¶
Эти функции доступны в Lua без подключения библиотеки — они зарегистрированы в LuaScriptEngine как глобальный объект CRYPTO.
Исходный код:
Valhalla.Scripting/Engine/Api/CryptoScriptApi.cs
5.1. CRYPTO:send_request¶
Отправка HTTP-запроса к REST API УЦ с mTLS и опциональной PKCS#7 подписью.
local resp = CRYPTO:send_request(raId, method, path, query, body, options, taskId)
| # | Параметр | Тип | Обязательный | Описание |
|---|---|---|---|---|
| 1 | raId |
number | да | ID записи в CryptoProCertificationCenters |
| 2 | method |
string | да | HTTP-метод: "GET" или "POST" |
| 3 | path |
string | да | Путь API (должен начинаться с /api/ra/), например /api/ra/users |
| 4 | query |
string|nil | нет | Query string без ?, например "certRequestId=abc-123" |
| 5 | body |
LuaTable|nil | нет | Тело POST-запроса (конвертируется в JSON). nil для GET |
| 6 | options |
LuaTable|nil | нет | Опции подписи и таймаута (см. ниже) |
| 7 | taskId |
number|nil | нет | ID задачи (для логирования в AutomationScriptsLog) |
Поля options:
| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
sign |
boolean | false |
Подписать поле rawRequest в body PKCS#7 |
signMode |
string | "submitAndAccept" |
"submitAndAccept" — двойная подпись, "submit"/"approve" — одинарная |
encoding |
string | nil |
"utf16le" — кодировать строку UTF-16LE перед подписью. nil — Base64→бинарные данные |
timeoutMs |
number | 30000 |
Таймаут HTTP-запроса в миллисекундах |
Возвращает: LuaTable с полями:
| Поле | Тип | Описание |
|---|---|---|
StatusCode |
number | HTTP-код ответа (200, 201, 400, 500...) |
Body |
string|nil | Тело ответа (raw string) |
Error |
string|nil | Сообщение об ошибке (nil при успехе). Формат: "ExceptionType: message" |
При ошибке HTTP-транспорта (timeout, connection refused) исключение ловится внутри C# и возвращается в
Error— это обход бага NLua/.NET 9 x64 (SEHException).
5.2. CRYPTO:parse_cert¶
Парсинг Base64-сертификата с извлечением основных полей.
local info = CRYPTO:parse_cert(certBase64)
Возвращает: LuaTable с полями:
| Поле | Тип | Описание |
|---|---|---|
serialNumber |
string | Серийный номер |
thumbprint |
string | SHA-1 отпечаток (hex, uppercase) |
subject |
string | DN субъекта |
issuer |
string | DN издателя |
notBefore |
string | Дата начала действия (yyyy-MM-ddTHH:mm:ss) |
notAfter |
string | Дата окончания действия (yyyy-MM-ddTHH:mm:ss) |
5.3. CRYPTO:get_thumbprint¶
local tp = CRYPTO:get_thumbprint(certBase64)
Возвращает: string — Thumbprint (SHA-1, hex, uppercase)
6. Процесс выпуска сертификата (полный цикл)¶
Шаг 1. Регистрация пользователя в УЦ¶
Кто выполняет: серверный Lua-скрипт (смарт-действие на шаге маршрута)
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.register_or_update_user(raId, CONTEXT.Id, epNameAttrsId, epToSaveUserId)
Что происходит:
1. Читает JSON из ДП epNameAttrsId (обязательно: CN, Country, Locality)
2. Если ДП epToSaveUserId пуст — POST /api/ra/users (создание, подставляет UsersFolder из настроек УЦ)
3. Если ДП epToSaveUserId заполнен — POST /api/ra/users/{userId} (обновление атрибутов)
4. Сохраняет UUID пользователя в ДП
Шаг 2. Генерация CSR (запроса на сертификат)¶
Кто выполняет: браузер пользователя (кнопка на МТФ)
window.tcCryptoLogic.newRequest(CONTEXT.taskId, EP_ATTRS_ID, EP_CSR_SAVE_ID, {})
Что происходит (на клиенте): 1. Определяет тип плагина (CryptoPro / RuToken) через настройки ЭП задачи 2. Считывает атрибуты из ДП (JSON-массив, формат см. раздел 3.3) 3. Генерирует ключевую пару на клиенте 4. Формирует PKCS#10 (CSR) в Base64 5. Записывает CSR в ДП
Шаг 3. Выпуск сертификата в УЦ¶
Кто выполняет: серверный Lua-скрипт
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.issue_certificate(raId, CONTEXT.Id, epUserId, epRequestId,
epToSaveRequestId, epToSaveCertificateId, epAuthorityId)
Что происходит:
1. Считывает userId и PKCS#10 из ДП
2. Удаляет PEM-заголовки из PKCS#10
3. POST /api/ra/certRequests с двойной PKCS#7 подписью
4. Сохраняет certRequestId в ДП
5. Polling GET /api/ra/certificates?certRequestId=... (до 10 попыток × 2 сек)
6. GET /api/ra/certificates/{id} — полная форма с rawCertificate
7. Сохраняет rawCertificate в ДП
Шаг 4. Установка сертификата на клиенте¶
Кто выполняет: браузер пользователя (кнопка на МТФ)
window.tcCryptoLogic.installCertificate(CONTEXT.taskId, EP_CERTIFICATE_ID)
Что происходит (на клиенте):
1. Считывает Base64-сертификат из ДП
2. Устанавливает через криптоплагин (CX509Enrollment.InstallResponse)
3. Сертификат привязывается к ключевой паре
Шаг 5. Получение Thumbprint (опционально)¶
Кто выполняет: серверный Lua-скрипт
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.get_thumbprint(CONTEXT.Id, epCertificateId, epThumbprintId)
7. Отзыв и управление жизненным циклом¶
Отзыв (Revoke)¶
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.revoke_certificate(raId, CONTEXT.Id, epCertificateId, revocationReason)
-- или с отложенной датой:
CryptoProCA.revoke_certificate(raId, CONTEXT.Id, epCertificateId, 0, fromTimestamp)
Приостановка (Pause) — SOAP fallback¶
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.pause_certificate(CONTEXT.Id, raId, epCertificateId, fromTs, toTs, 6)
Возобновление (Resume) — SOAP fallback¶
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.resume_certificate(CONTEXT.Id, raId, epCertificateId)
8. Настройка кнопок на МТФ¶
Кнопки МТФ вызывают функции через глобальный объект window.tcCryptoLogic, зарегистрированный в register-crypto-global.ts. Объект делегирует вызовы в Angular-сервис TcCryptoLogicService.
8.1. Кнопка «Сформировать запрос на сертификат»¶
window.tcCryptoLogic.newRequest(CONTEXT.taskId, EP_ATTRS_ID, EP_CSR_SAVE_ID, {})
EP_ATTRS_ID— ID ДП с JSON-массивом атрибутов (формат раздел 3.3)EP_CSR_SAVE_ID— ID ДП, куда записывается PKCS#10 (Base64)- Четвёртый параметр опционально принимает
{ extParamsId: { ContainerName: EP_CONTAINER_ID } }
8.2. Кнопка «Установить сертификат»¶
window.tcCryptoLogic.installCertificate(CONTEXT.taskId, EP_CERTIFICATE_ID)
EP_CERTIFICATE_ID— ID ДП с Base64-сертификатом (rawCertificate)- Требует: плагин КриптоПро ЭЦП Browser plug-in
8.3. Кнопка «Сменить PIN»¶
window.tcCryptoLogic.changePin(EP_THUMBPRINT_ID, { taskId: CONTEXT.taskId })
9. Типовой маршрут и примеры скриптов¶
9.1. Структура маршрута¶
[Шаг 1: Заполнение данных]
↓ Смарт при переходе: CryptoProCA.register_or_update_user(...)
[Шаг 2: Генерация запроса]
Кнопка МТФ: tcCryptoLogic.newRequest(...)
↓
[Шаг 3: Выпуск сертификата]
Смарт при переходе: CryptoProCA.issue_certificate(...)
↓
[Шаг 4: Установка и использование]
Кнопка МТФ: tcCryptoLogic.installCertificate(...)
Смарт при переходе: CryptoProCA.get_thumbprint(...)
9.2. Полный скрипт выпуска¶
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
local raId = 1 -- ID УЦ из CryptoProCertificationCenters
local taskId = CONTEXT.Id
local epUserId = 500 -- ДП: userId в УЦ
local epRequestId = 501 -- ДП: PKCS#10 запрос (Base64)
local epToSaveRequestId = 502 -- ДП: certRequestId (для записи)
local epToSaveCertificateId = 503 -- ДП: rawCertificate (для записи)
local epAuthorityId = 504 -- ДП: имя ЦС (может быть пустым)
CryptoProCA.issue_certificate(
raId, taskId,
epUserId, epRequestId,
epToSaveRequestId, epToSaveCertificateId,
epAuthorityId
)
9.3. Скрипт отзыва¶
include("[cryptopro] CryptoPro CA 2.0 — REST API library")
CryptoProCA.revoke_certificate(1, CONTEXT.Id, 503, 4) -- Superseded
10. Подпись PKCS#7 — техническая реализация¶
10.1. Алгоритм¶
- Попытка через
System.Security.Cryptography.Pkcs.SignedCms - При
CryptographicException(ГОСТ-ключи на .NET 9) — fallback на Win32 CAPI P/Invoke
10.2. Win32 CAPI P/Invoke¶
CertOpenStore → CertFindCertificateInStore → CryptAcquireCertificatePrivateKey → CryptSignMessage
| Сигнатурный OID | Хеш OID | Алгоритм |
|---|---|---|
| 1.2.643.7.1.1.3.2 | 1.2.643.7.1.1.2.2 | ГОСТ 34.10-2012 (256) → Стрибог-256 |
| 1.2.643.7.1.1.3.3 | 1.2.643.7.1.1.2.3 | ГОСТ 34.10-2012 (512) → Стрибог-512 |
| 1.2.643.2.2.3 | 1.2.643.2.2.9 | ГОСТ 34.10-2001 → ГОСТ 34.11-94 |
10.3. Режимы подписи (signMode)¶
| Режим | Описание | Применение |
|---|---|---|
submitAndAccept |
Двойная подпись: Sign(Sign(content)) | Выпуск сертификата, отзыв |
submit / approve |
Одинарная подпись | Если нужен только submit |
11. Логирование¶
Все запросы к REST API логируются в таблицу AutomationScriptsLog:
| Поле | Значение |
|---|---|
ObjectKey |
CRYPTO |
ObjectName |
POST /api/ra/certRequests, GET /api/ra/certificates и т.д. |
ObjectParams |
Тело запроса (усечено до 500 символов) |
AdditionalInfo |
HTTP 201: ... или ERROR: сообщение (ответ усечён до 4000 символов) |
TaskId |
ID задачи (если передан) |
Duration |
Время запроса в мс |
Фильтр для просмотра: ObjectKey = 'CRYPTO'
12. Сопоставление старых и новых смарт-действий¶
| # | Старое C#-действие | GUID | Новая Lua-функция | Протокол |
|---|---|---|---|---|
| 1 | Get Thumbprint | 9d636137-... |
CryptoProCA.get_thumbprint() |
Локальный X509 |
| 2 | CryptoPro CA - new or update user | dcc83d14-... |
CryptoProCA.register_or_update_user() |
REST API |
| 3 | CryptoPro CA - Issue certificate | C872CA74-... |
CryptoProCA.issue_certificate() |
REST API |
| 4 | CryptoPro CA - revoke certificate | bc2c3efa-... |
CryptoProCA.revoke_certificate() |
REST API |
| 5 | CryptoPro CA - pause certificate | af7d2931-... |
CryptoProCA.pause_certificate() |
SOAP fallback |
| 6 | CryptoPro CA - resume certificate | b1e6bdf5-... |
CryptoProCA.resume_certificate() |
SOAP fallback |
Ключевые отличия от старых смартов:
- Протокол: SOAP/COM → REST API + Win32 CAPI для подписи ГОСТ
- Формат данных пользователя: XML → JSON
- Запись в ДП: ExtParamValueEntityService.Update() → SMART:execute_action("ChangeExtParamValue") от имени системного робота
- Обработка ошибок: исключение → поле resp.Error (обход SEHException в NLua/.NET 9)
13. Известные ограничения (.NET 9 / NLua)¶
| Проблема | Обходное решение |
|---|---|
| NLua/.NET 9 x64: SEHException теряет оригинальное исключение | CRYPTO:send_request() ловит исключение внутри C# и возвращает в resp.Error |
UTILS:json_decode() падает на простых JSON-строках ("uuid") |
UUID из Body извлекается через resp.Body:gsub('"', '') |
SQL:scalar("...", nil) вызывает SEHException |
Всегда передавать {} вторым параметром |
os.clock() возвращает CPU-время процесса IIS (тысячи секунд) |
Для пауз используется os.time() (wall-clock) |
X509Certificate2.GetRSAPrivateKey() не работает с ГОСТ |
Win32 CAPI P/Invoke (CryptSignMessage) |
| REST API не поддерживает RR=6 (CertificateHold) | SOAP fallback через старый C#-смарт |
| REST API не поддерживает RR=8 (RemoveFromCrl) | SOAP fallback через старый C#-смарт |
14. Файлы реализации¶
| Файл | Назначение |
|---|---|
Valhalla.Scripting/Engine/Api/CryptoRequestService.cs |
HTTP-транспорт + PKCS#7 подпись |
Valhalla.Scripting/Engine/Api/CryptoScriptApi.cs |
Lua-обёртка CRYPTO:* |
TCClassLib/Smart/Scripting/Engine/Api/LibraryScriptApi.cs |
include() по ID или Description |
Valhalla.CryptoPro.CA/CaSmartActions.cs |
Старые C#-смарты (SOAP, для fallback) |
spa/api/crypto/register-crypto-global.ts |
Регистрация tcCryptoLogic в window |
spa/common/features/resolutions/eds-resolutions/tcCryptoLogic.service.ts |
Сервис tcCryptoLogic |
spa/common/features/resolutions/eds-resolutions/services/cryptopro.service.ts |
Прокси КриптоПро ЭЦП |
Миграция MSSQL: _nakat/DBMigrations/scripts/1Forma/v2.264/1775049532.2060173-*.sql |
SmartScript с библиотекой |
Миграция PG: _nakat/DBMigrations/scripts/1Forma_pg/v2.264/1775049532.2060173-*.pgsql |
SmartScript с библиотекой |