CleanSign API

Справочник · v1

CleanSign API

REST-API сервиса CleanSign для проверки электронных подписей (ЭП/ЭЦП). Принимает документы и файлы подписи через multipart/form-data, возвращает JSON со сведениями о подписантах, цепочкой сертификатов и классификацией подписи. Использует тот же движок проверки, что и веб-форма на главной странице. Подходит для пакетной обработки документов и мониторинга срока действия сертификатов; готовых коннекторов к учётным системам и операторам ЭДО сервис не поставляет — встраивание выполняется на стороне клиента.

Базовый URL: https://api.cleanvoice.ru/cleansign/api/v1.

Какие проверки выполняются

  • Соответствие хеша документа подписанному атрибуту messageDigest — отсекает подмену подписанного содержимого.
  • Криптографическая проверка подписи (ГОСТ Р 34.10-2012, RSA, ECDSA).
  • Построение цепочки сертификатов до закреплённого trust-anchor (ГУЦ Минцифры) в режиме fail-closed.
  • Проверка привязки signingCertificateV2 (RFC 5126), исключающая подмену сертификата подписанта.
  • Проверка аккредитации УЦ-эмитента в реестре Минцифры на текущий момент и на момент подписания.
  • Опционально: проверки OCSP и CRL, верификация контр-подписей и меток времени CAdES (профили BES — A).
  • Классификация подписи по 63-ФЗ — КЭП (она же УКЭП — усиленная квалифицированная), НЭП (усиленная неквалифицированная) или иная — с указанием класса средства ЭП (КС1, КС2, КС3) и СКЗИ.

Поддерживаемые форматы

  • CMS / PKCS#7 — отделённая подпись в виде самостоятельного файла рядом с документом. Расширения: .sig, .sgn, .sign, .p7s, .bin (плюс числовые суффиксы вида .sig2, .sig.001). Подпись принимается в форматах raw DER, base64 и PEM — обёртка определяется автоматически. Кроме того, если файл имеет нестандартное расширение (например, оператор переименовал .sig в .txt или вставил base64 подписи в текстовый файл) и его размер не превышает 256 KB, сервис проверяет содержимое и распознаёт CMS по сигнатуре signedData — после этого файл встаёт в пайплайн как обычная подпись. Документом может быть любой файл — .pdf, .docx, .xlsx, .doc, .xml, .txt, .html, .rtf и любой бинарный.
  • CAdES — те же расширения, что и CMS; распознаются профили BES, EPES, T, C, X-L Type 1, A. Штампы времени RFC 3161 проверяются end-to-end (TSA-подпись + сравнение imprint), для CAdES-A реконструируется imprint archive-timestamp v2.
  • PAdES — встроенная подпись в PDF (.pdf): чтение /ByteRange, /Contents, поддержка нескольких подписей в одном документе и словаря /DSS (DSS dictionary).
  • Opaque CMS — «совмещённая» подпись: PKCS#7 signedData, в котором подписываемый документ зашит внутри (encapContentInfo.eContent, RFC 5652 §5.2). Такой формат выдаёт Госключ при подписании PDF: файл может быть назван doc.pdf, но его байты — это CMS-обёртка, а сам PDF лежит внутри контейнера. Сервис автоматически распознаёт opaque CMS у любого расширения, извлекает встроенный документ и верифицирует подпись против него (отдельный файл-документ не требуется). В отчёте «имя файла подписи» получает синтетическое значение «{name} (opaque CMS)», а «имя файла документа» — фактическое имя загруженного файла.
  • S/MIME — почтовые сообщения multipart/signed и opaque application/pkcs7-mime. Расширения: .eml, .p7m, .mime, .msg.
  • XMLDSig / XAdES — XML-файлы (.xml) с алгоритмами ГОСТ Р 34.10-2001/2012 (256/512) или RSA/ECDSA. Поддерживаются преобразования c14n, exc-c14n, enveloped-signature, base64, W3C-1999 XPath и W3C-2002 XPath-Filter 2, а также проприетарные urn://smev-gov-ru/xmldsig/transform (СМЭВ-3) и urn:xml-dsig:transformation:v1.1 (ФТС таможня — частично, для мульти-namespace субдеревьев см. Известные ограничения в общей документации). Принимаются обе URI-семьи алгоритмов: urn:ietf:params:xml:ns:cpxmlsec:algorithms:* (CryptoPro xmlsec) и http://www.w3.org/2001/04/xmldsig-more#* (RFC 4490).
  • OOXML.docx, .xlsx, .pptx с поддержкой RelationshipTransform по ECMA-376 п.13.
  • ZIP-архивы.zip распаковывается на один уровень: документы и подписи внутри сопоставляются по содержимому (хеш) и по имени. Также поддерживается «архив подписан целиком»: foo.zip + foo.zip.sig либо archive.zip с сиблингом .sig, чей messageDigest совпадает с хешем архива.

Версионирование

Канонические пути API располагаются под префиксом /api/v{N}/. Контракт v1 зафиксирован: в существующие ответы могут добавляться новые необязательные поля, но имена и типы существующих полей не изменяются и не удаляются. Несовместимое изменение (переименование поля, изменение типа, удаление секции ответа) выпускается параллельной версией /api/v2; /api/v1 продолжает работать в прежнем виде.

Незаверсионированные пути /api/verify и /api/cert/check — это псевдонимы, ведущие на текущую актуальную версию. Они сохраняются для обратной совместимости со старыми интеграциями. В новых интеграциях используйте только версионированные пути, чтобы зафиксировать контракт.

Аутентификация

Доступ к API авторизуется по токену. Токен выдаётся при подключении и передаётся в заголовке Authorization: Bearer <token>. Запросы без валидного токена отклоняются с кодом 401 Unauthorized.

Все запросы выполняются по HTTPS. Максимальный размер тела запроса — 200 МБ.

Коды ошибок

HTTPКогдаЧто вернётся
200 OKЗапрос обработан. Невалидная подпись — это штатный результат проверки, статус по каждому файлу возвращается в items[i].status.JSON: VerificationResponse или CertificateCheckResponse
400 Bad RequestЗапрос не в формате multipart/form-data, отсутствует поле с файлами или повреждена форма.{ "error": "..." }
413 Payload Too LargeПревышен один из лимитов: размер запроса, размер записи в архиве, число записей, коэффициент сжатия (защита от zip-bomb).{ "error": "..." } с указанием конкретного лимита
500 Internal Server ErrorВнутренняя ошибка сервиса.{ "error": "..." }
Важно: отрицательный результат проверки подписи возвращается с кодом 200 OK, а не 4xx. Сам запрос обработан корректно; результат проверки находится в полях items[i].isValid и items[i].status.

