Модуль asn1cades

Модуль работает с расширениями CMS/PKCS

Основная задача слоя ASN.1 в контексте CAdES заключается не просто в сериализации данных, а в точном соблюдении спецификаций X.690/X.690 DER, поскольку любые отклонения приводят к невозможности верификации подписи в внешних системах. Именно поэтому модуль ASN.1 в Jsrsasign рассматривается как фундамент для построения доверенных криптографических структур.

Структура ASN.1 в CAdES-контейнерах

CAdES-подпись базируется на CMS (Cryptographic Message Syntax), где основной контейнер представляет собой последовательность ASN.1-объектов:

  • SignedData
  • SignerInfo
  • SignedAttributes
  • UnsignedAttributes
  • EncapsulatedContentInfo

Каждый из этих элементов представлен ASN.1 SEQUENCE с вложенными структурами. Например, SignedData содержит список сертификатов, алгоритмов и подписанных данных, закодированных строго по DER.

Ключевая особенность заключается в том, что даже изменение порядка атрибутов или способа кодирования INTEGER/OBJECT IDENTIFIER приводит к невалидной подписи.

Представление ASN.1 в Jsrsasign

В библиотеке Jsrsasign ASN.1-дерево представлено объектной моделью, основанной на классах DER:

  • KJUR.asn1.DERSequence
  • KJUR.asn1.DERSet
  • KJUR.asn1.DERInteger
  • KJUR.asn1.DERUTF8String
  • KJUR.asn1.DERTaggedObject

Каждый узел дерева соответствует ASN.1 типу и может быть вложен в другие структуры. Например:

var seq = new KJUR.asn1.DERSequence({
  array: [
    new KJUR.asn1.DERInteger({ int: 1 }),
    new KJUR.asn1.DERUTF8String({ str: "test" })
  ]
});

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

DER-кодирование как основа CAdES

CAdES требует строго DER-совместимого кодирования. Основные ограничения:

  • Только минимальная длина представления INTEGER
  • Запрещены неканонические SET-порядки
  • Обязательное соблюдение tag-length-value структуры
  • Отсутствие BER-вариантов кодирования

Jsrsasign автоматически применяет DER-правила при вызове getEncodedHex() у ASN.1-объектов. Это критично при формировании подписей, так как даже один лишний байт нарушает криптографическую проверку.

Работа с SignedAttributes

SignedAttributes в CAdES — это набор ASN.1 атрибутов, которые включаются в процесс хэширования перед подписью. Они всегда кодируются как DER SET OF, где порядок элементов должен быть строго отсортирован по DER-правилам.

Типичная структура включает:

  • contentType
  • messageDigest
  • signingTime
  • signingCertificate

В Jsrsasign это представляется как DERSet:

var attrs = new KJUR.asn1.DERSet({
  array: [
    new KJUR.asn1.DERSequence({
      array: [
        new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.9.3" }),
        new KJUR.asn1.DERSet({
          array: [
            new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.7.1" })
          ]
        })
      ]
    })
  ]
});

Каждый атрибут является ASN.1 SEQUENCE из OID и значения, что полностью соответствует PKCS#9.

Кодирование OID и бинарных данных

OID (Object Identifier) является фундаментальным элементом ASN.1. В CAdES они определяют алгоритмы, атрибуты и типы контейнеров.

Jsrsasign использует DERObjectIdentifier:

new KJUR.asn1.DERObjectIdentifier({
  oid: "2.5.4.3"
});

Бинарные данные (например, хэш или подпись) кодируются через DEROctetString:

new KJUR.asn1.DEROctetString({
  hex: "deadbeef"
});

При этом hex-строка должна быть строго парной и не содержать префиксов.

Вложенные структуры CMS

CMS/CAdES активно использует вложенность ASN.1. Например:

  • SignedData

    • EncapsulatedContentInfo
    • Certificates
    • SignerInfos

Каждый уровень реализуется через DERSequence с массивом вложенных объектов. Jsrsasign позволяет строить такие деревья рекурсивно, не ограничивая глубину.

Пример базовой структуры:

var signedData = new KJUR.asn1.DERSequence({
  array: [
    new KJUR.asn1.DERInteger({ int: 1 }),
    new KJUR.asn1.DERSet({ array: [] }),
    new KJUR.asn1.DERSequence({ array: [] })
  ]
});

