CMS (Cryptographic Message Syntax) в реализации Jsrsasign
представляет собой ASN.1-структуру, предназначенную для создания
подписанных сообщений в формате PKCS#7 / CMS. Основной объект для
формирования подписи — SignedData, который включает в
себя:
В Jsrsasign работа с CMS реализована через пространство имён
KJUR.asn1.cms, а также вспомогательные криптографические
классы KJUR.crypto.
Перед созданием SignedData требуется подготовить ключевой материал:
Типичный набор объектов:
const kp = KEYUTIL.generateKeypair("RSA", 2048);
const prvKey = kp.prvKeyObj;
const pubKey = kp.pubKeyObj;
Формирование самоподписанного сертификата (для тестовых сценариев):
const cert = new KJUR.asn1.x509.Certificate({
version: 3,
serial: {int: 1},
sigalg: "SHA256withRSA",
issuer: [{C: "RU", O: "Test"}],
notbefore: "230101000000Z",
notafter: "260101000000Z",
subject: [{C: "RU", O: "Test"}],
sbjpubkey: pubKey
});
cert.sign(prvKey, "SHA256withRSA");
const pemCert = cert.getPEM();
CMS SignedData может работать в двух режимах:
Пример контента:
const content = "Hello CMS SignedData";
Для CMS используется OCTET STRING обёртка:
const oids = KJUR.asn1.cms.CMSUtil;
Основной класс формирования структуры:
const sd = new KJUR.asn1.cms.SignedData({
content: {
type: "data",
content: content
},
certs: [pemCert],
signerInfos: [{
signerCert: pemCert,
digestAlg: "sha256",
signedAttrs: {
signingTime: new Date(),
contentType: "data",
messageDigest: null
}
}]
});
SignerInfo содержит критически важные параметры:
В Jsrsasign вычисление подписи выполняется автоматически при вызове
sign().
Пример явного формирования подписи:
const signer = new KJUR.crypto.Signature({
alg: "SHA256withRSA"
});
signer.init(prvKey);
signer.updateString(content);
const signatureHex = signer.sign();
Однако в CMS уровень абстракции выше — подпись инкапсулируется внутри
SignedData.
Signed attributes формируют защищённую часть подписи. Они хэшируются и включаются в вычисление подписи.
Основные атрибуты:
content-typemessage-digestsigning-timeПример формирования:
signedAttrs: {
signingTime: new Date(),
contentType: "data",
messageDigest: null
}
Jsrsasign автоматически вычисляет messageDigest, если он
не задан вручную.
Поле certificates включает:
Формат PEM передаётся напрямую:
certs: [pemCert]
В ASN.1 структурах это превращается в
CertificateSet.
После настройки всех параметров происходит построение DER-структуры:
const cmsDer = sd.getContentInfo().getContent().toString("hex");
Или получение PEM/BASE64 представления:
const cmsB64 = hextob64(cmsDer);
При использовании detached режима содержимое не встраивается:
const sd = new KJUR.asn1.cms.SignedData({
content: {
type: "data",
content: ""
},
detached: true,
certs: [pemCert],
signerInfos: [{
signerCert: pemCert,
digestAlg: "sha256"
}]
});
В этом случае хэш считается отдельно и используется только для проверки подписи.
Jsrsasign поддерживает набор стандартных алгоритмов:
Комбинации:
Указание алгоритма:
digestAlg: "sha256"
Финальная структура CMS SignedData включает:
В Jsrsasign это автоматически сериализуется в DER через ASN.1 encoder.
const kp = KEYUTIL.generateKeypair("RSA", 2048);
const cert = new KJUR.asn1.x509.Certificate({
version: 3,
serial: {int: 1},
sigalg: "SHA256withRSA",
issuer: [{C: "RU", O: "Org"}],
subject: [{C: "RU", O: "Org"}],
sbjpubkey: kp.pubKeyObj
});
cert.sign(kp.prvKeyObj, "SHA256withRSA");
const pemCert = cert.getPEM();
const sd = new KJUR.asn1.cms.SignedData({
content: {
type: "data",
content: "Test message"
},
certs: [pemCert],
signerInfos: [{
signerCert: pemCert,
digestAlg: "sha256",
signedAttrs: {
signingTime: new Date(),
contentType: "data"
}
}]
});
const cmsHex = sd.getContentInfo().getContent().toHex();
Проверка SignedData включает:
В Jsrsasign проверка выполняется через
KJUR.crypto.CMSVerifier:
const result = KJUR.crypto.CMSVerifier.verify({
cms: cmsB64,
certs: [pemCert]
});