В формате CMS (Cryptographic Message Syntax, RFC 5652) подписанные
данные организованы через структуру SignedData, внутри
которой ключевую роль играет объект SignerInfo. Именно
здесь разделяются атрибуты, участвующие в подписи, и данные, находящиеся
вне её криптографической защиты.
В SignerInfo существуют два независимых набора
атрибутов:
SignerInfo = {, signedAttrs, unsignedAttrs, signature ,}
Ключевая особенность unsigned attributes заключается в том, что их
содержимое может быть добавлено или изменено после формирования подписи
без нарушения криптографической целостности самого
SignerInfo.
В терминах ASN.1 структура SignerInfo выглядит следующим
образом:
unsignedAttrs располагаются строго после поля
signature и кодируются как набор атрибутов
(SET OF Attribute).
Каждый атрибут в CMS представляет собой структуру:
attrType — OID атрибутаattrValues — массив ASN.1 значенийUnsigned attributes следуют тому же формату, но их ключевое отличие — отсутствие включения в хэш при вычислении подписи.
Пример логической структуры:
Attribute ::= SEQUENCE {
attrType OBJECT IDENTIFIER,
attrValues SET OF ANY
}
Unsigned attributes обладают важным свойством: они не защищены подписью, следовательно:
Это делает их пригодными для метаданных, которые не должны ломать подпись при изменении.
В CMS и CAdES-расширениях unsigned attributes используются для добавления внешних криптографических доказательств и вспомогательных данных:
Позволяет подписать уже существующую подпись. Используется в многосторонних сценариях подписания.
Временная метка, подтверждающая существование подписи на определённый момент времени.
Используется в долговременном архивном хранении для подтверждения целостности документа спустя годы.
Информация об отзыве сертификатов может быть добавлена как вспомогательная метаинформация.
В библиотеке Jsrsasign работа с CMS реализована через пространство
имён KJUR.crypto.CMS.
Структура подписанта (SignerInfo) обычно представляется
объектом Jav * aScript:
{
version: 1,
sid: {...},
digestAlgorithm: "sha256",
signedAttrs: [...],
signatureAlgorithm: "SHA256withRSA",
signature: "...",
unsignedAttrs: [...]
}
При создании 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.
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.
При разборе CMS-структуры Jsrsasign предоставляет доступ к signerInfo:
var cms = new KJUR.crypto.CMS();
cms.parse(cmsData);
var signerInfos = cms.getSignerInfos();
var unsignedAttrs = signerInfos[0].unsignedAttrs;
Каждый элемент массива содержит:
Unsigned attributes кодируются как:
Однако при практической обработке важно учитывать:
Ключевое различие:
| Характеристика | signedAttributes | unsignedAttributes |
|---|---|---|
| Участвуют в подписи | да | нет |
| Защищены хэшем | да | нет |
| Можно модифицировать | нет | да |
| Криптографическая роль | основная | вспомогательная |
На практике возникают типичные ошибки:
При генерации CMS библиотека:
Unsigned attributes становятся «внешним слоем расширения» подписанта, не влияющим на базовую криптографическую целостность.