На практике такие структуры значительно сложнее, но принцип остаётся неизменным: дерево DER-объектов.

DERTaggedObject и контекстные теги

ASN.1 в CAdES часто использует контекстные теги [0], [1], [2] для обозначения опциональных полей. В Jsrsasign это реализовано через DERTaggedObject:

new KJUR.asn1.DERTaggedObject({
  tag: "a0",
  explicit: false,
  obj: new KJUR.asn1.DERSequence({ array: [] })
});

Параметр tag задаёт HEX-представление ASN.1 тега, где a0 соответствует [0] CONSTRUCTED.

Правильная работа с тегами критична для совместимости с внешними криптопровайдерами.

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

Базовый профиль CAdES-BES включает:

  • SignedData
  • SignerInfo
  • SignedAttributes
  • SignatureValue

ASN.1 дерево строится снизу вверх. Сначала формируются атрибуты, затем вычисляется хэш, затем создаётся SignerInfo.

SignerInfo в ASN.1 выглядит как:

  • version
  • sid (issuerAndSerialNumber)
  • digestAlgorithm
  • signedAttrs
  • signatureAlgorithm
  • signature
  • unsignedAttrs

Каждое поле является DER-объектом, а порядок строго фиксирован стандартом.

Преобразование ASN.1 в HEX и обратно

Jsrsasign предоставляет методы:

  • getEncodedHex() — сериализация в DER HEX
  • fromBER() — разбор бинарного ASN.1

Пример сериализации:

var hex = seq.getEncodedHex();

При обратном разборе:

var asn1 = ASN1HEX.decode(hex);

ASN1HEX позволяет навигацию по дереву без полной десериализации, что полезно для анализа подписанных контейнеров.

Ошибки кодирования и несовместимости

При работе с ASN.1 в CAdES наиболее частые проблемы:

  • неправильный порядок элементов SET
  • использование BER вместо DER
  • неверная длина OCTET STRING
  • отсутствие обязательных атрибутов
  • некорректные OID

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

Особенности работы с сертификатами в ASN.1

Сертификаты X.509 также являются ASN.1 структурами и часто включаются в CAdES контейнер как CertificateSet.

Структура сертификата:

  • TBSCertificate
  • signatureAlgorithm
  • signatureValue

Jsrsasign позволяет как разбирать, так и включать сертификаты в CMS через DERSequence.

Итеративное построение ASN.1 деревьев

При создании CAdES-структур используется подход постепенного построения дерева:

  1. Формирование контента
  2. Вычисление digest
  3. Создание SignedAttributes
  4. Генерация SignerInfo
  5. Упаковка в SignedData

Каждый шаг зависит от предыдущего, что делает ASN.1 не просто форматом, а процессной моделью данных.

Работа с бинарными представлениями в CMS

ASN.1 слой в Jsrsasign активно взаимодействует с бинарными структурами CMS. Это означает, что любые изменения в байтовом представлении отражаются на криптографической валидности.

Особое внимание уделяется:

  • точному позиционированию атрибутов
  • стабильности DER сериализации
  • воспроизводимости хэша

Любая нестабильность приводит к различию signature value при повторном вычислении.

Интеграция ASN.1 с криптографическими алгоритмами

ASN.1 модуль тесно связан с:

  • RSA/ECDSA подписью
  • SHA-1/SHA-256 хэшированием
  • HMAC структурами в отдельных CMS профилях

Алгоритмы кодируются через AlgorithmIdentifier:

new KJUR.asn1.DERSequence({
  array: [
    new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.1.11" }),
    new KJUR.asn1.DERNull()
  ]
});

Такой подход обеспечивает универсальность криптографических операций внутри ASN.1 дерева.

Манипуляции с ASN.1 деревьями

Jsrsasign допускает модификацию узлов после создания, однако это опасная операция в контексте CAdES, так как нарушает целостность подписи.

Типичные операции:

  • добавление узла в DERSequence
  • замена DEROctetString
  • изменение DERSet

Любое изменение требует пересчёта подписи, иначе структура становится недействительной.

Роль ASN.1 в проверке подписи

При верификации CAdES подписи ASN.1 используется для:

  • извлечения SignedAttributes
  • проверки digest
  • декодирования SignerInfo
  • сопоставления сертификатов

Без корректного ASN.1 разбора невозможно восстановить оригинальные данные подписи, что делает этот модуль ключевым элементом всей криптографической цепочки.