Разбор CSR

Запрос на подпись сертификата (Certificate Signing Request, CSR) в формате PKCS#10 представляет собой ASN.1-структуру, содержащую открытый ключ и атрибуты субъекта, подписанные приватным ключом. В контексте JavaScript-библиотеки Jsrsasign работа с CSR строится вокруг декодирования ASN.1 и извлечения полей X.500 имени, расширений и криптографической подписи.

Базовая структура CSR включает:

  • Subject (DN — Distinguished Name)
  • Subject Public Key Info
  • Attributes (опционально)
  • Signature Algorithm
  • Signature Value

В ASN.1-терминах CSR описывается как:

CertificationRequest ::= SEQUENCE {
  certificationRequestInfo CertificationRequestInfo,
  signatureAlgorithm AlgorithmIdentifier,
  signature BIT STRING
}

Ключевая часть — CertificationRequestInfo, именно она подписывается приватным ключом и затем проверяется при валидации CSR.


Работа с CSR в Jsrsasign

В библиотеке Jsrsasign основная точка входа для анализа CSR — модуль KJUR.asn1.csr.CSRUtil.

Парсинг PEM-формата CSR:

const csrPEM = `
-----BEGIN CERTIFICATE REQUEST-----
MIIC...
-----END CERTIFICATE REQUEST-----
`;

const info = KJUR.asn1.csr.CSRUtil.getInfo(csrPEM);
console.log(info);

getInfo выполняет полное декодирование структуры и возвращает объект с уже интерпретированными полями:

  • subject
  • subjectPublicKeyInfo
  • signatureAlgorithm
  • attributes (если есть)

Извлечение Subject (DN)

Distinguished Name в CSR представлен в виде X.500 структуры и включает такие поля, как CN, O, OU, C.

Пример извлечения:

const info = KJUR.asn1.csr.CSRUtil.getInfo(csrPEM);

console.log(info.subject.str);

Типичный результат:

CN=example.com, O=Example Corp, C=US

Для более детальной работы можно разобрать структуру по компонентам:

info.subject.array.forEach(rdn => {
  console.log(rdn.type, rdn.value);
});

Работа с открытым ключом из CSR

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

const pubKeyObj = KEYUTIL.getKey(info.subjectPublicKeyInfo);
console.log(pubKeyObj);

В зависимости от алгоритма (RSA, EC) объект будет иметь разные методы и параметры:

  • RSA: модуль и экспонента
  • EC: кривая и точка

Проверка подписи CSR

Одной из ключевых операций является проверка, что CSR действительно подписан соответствующим приватным ключом.

Jsrsasign позволяет выполнить валидацию автоматически:

const isValid = KJUR.asn1.csr.CSRUtil.verify(csrPEM);
console.log(isValid);

Внутри происходит:

  1. Извлечение certificationRequestInfo
  2. Вычисление хэша
  3. Проверка подписи с использованием public key

Если подпись некорректна или CSR был изменён, результат будет false.


Алгоритм подписи CSR

CSR содержит поле signatureAlgorithm, которое определяет используемый криптографический алгоритм:

Примеры:

  • SHA256withRSA
  • SHA384withECDSA
  • SHA512withRSA

Извлечение:

console.log(info.signatureAlgorithm.name);
console.log(info.signatureAlgorithm.param);

Это важно при проверке совместимости с серверной стороной (CA).


Атрибуты и расширения CSR

Хотя CSR PKCS#10 формально ограничен атрибутами, современные реализации часто используют их для передачи расширений сертификата.

Часто встречается атрибут:

  • extensionRequest (OID 1.2.840.113549.1.9.14)

Пример извлечения:

const attrs = info.attributes;

attrs.forEach(attr => {
  console.log(attr.name, attr.value);
});

Если присутствует extensionRequest, внутри могут быть:

  • Subject Alternative Name (SAN)
  • Key Usage
  • Extended Key Usage

Разбор Subject Alternative Name (SAN)

SAN является критически важным расширением, определяющим дополнительные домены или IP-адреса.

const ext = KJUR.asn1.x509.X509Util.getExtInfo(info.attributes);

console.log(ext.subjectAltName);

Пример содержимого:

DNS:example.com, DNS:www.example.com, IP:192.168.1.1

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

Jsrsasign поддерживает оба формата CSR:

PEM → объект

