Атрибуты CAdES в jsrsasign

CAdES (CMS Advanced Electronic Signatures) в контексте реализации через jsrsasign опирается на структуру CMS/PKCS

Основная модель CAdES в jsrsasign реализуется через ASN.1-структуры CMS, где подпись представлена как SignedData, содержащая набор подписанных атрибутов (signed attributes) и неподписанных атрибутов (unsigned attributes). Именно атрибуты превращают «сырую» CMS-подпись в формат, соответствующий требованиям CAdES.


Структура SignedData и место атрибутов

В jsrsasign CMS-структура обычно создаётся через пространство имён KJUR.asn1.cms. Внутри SignedData ключевым элементом является SignerInfo, где и располагаются атрибуты:

  • signedAttributes — участвуют в вычислении подписи
  • unsignedAttributes — не влияют на значение подписи, но расширяют её функциональность

Подпись вычисляется не над исходными данными напрямую, а над DER-кодированным набором signedAttributes, что является фундаментальной особенностью CAdES.


Signed attributes как основа CAdES-логики

Signed attributes формируют криптографически защищённое описание контекста подписи. Их изменение после подписания приводит к полной недействительности подписи.

messageDigest

Один из ключевых атрибутов — хеш исходного сообщения:

  • OID: 1.2.840.113549.1.9.4
  • Содержит digest данных, которые подписываются

В jsrsasign этот атрибут формируется автоматически при создании CMS-структуры.

Пример логики формирования:

var cms = new KJUR.asn1.cms.CMSUtil();
var signedData = cms.newSignedData({
  content: {str: "Hello CAdES"},
  certs: [certPem],
  signerInfo: [{
    hashAlg: "sha256",
    sattrs: {
      contentType: "data",
      signingTime: new Date()
    }
  }]
});

contentType

Атрибут определяет тип подписываемого содержимого:

  • OID: 1.2.840.113549.1.9.3
  • Обычно значение: data (1.2.840.113549.1.7.1)

Этот атрибут фиксирует семантику содержимого CMS.


signingTime

Фиксирует время создания подписи:

  • OID: 1.2.840.113549.1.9.5
  • Значение: UTC время

В jsrsasign он часто задаётся явно или генерируется автоматически:

sattrs: {
  signingTime: new Date()
}

Важно, что этот атрибут не является доверенным временем в юридическом смысле без использования timestampToken.


signingCertificate / signingCertificateV2

Ключевой CAdES-атрибут, связывающий подпись с конкретным сертификатом.

  • signingCertificate (CAdES-BES)
  • signingCertificateV2 (более современный вариант, SHA-256 и выше)

Он содержит хеш сертификата подписанта, а не сам сертификат.

В jsrsasign этот атрибут может формироваться через цепочку сертификатов:

sattrs: {
  signingCertificateV2: certPem
}

На практике библиотека может автоматически строить структуру ESSCertIDv2, соответствующую RFC 5035.


signingPolicy

Используется в расширенных профилях CAdES для указания политики подписи.

  • Не всегда обязателен
  • Содержит OID политики и её параметры

В jsrsasign поддержка зависит от уровня ручной сборки ASN.1 структуры.


Unsigned attributes и расширения CAdES

Unsigned attributes не участвуют в вычислении подписи, но критически важны для доверенной инфраструктуры.


timestampToken

Один из наиболее значимых атрибутов в CAdES-T и выше.

  • Добавляет криптографическое доказательство времени
  • Формируется через TSA (Time Stamping Authority)

В jsrsasign может добавляться как внешний атрибут:

uattrs: {
  timestampToken: tsaResponse
}

Он позволяет доказать, что подпись существовала в момент времени, подтверждённый сторонним сервером времени.


completeCertificateRefs и completeRevocationRefs

Используются в CAdES-C и CAdES-X Long.

  • completeCertificateRefs — ссылки на все сертификаты цепочки
  • completeRevocationRefs — ссылки на CRL/OCSP ответы

Эти атрибуты уменьшают зависимость от внешних источников при проверке подписи.


certificateValues и revocationValues