POST /api/v1/verify

Проверяет одну или несколько связок «документ + подпись». Принимает ZIP-архивы (распаковываются рекурсивно), пары вида «doc.pdf + doc.pdf.sig», PDF со встроенной PAdES-подписью, opaque-CMS файлы (документ зашит в encapContentInfo — типичный выхлоп Госключа), .eml с S/MIME, файлы .docx, .xlsx, .pptx и .xml (XMLDSig).

Про revocation в ответе. CRL-проверка делается поиском в CRL-банке в памяти — никаких сетевых запросов в момент проверки. Если CDP-URL сертификата ещё не проиндексирован банком (первая встреча УЦ), проверка revocation-crl приходит со статусом Skipped и пометкой «CRL not yet indexed»; URL автоматически кладётся в очередь фоновой прокачки, следующая проверка отдаст Good/Revoked. OCSP по умолчанию асинхронный: revocation-ocsp приходит как Pending, клиент обращается к /api/v1/revocation и подменяет результат. OCSP сразу в ответе — флаг ?withRevocation=true (медленнее на 0.5–10 с).

POST /api/v1/verify
multipart/form-data → application/json

Параметры запроса (query или поле формы)

ПолеТипОписание
filesfile[]Один или несколько файлов. Документ и подпись могут передаваться отдельными частями формы либо одним ZIP-архивом. Имя поля формы — files.
returnSignatureFileboolЕсли true, в каждый элемент результата добавляется signatureFileBase64 — байты файла подписи в base64 (для отделённой подписи), внутренний CMS (для PAdES, S/MIME и opaque CMS — здесь это байты самого загруженного файла) либо файл sig*.xml (для OOXML). Значение по умолчанию — false.
returnCertificateFileboolЕсли true, в каждом подписанте возвращается поле certificateBase64 с DER-представлением сертификата подписанта в base64. Значение по умолчанию — false.

Пример запроса

curl -X POST 'https://api.cleanvoice.ru/cleansign/api/v1/verify?returnCertificateFile=true' \
  -F 'files=@invoice.pdf' \
  -F 'files=@invoice.pdf.sig' \
  -H 'Authorization: Bearer YOUR_KEY'
import requests

files = [
    ('files', ('invoice.pdf',     open('invoice.pdf',     'rb'))),
    ('files', ('invoice.pdf.sig', open('invoice.pdf.sig', 'rb'))),
]
resp = requests.post(
    'https://api.cleanvoice.ru/cleansign/api/v1/verify',
    params={'returnCertificateFile': 'true'},
    files=files,
    headers={'Authorization': 'Bearer YOUR_KEY'},
)
data = resp.json()
print(data['summary']['validlySigned'], 'valid of', data['summary']['totalDocuments'])
const fd = new FormData();
fd.append('files', pdfFile,  'invoice.pdf');
fd.append('files', sigFile,  'invoice.pdf.sig');

const r = await fetch('https://api.cleanvoice.ru/cleansign/api/v1/verify?returnCertificateFile=true', {
  method: 'POST',
  body: fd,
});
const data = await r.json();
console.log(data.summary.validlySigned + ' / ' + data.summary.totalDocuments);
using var http = new HttpClient { BaseAddress = new Uri("https://api.cleanvoice.ru/cleansign/") };
http.DefaultRequestHeaders.Authorization = new("Bearer", "YOUR_KEY");

using var form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(File.ReadAllBytes("invoice.pdf")),     "files", "invoice.pdf");
form.Add(new ByteArrayContent(File.ReadAllBytes("invoice.pdf.sig")), "files", "invoice.pdf.sig");

var resp = await http.PostAsync("api/v1/verify?returnCertificateFile=true", form);
var json = await resp.Content.ReadAsStringAsync();

Пример ответа (200 OK)

{
  "summary": {
    "totalDocuments":    1,
    "signed":            1,
    "validlySigned":     1,
    "invalidSignatures": 0,
    "notSigned":         0,
    "orphanSignatures":  0
  },
  "items": [
    {
      "documentFile":           "invoice.pdf",
      "documentSize":            182734,
      "signatureFile":           "invoice.pdf.sig",
      "isSigned":                true,
      "isValid":                 true,
      "status":                  "Valid",
      "documentHashAlgorithm":   "GOST R 34.11-2012 (256)",
      "documentHashHex":         "8E5C…",
      "messageDigestMatches":    true,
      "isPowerOfAttorney":       false,
      "signers": [
        {
          "subjectCommonName":     "Иванов Иван Иванович",
          "subjectType":           "ЮЛ",
          "signerShortName":       "Иванов И. И.",
          "signingTime":           "2026-04-30T17:42:11+00:00",
          "signatureValid":        true,
          "trustStatus":           "Trusted",
          "chainTrusted":          true,
          "trustedRootSubject":    "CN=Минцифры России",
          "classification":        { "kind": "КЭП", "kindFull": "Квалифицированная электронная подпись",
                                     "classes": ["КС1"], "subjectSignTool": "КриптоПро CSP (5.0.12000)",
                                     "usesGost": true, "issuedByAccreditedUc": true, "isGoskey": false,
                                     "deprecationWarnings": [] },
          "attributes":            { "inn": "772372861423", "innLe": "7709000010",
                                     "ogrn": "1047709098315", "snils": "14233464635",
                                     "email": "i.ivanov@example.com",
                                     "givenName": "Иван Иванович", "surname": "Иванов",
                                     "organization": "ООО «Пример»" },
          "accreditation":         { "issuingUcSki": "23F0DA4A5DE30C96E91F976A3E641689A1F8553C",
                                     "issuingUcName": "УЦ ФНС России",
                                     "accreditedFrom": "2024-01-01T00:00:00+00:00",
                                     "accreditedTo":   null },
          // null accreditedTo  → УЦ accredited at the moment of the response.
          // null issuingUcSki  → issuing УЦ wasn't found in the Минцифры registry.
          // Clients derive "accredited at signing time" by comparing
          // signingTime against AccreditedFrom / AccreditedTo themselves.
          "certificateBase64":     "MIIH…"   // только если returnCertificateFile=true
        }
      ],
      "errors":   [],
      "warnings": []
    }
  ]
}

