Unsigned attributes

В формате CMS (Cryptographic Message Syntax, RFC 5652) подписанные данные организованы через структуру SignedData, внутри которой ключевую роль играет объект SignerInfo. Именно здесь разделяются атрибуты, участвующие в подписи, и данные, находящиеся вне её криптографической защиты.

В SignerInfo существуют два независимых набора атрибутов:

  • signedAttributes — включаются в вычисление подписи
  • unsignedAttributes — не участвуют в подписи и не влияют на её проверку

SignerInfo = {, signedAttrs, unsignedAttrs, signature ,}

Ключевая особенность unsigned attributes заключается в том, что их содержимое может быть добавлено или изменено после формирования подписи без нарушения криптографической целостности самого SignerInfo.


Структура SignerInfo и позиция unsigned attributes

В терминах ASN.1 структура SignerInfo выглядит следующим образом:

  • version
  • sid (идентификатор подписанта)
  • digestAlgorithm
  • signedAttrs (опционально)
  • signatureAlgorithm
  • signature
  • unsignedAttrs (опционально)

unsignedAttrs располагаются строго после поля signature и кодируются как набор атрибутов (SET OF Attribute).


Формат атрибута unsigned attributes

Каждый атрибут в CMS представляет собой структуру:

  • attrType — OID атрибута
  • attrValues — массив ASN.1 значений

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

Пример логической структуры:

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

Криптографический смысл отсутствия подписи

Unsigned attributes обладают важным свойством: они не защищены подписью, следовательно:

  • не влияют на результат проверки подписи
  • могут быть добавлены после подписания
  • не гарантируют целостность

Это делает их пригодными для метаданных, которые не должны ломать подпись при изменении.


Типичные применения unsigned attributes

В CMS и CAdES-расширениях unsigned attributes используются для добавления внешних криптографических доказательств и вспомогательных данных:

1. CounterSignature (контрподпись)

Позволяет подписать уже существующую подпись. Используется в многосторонних сценариях подписания.

2. TimestampToken (RFC 3161)

Временная метка, подтверждающая существование подписи на определённый момент времени.

3. Archive Timestamp

Используется в долговременном архивном хранении для подтверждения целостности документа спустя годы.

4. Revocation info (иногда вне signedAttrs)

Информация об отзыве сертификатов может быть добавлена как вспомогательная метаинформация.


Реализация unsigned attributes в Jsrsasign

В библиотеке Jsrsasign работа с CMS реализована через пространство имён KJUR.crypto.CMS.

Структура подписанта (SignerInfo) обычно представляется объектом Jav * aScript:

{
  version: 1,
  sid: {...},
  digestAlgorithm: "sha256",
  signedAttrs: [...],
  signatureAlgorithm: "SHA256withRSA",
  signature: "...",
  unsignedAttrs: [...]
}

Добавление unsigned attributes при формировании CMS

При создании CMS через Jsrsasign можно расширить SignerInfo дополнительными атрибутами, которые не будут участвовать в подписи.

Пример добавления counterSignature:

var cms = new KJUR.crypto.CMS();

cms.sign({
  content: "Hello world",
  cert: certPEM,
  key: keyPEM,
  digestAlg: "sha256",

  signerInfo: {
    unsignedAttrs: [
      {
        attrType: "1.2.840.113549.1.9.6",
        attrValues: [
          {
            type: "SIGNATURE",
            value: "..."
          }
        ]
      }
    ]
  }
});

OID 1.2.840.113549.1.9.6 соответствует counterSignature.


Добавление временной метки как unsigned attribute

TimestampToken (RFC 3161) часто кодируется как ASN.1 объект и помещается в unsigned attributes:

unsignedAttrs: [
  {
    attrType: "1.2.840.113549.1.9.16.2.14",
    attrValues: [timestampTokenASN1]
  }
]

OID 1.2.840.113549.1.9.16.2.14 соответствует id-aa-signatureTimeStampToken.


Чтение unsigned attributes из CMS

При разборе CMS-структуры Jsrsasign предоставляет доступ к signerInfo:

var cms = new KJUR.crypto.CMS();
cms.parse(cmsData);

var signerInfos = cms.getSignerInfos();
var unsignedAttrs = signerInfos[0].unsignedAttrs;

Каждый элемент массива содержит:

  • OID атрибута
  • ASN.1 структуру значений
  • необработанные данные в DER

Особенности кодирования unsigned attributes

Unsigned attributes кодируются как:

  • DER SET OF Attribute
  • порядок элементов не критичен для криптографической проверки
  • могут отсутствовать без изменения результата подписи

Однако при практической обработке важно учитывать:

  • разные реализации могут по-разному сортировать атрибуты
  • вложенные структуры требуют строгого ASN.1 декодирования
  • некоторые атрибуты содержат бинарные OCTET STRING

Отличие от signed attributes

Ключевое различие:

Характеристика signedAttributes unsignedAttributes
Участвуют в подписи да нет
Защищены хэшем да нет
Можно модифицировать нет да
Криптографическая роль основная вспомогательная

Ошибки при работе с unsigned attributes

На практике возникают типичные ошибки:

  • помещение критических данных в unsignedAttrs вместо signedAttrs
  • ожидание криптографической защищённости timestamp в unsignedAttrs
  • неверное кодирование OID или ASN.1 структуры
  • смешивание форматов CAdES-BES и CAdES-T без учета timestamp token

Поведение Jsrsasign при сериализации

При генерации CMS библиотека:

  • формирует DER-структуру SignerInfo
  • вычисляет подпись только по signedAttrs (если они заданы)
  • вставляет unsignedAttrs без включения в digest
  • сериализует результат в SignedData

Unsigned attributes становятся «внешним слоем расширения» подписанта, не влияющим на базовую криптографическую целостность.