Содержат:

  • полные сертификаты цепочки
  • данные об отзыве (CRL, OCSP)

В jsrsasign такие структуры обычно формируются вручную при построении расширенных CMS-подписей.


Формирование CAdES-структур в jsrsasign

jsrsasign предоставляет низкоуровневую и среднеуровневую работу с CMS через KJUR.asn1.cms.CMSUtil.

Типовой процесс включает:

  1. Хеширование данных
  2. Формирование signedAttributes
  3. Кодирование ASN.1 структуры
  4. Вычисление подписи приватным ключом
  5. Формирование SignerInfo
  6. Добавление unsignedAttributes при необходимости

Пример формирования базовой CAdES-BES структуры

var cmsUtil = new KJUR.asn1.cms.CMSUtil();

var signed = cmsUtil.newSignedData({
  content: {str: "Document content"},
  certs: [certPem],
  signerInfo: [{
    hashAlg: "sha256",
    sattrs: {
      contentType: "data",
      signingTime: new Date()
    }
  }]
});

var pem = KJUR.asn1.cms.CMSUtil.getPEM(signed);

Здесь signedAttributes формируются автоматически, но могут быть расширены вручную при необходимости реализации строгого CAdES-профиля.


Роль DER-кодирования в атрибутах

Все signed attributes кодируются в DER-формате перед подписанием. Это означает:

  • порядок атрибутов фиксирован
  • структура строго нормализуется
  • любое изменение приводит к изменению хеша

jsrsasign автоматически обеспечивает DER-кодирование через ASN.1 реализацию KJUR.asn1.


Особенности работы с OID в CAdES-атрибутах

Каждый атрибут в CAdES идентифицируется OID. jsrsasign использует внутренние таблицы OID:

  • contentType → 1.2.840.113549.1.9.3
  • messageDigest → 1.2.840.113549.1.9.4
  • signingTime → 1.2.840.113549.1.9.5

При расширении функциональности новые OID добавляются вручную в ASN.1 структуру.


Механика вычисления подписи над атрибутами

Ключевой момент CAdES:

  1. формируется SET OF signedAttributes
  2. выполняется DER encoding
  3. вычисляется hash (SHA-256 и др.)
  4. hash подписывается приватным ключом
  5. результат помещается в SignerInfo

Таким образом подпись привязана не к документу напрямую, а к метаданным атрибутов.


Ошибки при работе с атрибутами

На практике встречаются типовые проблемы:

  • отсутствие messageDigest приводит к невозможности валидации
  • неверный DER порядок атрибутов ломает подпись
  • ручное изменение signingTime после подписи делает структуру недействительной
  • несовпадение signingCertificateV2 с реальным сертификатом вызывает ошибки доверия

jsrsasign не всегда валидирует CAdES-уровень строго, поэтому ответственность за корректность структуры часто лежит на разработчике.


Расширение CAdES уровней через атрибуты

CAdES определяется уровнем добавленных атрибутов:

  • CAdES-BES — базовые signedAttributes
  • CAdES-T — добавление timestampToken
  • CAdES-C — добавление ссылок на сертификаты и отзыв
  • CAdES-X Long — полные цепочки и долгосрочная проверка

В jsrsasign эти уровни не выделены как отдельные API, но реализуются комбинацией signedAttributes и unsignedAttributes.


Практическая архитектура атрибутов в jsrsasign

Внутренне атрибуты представлены как ASN.1 структуры:

  • Attribute ::= SEQUENCE { attrType OBJECT IDENTIFIER, attrValues SET OF ANY }

jsrsasign использует классы:

  • KJUR.asn1.DERSet
  • KJUR.asn1.DERSequence
  • KJUR.asn1.DERObjectIdentifier

для построения каждого элемента.


Значение атрибутов в проверке подписи

При валидации CMS:

  • signedAttributes пересчитываются и сравниваются с подписью
  • unsignedAttributes проверяются отдельно
  • несоответствие любого signedAttribute приводит к ошибке

Таким образом атрибуты выступают не метаданными, а частью криптографического ядра подписи.