CMS (Cryptographic Message Syntax) представляет собой стандарт, описывающий формат криптографически защищённых сообщений, включающих цифровую подпись, сертификаты и зашифрованные данные. В экосистеме JavaScript библиотека Jsrsasign предоставляет инструменты для формирования PKCS
Библиотека может использоваться как в браузере, так и в Node.js. В браузере достаточно подключить UMD-сборку:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/10.8.6/jsrsasign-all-min.js"></script>
В Node.js установка выполняется через npm:
npm install jsrsasign
И подключение:
const jsrsasign = require("jsrsasign");
const KJUR = jsrsasign.KJUR;
Для работы с CMS важны компоненты:
KJUR.asn1.cms — генерация CMS/PKCS#7 структурKEYUTIL — работа с ключами и сертификатамиKJUR.crypto — криптографические операцииCMS-подпись строится вокруг объекта SignedData, который включает:
Логика формирования CMS в Jsrsasign сводится к последовательному созданию ASN.1-структуры и её подписи приватным ключом.
Для создания подписи требуется RSA-ключ и сертификат X.509.
Пример генерации ключевой пары (для тестирования):
const kp = KEYUTIL.generateKeypair("RSA", 2048);
const privateKey = kp.prvKeyObj;
const publicKey = kp.pubKeyObj;
Создание самоподписанного сертификата:
const cert = KJUR.asn1.x509.X509Util.newCertPEM({
serial: {int: 1},
sigalg: "SHA256withRSA",
subject: [{name: "C", value: "KZ"}, {name: "CN", value: "Test User"}],
sbjpubkey: publicKey,
cakey: privateKey,
notbefore: "230101000000Z",
notafter: "250101000000Z"
});
Сертификат в формате PEM будет использоваться внутри CMS.
CMS может подписывать как текст, так и бинарные данные. В Jsrsasign чаще используется строковый контент.
const data = "Документ для цифровой подписи";
Важно учитывать кодировку: по умолчанию используется UTF-8, но при работе с бинарными файлами данные предварительно кодируются в base64 или hex.
Основной объект для формирования подписи —
KJUR.asn1.cms.SignedData.
Пример создания подписи:
const cmsSigned = new KJUR.asn1.cms.SignedData({
content: {
type: "data",
content: data
},
signerInfo: [{
version: 1,
sid: {
type: "issuserandserialnumber",
cert: cert
},
digestAlgorithm: "sha256",
signatureAlgorithm: "SHA256withRSA",
signature: {
alg: "SHA256withRSA",
key: privateKey
}
}],
certificates: [cert]
});
После создания объект необходимо сериализовать в DER или PEM формат:
const cmsDer = cmsSigned.getContentInfo({asn1: true});
const cmsPem = KJUR.asn1.ASN1Util.getPEMStringFromHex(cmsDer.toHex(), "CMS");
Процесс формирования CMS-подписи включает несколько этапов:
В упрощённой реализации Jsrsasign автоматически выполняет шаги 1–4
внутри SignedData.
Для повышения криптографической устойчивости можно включить атрибуты:
Пример:
signedAttrs: {
signingTime: new Date(),
contentType: "data",
messageDigest: KJUR.crypto.Util.hashString(data, "sha256")
}
Jsrsasign позволяет получать результат в нескольких форматах:
Пример конвертации:
const derHex = cmsSigned.getContentInfo().toHex();
const pem = KJUR.asn1.ASN1Util.getPEMStringFromHex(derHex, "CMS");
Проверка выполняется через извлечение SignedData и валидацию подписи:
const cmsObj = new KJUR.asn1.cms.ContentInfo({pem: pem});
const sd = new KJUR.asn1.cms.SignedData({cmsobj: cmsObj});
const isValid = sd.verify();
В процессе проверки:
В реальных системах CMS используется для:
Пример полного цикла:
const message = JSON.stringify({
id: 10,
user: "alice",
amount: 500
});
const cms = new KJUR.asn1.cms.SignedData({
content: {type: "data", content: message},
signerInfo: [{
digestAlgorithm: "sha256",
signatureAlgorithm: "SHA256withRSA",
signature: {
alg: "SHA256withRSA",
key: privateKey
},
sid: {cert: cert}
}],
certificates: [cert]
});
const signed = cms.getContentInfo().toString("hex");
Отправка подписанного сообщения:
fetch("/api/verify", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({cms: signed})
});
Если алгоритм подписи и хэширования не согласованы, подпись будет невалидной.
Различие между UTF-8 и бинарными данными приводит к некорректному хэшу.
CMS требует корректного X.509 сертификата, иначе структура SignedData не формируется.
Если не включены промежуточные сертификаты, проверка на стороне получателя может провалиться.
CMS выгодно отличается от “голой” RSA-подписи тем, что:
PKCS#1 используется только для подписи хэша, тогда как CMS — полноценный контейнер.
При внедрении Jsrsasign CMS в системы документооборота важно учитывать:
CMS-подписи, созданные Jsrsasign, обычно совместимы с серверными PKI-системами при корректной настройке алгоритмов и сертификатов.