PKI (Public Key Infrastructure) в JavaScript реализуется через сочетание криптографических примитивов и форматов сертификатов X.509, где библиотека Jsrsasign обеспечивает полный набор средств для генерации ключей, создания сертификатов, подписи и проверки цепочек доверия.
Базовая модель PKI включает три уровня:
Корневой сертификат является доверенной точкой, от которой строится вся цепочка доверия. Его приватный ключ используется только для подписи промежуточных CA. Нарушение безопасности Root CA приводит к компрометации всей инфраструктуры, поэтому в реальных системах он обычно хранится офлайн.
Промежуточные CA уменьшают риск использования корневого ключа и позволяют разделять зоны ответственности. Конечные сертификаты применяются для TLS-серверов, клиентской аутентификации, подписи данных.
Jsrsasign предоставляет инструменты:
Основные пространства имен:
KEYUTIL — генерация и импорт ключейKJUR.crypto — криптографические операцииKJUR.asn1.x509 — работа с сертификатамиX509 — высокоуровневое API сертификатовСоздание RSA ключей выполняется через генератор ключевых пар:
var kp = KEYUTIL.generateKeypair("RSA", 2048);
var privateKey = kp.prvKeyObj;
var publicKey = kp.pubKeyObj;
Приватный ключ используется для подписи сертификатов, публичный — встраивается в сертификаты.
Для более строгих конфигураций применяется длина 3072 или 4096 бит.
Корневой сертификат самоподписанный, то есть подписывается собственным приватным ключом.
var caKey = KEYUTIL.generateKeypair("RSA", 2048);
var caCert = new X509();
caCert.setSerialNumberByParam({ int: 1 });
caCert.setIssuerName("CN=RootCA,O=Example,C=US");
caCert.setSubjectName("CN=RootCA,O=Example,C=US");
caCert.setNotBefore("20250101000000Z");
caCert.setNotAfter("20350101000000Z");
caCert.setPublicKey(caKey.pubKeyObj);
caCert.sign(caKey.prvKeyObj, "sha256WithRSAEncryption");
var caPem = caCert.getPEM();
Ключевые особенности:
Intermediate CA подписывается Root CA и формирует доверенную цепочку.
var intKey = KEYUTIL.generateKeypair("RSA", 2048);
var intCert = new X509();
intCert.setSerialNumberByParam({ int: 2 });
intCert.setIssuerName("CN=RootCA,O=Example,C=US");
intCert.setSubjectName("CN=IntermediateCA,O=Example,C=US");
intCert.setNotBefore("20250101000000Z");
intCert.setNotAfter("20300101000000Z");
intCert.setPublicKey(intKey.pubKeyObj);
intCert.sign(caKey.prvKeyObj, "sha256WithRSAEncryption");
var intPem = intCert.getPEM();
На этом уровне формируется разделение доверия: Root CA используется только для подписи Intermediate CA.
Конечный сертификат используется для TLS или подписи данных.
var endKey = KEYUTIL.generateKeypair("RSA", 2048);
var endCert = new X509();
endCert.setSerialNumberByParam({ int: 3 });
endCert.setIssuerName("CN=IntermediateCA,O=Example,C=US");
endCert.setSubjectName("CN=service.example.com,O=Example,C=US");
endCert.setNotBefore("20250101000000Z");
endCert.setNotAfter("20260101000000Z");
endCert.setPublicKey(endKey.pubKeyObj);
endCert.sign(intKey.prvKeyObj, "sha256WithRSAEncryption");
var endPem = endCert.getPEM();
Здесь Issuer совпадает с Intermediate CA, формируя цепочку:
Root CA → Intermediate CA → End Entity
Цепочка проверяется последовательной валидацией подписей:
Jsrsasign позволяет проверять подписи сертификатов:
var cert = new X509();
cert.readCertPEM(endPem);
var pubKey = intKey.pubKeyObj;
var isValid = cert.verifySignature(pubKey);
Для полной цепочки проверка выполняется каскадно.
PKI используется не только для TLS, но и для цифровых подписей.
var sig = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
sig.init(endKey.prvKeyObj);
sig.updateString("critical data");
var signatureHex = sig.sign();
Проверка:
var verifier = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
verifier.init(endKey.pubKeyObj);
verifier.updateString("critical data");
var result = verifier.verify(signatureHex);
Jsrsasign поддерживает преобразования:
Пример загрузки сертификата:
var cert = new X509();
cert.readCertPEM(pemString);
Извлечение публичного ключа:
var pubKey = cert.getPublicKey();
Расширения определяют назначение сертификата:
Пример установки расширений:
cert.setExtBasicConstraints({ cA: true, critical: true });
cert.setExtKeyUsage(["keyCertSign", "cRLSign"]);
Для конечных сертификатов:
cert.setExtKeyUsage(["digitalSignature", "keyEncipherment"]);
Проверка роли сертификата осуществляется через расширения:
cA=truecA=falseЭто важно при построении цепочки доверия, чтобы исключить использование end-entity сертификата как промежуточного центра.
PKI на Jsrsasign часто используется для:
Пример проверки подписи JWT-подобного токена:
var sig = new KJUR.crypto.Signature({ alg: "SHA256withRSA" });
sig.init(pubKey);
sig.updateString(header + "." + payload);
var verified = sig.verify(signature);
Каждый сертификат содержит:
Проверка актуальности:
var now = new Date();
var notBefore = cert.getNotBefore();
var notAfter = cert.getNotAfter();
var isActive = (now >= notBefore && now <= notAfter);
Отзыв сертификатов в простых системах моделируется через CRL (Certificate Revocation List), который можно реализовать вручную как список серийных номеров.
Полноценная минимальная схема включает:
Jsrsasign позволяет реализовать эту модель полностью в JavaScript без внешних криптографических сервисов, опираясь на встроенные ASN.1 структуры и криптографические алгоритмы RSA и ECDSA