POST /api/v1/cert/check

Проверка только сертификата, без документа. Эндпоинт оптимизирован для регулярных запусков из cron. Принимает .cer, .crt, .pem, .der или CMS-файл (.sig); во втором случае сертификат подписанта извлекается по SignerID. Возвращает срок действия, число дней до истечения, аккредитацию УЦ, статус OCSP и CRL, классификацию.

POST /api/v1/cert/check
multipart/form-data → application/json

Пример: ежедневный мониторинг

#!/bin/bash
# Завершиться с ошибкой, если до истечения сертификата осталось менее 30 дней.
RESP=$(curl -sf -F files=@/etc/ssl/edo.cer https://api.cleanvoice.ru/cleansign/api/v1/cert/check)
DAYS=$(echo "$RESP" | jq '.items[0].daysUntilExpiry')
[ "$DAYS" -lt 30 ] && echo "ALERT: cert expires in $DAYS days" && exit 1

Пример ответа

{
  "summary": { "total": 1, "currentlyValid": 1, "expiringSoon": 0, "expired": 0,
               "trusted": 1, "untrusted": 0, "revoked": 0 },
  "items": [{
    "fileName":          "edo.cer",
    "source":            "X509",
    "subjectCommonName": "ООО «Пример»",
    "issuer":            "CN=Удостоверяющий центр Федерального казначейства",
    "notBefore":         "2025-08-12T08:14:00+00:00",
    "notAfter":          "2026-08-12T08:14:00+00:00",
    "isCurrentlyValid":  true,
    "daysUntilExpiry":   97,
    "publicKeyAlgorithm":"GOST R 34.10-2012 (256)",
    "classification":    { "kind": "КЭП", "classes": ["КС1"], "issuedByAccreditedUc": true },
    "trust":             { "status": "Trusted", "trusted": true,
                           "rootSubject": "CN=Минцифры России",
                           "chain": [...] },
    "accreditation":     { "issuingUcSki": "...", "issuingUcName": "УЦ Казначейства",
                           "accreditedFrom": "2024-01-01T00:00:00+00:00", "accreditedTo": null },
    "revocation":        null,
    "revocationCrl":     null
  }]
}
POST/api/v1/revocation

Асинхронная OCSP-проверка сертификата

Эндпоинт делает OCSP-запрос к responder'у УЦ (RFC 6960) для одного сертификата. Спроектирован как асинхронное продолжение /api/v1/verify и /api/v1/cert/check: по умолчанию они откладывают OCSP-запрос (он может занять до нескольких секунд) и возвращают check со статусом Pending и URL OCSP-endpoint'а. Клиент (фронт или CLI) дёргает этот эндпоинт с DER-сертификатом подписанта и получает финальный статус.

CRL revocation через этот эндпоинт не запрашивается. Начиная с версии с CRL-банком, CRL-проверка делается сразу в ответе /verify и /cert/check по индексу отозванных серийников в памяти (см. /api/v1/crl-bank/stats) — это поиск за константное время без обращений по сети. Здесь только OCSP, который остаётся онлайн-запросом к серверу УЦ.

Сертификат-издатель резолвится из TrustStore по SubjectKeyIdentifier / IssuerDN. Если издателя нет в trust-store (зарубежные / тестовые УЦ — EJBCA, Let's Encrypt, DigiCert), check возвращается как NotApplicable с пометкой «issuer cert not in trust store» — без открытого ключа издателя OCSP-запрос построить нельзя.

Без rate-limit: UI стреляет в этот эндпоинт параллельно для каждого подписанта в multi-signer документе. Bearer-токен остаётся обязательным.

Запрос

POST /api/v1/revocation
Content-Type: application/json
Authorization: Bearer <session-token>

{
  "signerCertBase64": "MIIH..."
}

Параметры тела

ПолеТипОписание
signerCertBase64stringDER-сертификат подписанта в base64. Обычно копируется из ответа /verify — поле items[].signers[].certificateBase64. PEM-обёртку и пробелы убирать не нужно — парсер их игнорирует.

Ответ — OCSP прошёл

200 OK

{
  "ocsp": {
    "status":     "Good",
    "producedAt": "2026-05-16T19:49:55+00:00",
    "thisUpdate": "2026-05-16T19:49:55+00:00",
    "ocspUrl":    "http://ocsp1.taxcom.ru/OCSPAL/ocsp.srf"
  },
  "ocspCheck": {
    "id":      "revocation-ocsp",
    "status":  "Ok",
    "details": "Endpoint: http://ocsp1.taxcom.ru/..."
  }
}

Поля ответа

ПолеТипОписание
ocsp OcspResult?Сырой результат OCSP-запроса (RFC 6960). null если OCSP отключён в конфиге или не было issuer cert.
ocsp.statusstringGood / Revoked / Unknown / NoEndpoint / FetchFailed / InvalidResponse. Это сырое значение по протоколу OCSP (не унифицированный VerificationCheck.Status).
ocsp.ocspUrlstring?URL, по которому был отправлен OCSP-запрос (из id-ad-ocsp AIA-extension сертификата).
ocspCheckVerificationCheckУнифицированный check той же формы, что в /verify. Содержит id="revocation-ocsp", status из таксономии VerificationCheck (Ok / Failed / Unreachable / NotApplicable / Skipped), endpoint URL в details. Подходит для прямой замены Pending-чека из /verify по id.

Ответ — сертификат отозван

200 OK

{
  "ocsp": {
    "status":           "Revoked",
    "revocationTime":   "2025-08-12T11:14:00+00:00",
    "revocationReason": "keyCompromise",
    "ocspUrl":          "http://pki.tax.gov.ru/ocsp02/ocsp.srf"
  },
  "ocspCheck": {
    "id":       "revocation-ocsp",
    "status":   "Failed",
    "critical": true,
    "details":  "Revoked at 2025-08-12T11:14:00Z, reason: keyCompromise. Endpoint: http://pki.tax.gov.ru/..."
  }
}

Ответ — issuer не в trust-store (зарубежный/тестовый УЦ)

200 OK

{
  "ocsp": null,
  "ocspCheck": {
    "id":      "revocation-ocsp",
    "status":  "NotApplicable",
    "details": "Cannot check OCSP: the signer's issuer certificate is not in the trust store..."
  }
}

Для зарубежных УЦ (EJBCA, Let's Encrypt, DigiCert и т.п.) — это ожидаемый ответ. Чтобы OCSP заработал, добавьте сертификат-издатель в trust-store/intermediates/.

Ответ — OCSP выключен в конфиге

200 OK

{
  "ocsp": null,
  "ocspCheck": {
    "id":      "revocation-ocsp",
    "status":  "Skipped",
    "details": "Disabled in configuration (CleanSign:TrustStore:EnableOcsp=false)."
  }
}

Использование из браузера

// Достали cert из ответа /verify
const cert = response.items[0].signers[0].certificateBase64;

// Дёрнули revocation
const r = await fetch('/api/v1/revocation', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer ' + token,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ signerCertBase64: cert }),
});
const { ocspCheck } = await r.json();

// Заменили Pending-чек на финальный
signer.checks = signer.checks.map(c =>
  c.id === ocspCheck.id ? ocspCheck : c);

Inline-альтернатива для бизнес-API

Если асинхронная схема неудобна (например, скрипт по расписанию) — можно попросить /verify вернуть OCSP сразу в ответе:

POST /api/v1/verify?withRevocation=true
Content-Type: multipart/form-data
...

То же для /api/v1/cert/check?withRevocation=true. В этом режиме отдельный вызов /revocation не нужен, но первый ответ возвращается на 0.5–10 секунд медленнее (зависит от скорости responder'а УЦ). CRL в любом случае проверяется inline через CRL-банк.

GET/api/v1/registry/ucs

Список аккредитованных УЦ

Возвращает текущий снимок реестра аккредитованных удостоверяющих центров Минцифры из памяти. Источник — TSL-XML по адресу https://e-trust.gosuslugi.ru/CA/DownloadTSL?schemaVersion=0, сохраняется в trust-store/registry/tsl-cache.xml и обновляется фоновой задачей каждые 24 часа. На «свежем» хосте — ~481 УЦ.

Эндпоинт открыт (без сессии и rate-limit), читает только из памяти — подходит для регулярных опросов из мониторинга или интеграций.

Параметры

Нет.

Ответ

200 OK

{
  "loadedAt":   "2026-05-13T01:44:04.5976972Z",
  "source":     "tsl-cache.xml",
  "count":      481,
  "items": [
    {
      "subjectKeyIdentifier": "23F0DA4A5DE30C96E91F976A3E641689A1F8553C",
      "name":                 "УЦ ФНС России",
      "inn":                  "7707329152",
      "ogrn":                 "1047707030513",
      "accreditedFrom":       "2021-12-29T00:00:00",
      "accreditedTo":         null,
      "notes":                "Действует"
    },
    ...
  ]
}

Поля ответа

ПолеТипОписание
loadedAt datetimeКогда снимок был загружен в память (соответствует времени изменения файла tsl-cache.xml или generatedAt из встроенного снимка).
source string Источник: tsl-cache.xml при живом TSL или accredited-ucs.json (bundled) на самом cold-start.
count int Количество УЦ в реестре.
items[].subjectKeyIdentifierstringHex SKI сертификата УЦ — стабильный идентификатор (Subject DN и ОГРН/ИНН могут переоформляться).
items[].name string Название УЦ.
items[].inn string? ИНН организации УЦ.
items[].ogrn string? ОГРН организации УЦ.
items[].accreditedFrom datetime?Когда была получена аккредитация.
items[].accreditedTo datetime?Когда аккредитация была отозвана. null = действует на текущий момент.
items[].notes string? Текстовая пометка из TSL (Действует / Прекращена / Аннулирована / Приостановлена).
GET/api/v1/registry/ucs/{ski}

Поиск УЦ по SKI

Возвращает запись о конкретном УЦ по hex-значению SubjectKeyIdentifier. SKI можно получить из leaf-сертификата подписанта — он совпадает с SKI его эмитента, либо из ответа /verify (accreditation.issuingUcSki).

Параметры пути

ПараметрТипОписание
skistringHex SubjectKeyIdentifier (без разделителей, регистр любой).

Ответ

200 OK — объект AccreditedUc (поля как в items[] выше).
404 Not Found — УЦ с таким SKI в реестре нет.

GET/api/v1/revoked/{serial}

Поиск отозванных сертификатов по серийному номеру

Поиск серийника в банке CRL в памяти — фоновая служба раз в сутки выкачивает Certificate Revocation List каждого аккредитованного УЦ из TSL Минцифры и держит в памяти индекс отозванных серийников. Этот эндпоинт ищет hex-серийник по всем CRL, которые сейчас в банке.

Применение: антифрод, сторонний мониторинг конкретного сертификата без перезаливки файла, аудит выпущенных сертификатов.

Важно: пустой результат означает «не найден в покрытых банком УЦ» — это не то же самое, что «гарантированно не отозван». Источник списка URL — <АдресаСписковОтзыва> в TSL Минцифры, поэтому покрываются все 481 аккредитованных УЦ. Сертификаты неаккредитованных или зарубежных издателей в банке отсутствуют.

Авторизация

Bearer-токен сессии. Rate-limit slot не тратится — подходит для регулярных опросов.

Параметры пути

ПараметрТипОписание
serialstringHex-серийник сертификата. Принимаются форматы: aabbcc, 0xaabbcc, aa:bb:cc. Регистр любой, пробелы/дефисы игнорируются.

Ответ

200 OK

{
  "serialHex":       "23f0da4a5de30c96e91f976a3e641689a1f8553c",
  "bankSize":        17,
  "lastRefreshedAt": "2026-05-17T01:42:11.319Z",
  "hits": [
    {
      "url":            "http://pki.tax.gov.ru/cdp/...crl",
      "issuerDn":       "C=RU, O=ФНС России, ...",
      "issuerAkiHex":   "23f0da4a5de30c96e91f976a3e641689a1f8553c",
      "revocationDate": "2025-08-12T11:14:00Z",
      "reason":         "keyCompromise"
    }
  ]
}

Поля ответа

ПолеТипОписание
serialHex string Серийник в каноничном виде (без префикса 0x, в нижнем регистре).
bankSize int Сколько CRL сейчас в банке.
lastRefreshedAtdatetime?Когда фоновое обновление последний раз отработало. null до первого прогона.
hits[] array Совпадения. Обычно 0 или 1. >1 означает что разные УЦ переиспользовали серийник (патология).
hits[].url string CRL-URL где найден серийник.
hits[].issuerDn string Issuer DN из CRL — название УЦ, который отозвал.
hits[].issuerAkiHexstring? AuthorityKeyIdentifier УЦ (hex). Стабильный идентификатор УЦ через смены DN.
hits[].revocationDatedatetimeКогда сертификат был отозван.
hits[].reason string? Причина из RFC 5280 §5.3.1: keyCompromise, cACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, removeFromCRL, privilegeWithdrawn, aACompromise, unspecified.
GET/api/v1/crl-bank/stats

Состояние CRL-банка

Сведения о банке в памяти: сколько CRL покрыто, общее число проиндексированных отозванных записей, время последнего обновления. С параметром ?per=1 возвращает разбивку по каждому CRL (URL, issuer DN, окно thisUpdate / nextUpdate, число записей, флаг проверки подписи).

Как банк наполняется

Источник CDP-URL'ов — сам TSL Минцифры. В XML по адресу https://e-trust.gosuslugi.ru/CA/DownloadTSL?schemaVersion=0 для каждого аккредитованного УЦ перечислены теги <АдресаСписковОтзыва><Адрес>…</Адрес> — это полный авторитетный список (~3000 уникальных URL'ов по 481 УЦ, сопровождается Минцифры ежедневно). Никаких ручных списков и догадок по факту использования — только данные из TSL.

  1. На старте сервиса MintsifryRegistryRefreshService читает TSL из trust-store/registry/tsl-cache.xml. Тут же ParseTslCrlUrls извлекает все CDP-URL'ы и добавляет в trust-store/crl-bank/known-urls.json. Внутренние / VPN-only хосты (10.x.x.x, 192.168.x.x, *.local) отфильтрованы как недостижимые с публичного хоста.
  2. Фоновая служба CrlBankRefreshService запускается раз в сутки в 03:00 МСК (00:00 UTC) — минимальная нагрузка на сервис, к началу рабочего дня в Москве (~09:00) банк уже полностью прокачан. Час и минута настраиваются: CleanSign:CrlBank:ScheduleUtcHour / ScheduleUtcMinute.
  3. Если при запуске банк пустой (первый запуск либо удалили trust-store/crl-bank/crls/) — служба запускает немедленный догоняющий прогон, не дожидаясь ночного слота.
  4. На каждом прогоне служба проходит весь known-urls.json с параллелизмом Concurrency (по умолчанию 8): для каждого URL делает HTTP GET, парсит BouncyCastle'ом, проверяет подпись CRL относительно trust-store, индексирует отозванные серийники в FrozenDictionary<BigInteger,RevokedEntry>, и пишет на диск:
    • trust-store/crl-bank/crls/<sha256(url)>.crl — сырые DER-байты.
    • trust-store/crl-bank/crls/<sha256(url)>.json — сопроводительные сведения: URL, issuerDn, AKI, thisUpdate/nextUpdate, signatureVerified, last_fetched.
  5. После прохождения всех URL делается атомарная замена снимка в памяти (потокобезопасное чтение без блокировок).
  6. На каждом обновлении TSL (раз в сутки) новые URL'ы из <АдресаСписковОтзыва> добавляются в known-urls.json. Старые URL'ы оттуда не удаляются — они остаются актуальными для сертификатов, которые были выпущены под старым ключом УЦ до его ротации.
  7. При перезапуске сервиса конструктор CrlBank синхронно восстанавливает индексы с диска — не теряем покрытие в промежутке между ночными прогонами.

Что в памяти. На каждый CRL держим только то, что нужно для поиска: FrozenDictionary<BigInteger,RevokedEntry> отозванных серийников + thisUpdate/nextUpdate/signatureVerified. Сами «не отозванные» серийники не нужны — CRL по определению содержит только отозванные, остальное считается действительным в пределах окна.

Что на диске. Полный CRL DER + сопроводительные сведения JSON. При перезапуске всё восстанавливается без обращения по HTTP.

Покрытие. Полное по всем 481 аккредитованным УЦ Минцифры. Если в TSL появляется новый УЦ — его CRL прокачается на ближайшем ночном прогоне. УЦ, который не аккредитован (зарубежные тестовые EJBCA, Let's Encrypt и т.п.), банком не покрывается — что корректно по смыслу: 63-ФЗ обязывает доверять только аккредитованным УЦ.

Предельный размер CRL. Файл больше CleanSign:CrlBank:MaxCrlSizeBytes (по умолчанию 500 МБ) пропускается с предупреждением в журнале — защита от случайно опубликованного гигабайта.

Если CRL у УЦ не отвечает / 404. Старый CRL и его индекс в памяти и на диске остаются — следующая попытка через сутки. Покрытие не теряется из-за временного сбоя CDP.

Запаздывание отзыва. Сертификат, отозванный сразу после ночного прогона, попадёт в наш банк только на следующий день. Окно — до 24 ч. Для большинства задач это приемлемо (КриптоПро CSP по умолчанию делает то же самое).

Авторизация

Bearer-токен сессии. Rate-limit slot не тратится.

Параметры запроса

ПараметрТипОписание
perstring?Если 1 или true — включить разбивку perCrl[]. По умолчанию опускается, чтобы ответ оставался компактным.

Ответ

200 OK

{
  "totalCrls":            17,
  "totalRevokedEntries":  1842153,
  "lastRefreshedAt":      "2026-05-17T01:42:11.319Z",
  "perCrl": [
    {
      "url":               "http://pki.tax.gov.ru/cdp/...crl",
      "issuerDn":          "C=RU, O=ФНС России, ...",
      "thisUpdate":        "2026-05-16T15:13:47Z",
      "nextUpdate":        "2026-05-17T15:13:47Z",
      "revokedCount":      1240811,
      "signatureVerified": true
    },
    ...
  ]
}

Поля ответа

ПолеТипОписание
totalCrls int Сколько разных CRL сейчас в банке.
totalRevokedEntries long Суммарное число проиндексированных отозванных серийников по всем CRL.
lastRefreshedAt datetime?UTC-время последнего успешного прогона обновления.
perCrl[] array? Возвращается только при ?per=1.
perCrl[].url string URL cRLDistributionPoint.
perCrl[].issuerDn string Issuer DN — УЦ который опубликовал CRL.
perCrl[].thisUpdate datetime?Время выпуска CRL по самой CRL.
perCrl[].nextUpdate datetime?Время следующего ожидаемого обновления.
perCrl[].revokedCountint Число отозванных серийников в этом CRL.
perCrl[].signatureVerifiedboolПроверена ли подпись CRL против корня из trust-store. Если false — содержимое в банке отображается, но revocation-ответы такого CRL в /verify не учитываются (CrlChecker делает fallback на live HTTP).

VerificationResponse

Ответ POST /api/v1/verify.

ПолеТипОписание
summary object Сводка по всему запросу.
summary.totalDocuments intСколько документов было распознано.
summary.signed intИз них подписанных (любым статусом, включая невалидные).
summary.validlySigned intИз подписанных — прошедших полную проверку (status=Valid).
summary.invalidSignatures intПодписанных с фейлом (хэш не совпал, недоверенная цепочка, пр.).
summary.notSigned intДокументов, для которых не нашлось подписи.
summary.orphanSignatures intПодписей без сопоставленного документа.
items DocumentVerificationResult[] Результат по каждому документу/паре. См. ниже.

DocumentVerificationResult

ПолеТипОписание
documentFile string Имя/путь документа (включая путь внутри архива, если это ZIP).
documentSize long Размер документа в байтах.
signatureFile string? Имя/путь файла подписи. null для NotSigned. Для встроенной подписи — синтетическое имя вроде doc.pdf (PAdES), doc.pdf (opaque CMS), msg.eml (S/MIME application/pkcs7-signature).
isSigned bool Найдена ли вообще какая-либо подпись.
isValid bool Прошла ли подпись все обязательные проверки. true ↔ status=Valid.
status string Один из: Valid (все обязательные проверки прошли); Untrusted (математика подписи корректна, но цепочка не доходит до корня в trust-store); DocumentHashMismatch (хеш документа не совпадает с подписанным значением — документ изменён или приклеена не та подпись); InvalidSignature (криптографическая проверка не прошла); InvalidSignatureContainer / BrokenContainer (файл подписи не парсится как корректный CMS); OrphanSignature (подпись без сопоставленного документа в загрузке — поле signers всё равно заполнено, см. ниже); NotSigned (документ без сопоставленной подписи); UnverifiedXmlSignature (формат XMLDSig распознан и сертификат подписанта извлечён, но криптографический бинд подписи к документу программно подтвердить не удалось — типично для ФТС таможни на urn:xml-dsig:transformation:v1.1; рекомендуется ручная сверка в стороннем сервисе).
documentHashAlgorithm string? Человекочитаемое имя алгоритма (например, «GOST R 34.11-2012 (256)»).
documentHashHex string? Hex-представление вычисленного хеша документа.
messageDigestMatches bool? Совпал ли хеш документа с подписанным атрибутом messageDigest. false = «приклеили чужую подпись».
isPowerOfAttorney bool Файл является МЧД (машиночитаемой доверенностью) — определяется по имени ON_EMCHD_*.xml.
companionOfSignedFile string? Заполняется, когда сам файл не подписан, но в той же загрузке есть подписанный .xml / .json с тем же базовым именем — типовая схема российских госпорталов (СФР, ФНС, Госуслуги, Росреестр, Минобороны): машиночитаемый XML несёт юридически значимую подпись, рядом лежит PDF/DOCX-копия для печати, которая сама подписи не имеет. null, если такой связки нет.
signers SignerInfoResult[]Информация по каждому подписанту. Обычно один элемент. Заполняется и для OrphanSignature (подпись без документа): сертификат, цепочка доверия, классификация КЭП/НЭП, аккредитация УЦ, OCSP/CRL — всё, что не требует содержимого документа, отрабатывает; криптоматематика помечается signatureValid=false (документа для сверки нет).
errors string[] Ошибки, делающие подпись невалидной.
warnings string[] Предупреждения (deprecated алгоритмы, отсутствие OCSP-эндпойнта и т. п.).
signatureFileBase64 string? Заполняется только при returnSignatureFile=true.

SignerInfoResult

Полная карточка подписанта. Поля сгруппированы для удобства.

Идентификация

subjectCommonNamestringCN из Subject DN.
subject stringПолный Subject DN.
issuer stringПолный Issuer DN.
serialNumber stringСерийный номер сертификата (hex).
subjectType string?«Физлицо» / «ИП» / «ЮЛ» / null — определяется по российским OID-ам.
signerShortName string?Компактное «Иванов И. И.» если есть фамилия и имя в attributes.
attributes RussianSubjectAttributesИНН, ИНН ЮЛ, ОГРН, ОГРНИП, СНИЛС, email, surname, givenName, organization, organizationUnit, country, locality, title.

Срок действия и алгоритмы

certNotBefore datetimeНачало срока действия сертификата (ISO-8601 UTC).
certNotAfter datetimeКонец срока действия.
certificateTimeValid bool Был ли сертификат действителен в момент подписания (certNotBefore ≤ signingTime ≤ certNotAfter). Если этот флаг true, а certExpiredNow тоже true — типичная ситуация «подпись действительна, но сертификат к моменту проверки уже истёк»; isValid остаётся true по 63-ФЗ.
certExpiredNow bool true, если на момент проверки сертификат подписанта уже истёк (UtcNow > certNotAfter). Не влияет на isValid — нужен для UI/мониторинга, чтобы было видно расхождение «подписано когда-то валидным сертификатом, но сегодня он просрочен». Юридическая значимость такой подписи зависит от типа: для КЭП — определяется состоянием сертификата на момент подписания (63-ФЗ, ст. 11); для НЭП и иной — условиями соглашения сторон.
certNotYetValidNow bool true, если на момент проверки certNotBefore ещё не наступило (UtcNow < certNotBefore). Зеркальный кейс — обычно следствие расхождения часов или backdated-подписи.
digestAlgorithmOid string OID алгоритма хеширования.
digestAlgorithmName string Человекочитаемое имя.
signatureAlgorithmOid string OID алгоритма подписи.
signatureAlgorithmName string Имя.
signingTime datetime?Из подписанного атрибута signingTime (если есть).

Криптопроверка и доверие

signatureValid bool Прошла ли криптоматематика подписи.
signatureError string? Текст ошибки, если signatureValid=false.
trustStatus string Один из: Trusted, UntrustedRoot, BrokenChain, SignatureFailure, Expired, TrustStoreEmpty.
chainTrusted bool Завершилась ли цепочка на закреплённом anchor-е (ГУЦ Минцифры).
trustedRootSubject string? Subject корневого сертификата, если он в trust-store.
chain CertificateChainLink[]Цепочка leaf → ... → root. Каждый узел: subject, issuer, serialNumber, notBefore, notAfter, inTrustStore.
trustErrors string[]Подробности проблем доверия.

Расширенная информация

classification SignatureClassificationkind (КЭП/НЭП/Иная), kindFull, reason, classes (КС1/КС2/КС3), subjectSignTool (СКЗИ), usesGost, issuedByAccreditedUc, isGoskey, deprecationWarnings.
cades CadesProfile? Уровень CAdES: BES, EPES, T, C, X-L, X Long Type 1, A.
timestamps TimestampResult[]Метки времени с проверенной TSA-подписью.
revocation OcspResult? OCSP-проверка (опционально, off by default).
revocationCrl CrlResult? CRL-проверка (опционально).
accreditation AccreditationCheck?Идентичность УЦ, выпустившего сертификат подписанта (issuingUcSki, issuingUcName) и окно его аккредитации (accreditedFrom, accreditedTonull означает «действует»). Клиент сам вычисляет «аккредитован сейчас» или «аккредитован на момент подписания», сравнивая даты с signingTime. issuingUcSki=null → УЦ нет в реестре Минцифры.
counterSignatures CounterSignatureInfo[]Контр-подписи (id-aa-counterSignature).
signingCertBinding object? Проверка signingCertificateV2 (RFC 5126): Verified / Mismatch / Malformed / NotPresent.
certificateBase64 string? DER сертификата в base64 — только при returnCertificateFile=true.
checks VerificationCheck[]Список всех проверок, которые выполнились для этого подписанта, с унифицированным статусом. См. ниже.

VerificationCheck

Унифицированная запись об одной из проверок конвейера верификации. Лежит в массиве signers[i].checks в том порядке, в котором проверки фактически срабатывают.

Поля

id stringМашиночитаемый идентификатор (см. каталог ниже). Стабилен — можно по нему фильтровать/группировать.
name stringКороткое человеческое название.
description stringОдна-две строки о том, что именно проверяется.
status stringОдин из: Ok, Failed, Warning, Skipped, Unreachable, NotApplicable. См. таблицу значений ниже.
details string?Подробности — текст ошибки, причина пропуска, время отзыва и т.п. Заполнено когда есть что сказать.
critical bool Если true и status="Failed" — этот провал привёл к IsValid=false в родительском документе. Если false — провал считается предупреждением и не отбивает подпись.

Значения status

Ok Проверка отработала, всё в порядке.
Failed Проверка отработала и провалилась. Если critical=true — родительский документ помечен невалидным.
Warning Нефатальное замечание (устаревший алгоритм, аккредитация УЦ под вопросом). Подпись остаётся валидной.
Skipped Проверка отключена в конфигурации (например EnableOcsp=false).
Unreachable Проверка нуждается в сети, но эндпоинт не отозвался (OCSP/CRL responder, TLS-ГОСТ прокси). Результата нет, подпись из-за этого не отбивается.
NotApplicable Проверка не имеет входных данных для этой подписи (нет counter-signatures, нет CRL endpoint в сертификате и т.п.).

Каталог проверок (id → что делает)

idЧто проверяетcriticalВлияние на IsValid
cms-parse CMS / PKCS#7 SignedData разобран без ASN.1-ошибок.даFailed → IsValid=false
document-hash Хеш документа совпадает с подписанным messageDigest. Ловит подмену документа.даFailed → IsValid=false (статус DocumentHashMismatch)
signature-math Криптоматематика подписи против открытого ключа сертификата.даFailed → IsValid=false (InvalidSignature)
cert-time Сертификат внутри окна NotBefore / NotAfter на момент проверки.нетПокрывается signatureValid и проверкой цепочки.
chain-anchor Цепочка завершается закреплённым anchor-ом (ГУЦ Минцифры), каждое звено валидно.да*Failed → IsValid=false. UntrustedRoot → Warning + status=Untrusted (если включено RequireTrustedChain).
signing-cert-binding id-aa-signingCertificateV2 (RFC 5035) — закрывает атаку подмены сертификата.даFailed → IsValid=false
revocation-ocsp Статус отзыва через OCSP-сервис УЦ. Асинхронный: /verify по умолчанию возвращает status=Pending с endpoint-URL в details, клиент дёргает /api/v1/revocation и заменяет чек в финальном ответе. Inline только при ?withRevocation=true.при RevokedRevoked → IsValid=false. Unreachable / Skipped / Pending → не влияет.
revocation-crl Статус отзыва через CRL. Поиск только в CRL-банке в памяти — никаких HTTP-запросов в момент проверки. Когда cRLDistributionPoint сертификата ещё не проиндексирован, проверка возвращается со status=Skipped и пометкой «CRL not yet indexed»; URL регистрируется в фоновой очереди, прокачивается на ближайшем прогоне CrlBankRefreshService, и следующая проверка отдаёт Good/Revoked мгновенно из памяти.при RevokedRevoked → IsValid=false. Skipped (не в банке) / Unreachable → не влияет.
accreditation Был ли выпустивший УЦ аккредитован Минцифры на момент подписания (63-ФЗ).нетНе влияет на IsValid — только на классификацию (КЭП vs НЭП).
signature-kind Классификация: КЭП / НЭП / Иная по политикам сертификата и алгоритму ключа.нетНе влияет на IsValid.
cades-level Профиль CAdES (BES/EPES/T/C/X-L/A) и верификация TSA-меток.нетНе влияет на IsValid.
counter-signatures Контрсигнатуры (id-aa-counterSignature) — каждая рекурсивно верифицируется.нетНе влияет на IsValid основной подписи.
algorithm-deprecationНе используются ли устаревшие алгоритмы (SHA-1, MD5, ГОСТ 2001).нетТолько предупреждение.

Замечание про Unreachable: CleanSign fail-open — если OCSP/CRL responder недоступен или TLS-ГОСТ прокси упал, подпись не отбивается. В checks такой пункт будет Unreachable, а свойство isValid родительского документа останется true. Если revocation-check критичен для вашего use-case — фильтруйте на стороне клиента (checks.some(c => c.id.startsWith('revocation-') && c.status === 'Unreachable')).

Forward-compatibility: новые проверки могут появляться в каталоге, новые значения status — нет (текущие шесть фиксированы). Если ваш клиент не знает какой-то id — просто игнорируйте такую запись или рендерьте её как-нибудь нейтрально.

CertificateCheckResponse

Ответ POST /api/v1/cert/check. Структура простая:

summary.total intСколько файлов прислали.
summary.currentlyValid intДействительных сейчас.
summary.expiringSoon intИстекают в ближайшие 30 дней.
summary.expired intУже истекли.
summary.trusted intЦепочка ведёт к закреплённому anchor-у.
summary.untrusted intЦепочка не выстроилась или anchor другой.
summary.revoked intОтозваны (по OCSP или CRL, если включены).
items[i] CertificateCheckResultfileName, source, subject, issuer, serialNumber, notBefore, notAfter, isCurrentlyValid, daysUntilExpiry, publicKeyAlgorithm, signatureAlgorithm, deprecationWarnings, classification, trust, accreditation, revocation, revocationCrl, attributes. Производный признак «истекает скоро» вычисляется на стороне клиента из daysUntilExpiry по своему порогу.

Файлы ЭДО ФНС — расшифровка имён

В бандлах от операторов ЭДО (Контур, Диадок, Такском, СБИС) и из личного кабинета ФНС/ОФД встречаются XML-файлы с именами вида <префикс>_<тип>_<ИНН отправителя>_<ИНН получателя>_<дата>_<UUID>.xml. Префикс называет роль документа в обмене (приказы ФНС России о форматах ЭДО — например ММВ-7-6/138@, серия 383@).

Префиксы

ПрефиксРасшифровкаРоль в обмене
ON_Основной документ налогоплательщикаСодержательный документ — то, что отправитель шлёт получателю (УПД, счёт-фактура, отчёт по требованию).
IZ_Извещение о получении документа«Я подтверждаю, что документ дошёл по транспорту». Подписывается КЭП оператора или получателя.
KV_Квитанция о приёме документа«Документ проверен по формату и принят к рассмотрению». Подписывается КЭП ФНС.
TR_Транспортная информация (TR_INFSOOB)Сопроводительный конверт с метаданными: отправитель / получатель / дата / идентификаторы транзакции.
DP_Документ продавца / отправителяДокумент от налогоплательщика в адрес ФНС или от продавца покупателю.

Примеры из реальных бандлов

ФайлЧто это
ON_DOCNPNO_…Документ налогоплательщика, направляемый в налоговый орган (ответ на требование ФНС).
IZ_ONDOCNPNO_…Извещение о получении ON-документа — получатель/оператор подтвердил приём по транспорту.
KV_ONDOCNPNO_…Квитанция ФНС о приёме ON-документа после форматной проверки.
TR_INFSOOB.xmlТранспортная инфосообщение — обвязка пакета.
DP_PDOTPR_…Документ продавца, передающий товары/услуги по требованию (универсальный передаточный документ — УПД).
ON_NSCHFDOPPR_…НСЧФ — счёт-фактура с признаками операций передачи. Это сам УПД-документ.

Как идёт обмен

  1. Налогоплательщик подписывает ON + TR своей КЭП → шлёт оператору ЭДО (Контур, Такском, Диадок и т.д.).
  2. Оператор подписывает IZ своей КЭП → шлёт в ФНС.
  3. ФНС проверяет формат, подписывает KV своей КЭП → шлёт обратно через оператора.
  4. Оператор подписывает свою IZ на KV → отдаёт налогоплательщику.

Итого один обмен документом — пакет из 3–5 подписанных XML-файлов, между ними цепочка извещений и квитанций. Все подписи — отдельные .sig (CMS detached) либо встроенные в <Signature> внутри XML.

confirmation.xml

Файл confirmation.xml — это уже не ФНС-формат, а внутренний формат конкретного оператора ЭДО (Goskey / Диадок / СБИС): подтверждение принятия документа в системе оператора, ID транзакции и т.п. Имя стандартизировано на уровне оператора, не ФНС.

Что делает CleanSign

Пакет из таких файлов обрабатывается естественно: каждая XML + её .sig верифицируются отдельно. Если имена файлов рассогласованы (некоторые операторы кладут confirmation.sig рядом с XML, имя которого не совпадает с реальным подписанным документом) — срабатывает сопоставление по содержимому через messageDigest в CMS, и пара восстанавливается корректно.

Типичные интеграции

Сценарии, в которых API применяется на практике.

Учётные системы (1С, SAP, ERP)

При приёме входящего УПД, акта или счёта-фактуры файл автоматически направляется на /api/v1/verify; проводка блокируется, если подпись контрагента невалидна или сертификат отозван.

Операторы ЭДО

Кросс-проверка пакетов от смежных операторов и ФНС: PDF + .sig, ON_DOCNPNO, KV-квитанции, confirmation.*. Автоматическое сопоставление по содержимому, единый формат отчёта.

Финтех, банки, факторинг

Перед выкупом дебиторской задолженности выполняется автоматическая проверка договора поставки: валидная КЭП обеих сторон, цепочка до ГУЦ Минцифры, аккредитация УЦ на момент подписания.

Госорганы и B2G

Приём электронных обращений: проверка подписи заявителя, классификация (КЭП, НЭП), привязка к ФЛ, ИП или ЮЛ по ИНН, СНИЛС и ОГРН, выявление машиночитаемой доверенности (МЧД).

Мониторинг сертификатов через cron

Эндпоинт /api/v1/cert/check запускается раз в сутки по сертификатам ЭДО и API-партнёров; формирует оповещение за Х дней до истечения, при отзыве сертификата или при потере аккредитации УЦ.

curl -F files=@cert.cer \
  https://api.cleanvoice.ru/cleansign/api/cert/check \
  | jq '.items[0].daysUntilExpiry < 30'

Долгосрочное хранение

При помещении документа в архив фиксируется уровень CAdES (от BES до A), валидируются метки времени, сохраняется цепочка сертификатов и снимок реестра аккредитации УЦ в качестве доказательственной базы.

Состав подписки

Подписка включает не только доступ к API, но и операционное обслуживание сервиса в режиме 24/7:

КомпонентСостав
Актуальный trust-storeАвтоматическое обновление: загрузка новых промежуточных сертификатов через AIA, обработка ротации ключей УЦ, актуальные точки распространения CRL.
Синхронизация с реестром МинцифрыЕжедневные обновления с добавление новых аккредитованных УЦ, аннулирования, изменения статуса.
Сопровождение форматовАдаптация движка к новым форматам (Goskey 2.x, новые OID Минцифры, изменения 63-ФЗ). Обновления применяются на стороне сервиса без действий со стороны клиента.
ПроизводительностьГоризонтальное масштабирование под пиковую нагрузку.
SLA и поддержкаЦелевая доступность 99.95%.

Запросить стоимость

В письме укажите сценарии использования и ожидаемый объём верификаций в месяц.