const info = KJUR.asn1.csr.CSRUtil.getInfo(pem);

DER (Base64/Hex)

const hexCSR = hextorstr(PEMtoHex(csrPEM));
const info = KJUR.asn1.csr.CSRUtil.getInfo(hexCSR);

Преобразование особенно важно при работе с API, которые возвращают бинарные данные.


Проверка соответствия публичного ключа и подписи

Внутренняя логика CSR предполагает, что подпись создаётся приватным ключом, соответствующим публичному.

Jsrsasign позволяет вручную проверить это через криптографические primitives:

const csr = new KJUR.asn1.csr.CSR();
csr.readCertPEM(csrPEM);

const pubKey = csr.getPublicKey();
const sigValid = csr.verifySignature();

console.log(sigValid);

Типичные ошибки при разборе CSR

Часто встречаются следующие проблемы:

Некорректный PEM формат

  • отсутствуют BEGIN/END строки
  • лишние пробелы или переносы

Несовпадение алгоритмов

  • CSR подписан ECDSA, а проверка идёт как RSA

Повреждённый ASN.1

  • обрезанный Base64 блок
  • неверная длина BIT STRING

Извлечение полной структуры CSR

Для глубокого анализа можно получить сырой ASN.1 объект:

const csr = new KJUR.asn1.csr.CSR(csrPEM);
const asn1 = csr.getASN1();

console.log(JSON.stringify(asn1, null, 2));

Это позволяет увидеть:

  • точную структуру SEQUENCE
  • OID алгоритмов
  • вложенные SET/SEQUENCE
  • raw значения полей

Практическое использование CSR в цепочке сертификатов

CSR в Jsrsasign часто используется в следующих сценариях:

  • генерация запроса для CA
  • проверка входящих сертификатных заявок
  • извлечение SAN перед выдачей сертификата
  • автоматизация TLS инфраструктуры

Типичный поток:

  1. Генерация ключевой пары
  2. Формирование CSR
  3. Отправка CSR на CA
  4. Проверка CSR на стороне сервера
  5. Выпуск X.509 сертификата

Анализ публичного ключа внутри CSR

Для RSA ключа:

const key = KEYUTIL.getKey(info.subjectPublicKeyInfo);

console.log(key.n.toString(16)); // modulus
console.log(key.e.toString(16)); // exponent

Для EC:

console.log(key.curveName);
console.log(key.pubKeyHex);

Это позволяет определить параметры криптосистемы до выдачи сертификата.


Проверка соответствия CSR требованиям CA

Перед принятием CSR часто проверяют:

  • длину RSA ключа (минимум 2048)
  • наличие SAN
  • корректность CN
  • допустимость алгоритма подписи

Jsrsasign позволяет собрать все данные в одном объекте и выполнить валидацию без внешних зависимостей.


Внутреннее устройство CSRUtil

CSRUtil в Jsrsasign выполняет несколько этапов:

  1. Декодирование PEM → ASN.1
  2. Разбор CertificationRequestInfo
  3. Интерпретация X.500 DN
  4. Извлечение SubjectPublicKeyInfo
  5. Разбор атрибутов
  6. Проверка signatureAlgorithm

Этот слой абстракции избавляет от необходимости ручного анализа ASN.1 дерева.


Работа с нестандартными CSR

Некоторые CSR содержат расширенные атрибуты:

  • challengePassword
  • unstructuredName
  • custom OID extensions

Jsrsasign не всегда интерпретирует их автоматически, но позволяет получить raw значения через ASN.1 дерево и разобрать вручную через OID-маппинг.

info.attributes.forEach(attr => {
  console.log(attr.oid, attr.valueHex);
});

Разбор CSR на уровне криптографического хеша

Валидация подписи CSR основана на вычислении хеша от certificationRequestInfo.

Процесс:

hash = H(certificationRequestInfo)
verify(signature, hash, publicKey)

Jsrsasign скрывает эти операции, но логически они соответствуют стандарту PKCS#10 и X.509.


Интеграция CSR с генерацией X.509 сертификатов

После анализа CSR он может быть использован для создания сертификата:

const cert = new KJUR.asn1.x509.Certificate();

cert.setSubject(info.subject);
cert.setPublicKey(info.subjectPublicKeyInfo);
cert.sign(caPrivateKey, "SHA256withRSA");

CSR здесь выступает источником доверенных параметров субъекта.