PKCS#10: запрос на сертификат (CSR)

Запрос на сертификат в формате PKCS#10 представляет собой ASN.1-структуру, содержащую сведения о субъекте, его открытый ключ и цифровую подпись, подтверждающую владение соответствующим приватным ключом. В контексте JavaScript и библиотеки jsrsasign этот процесс сводится к формированию объекта CertificationRequest, его кодированию в DER и последующему преобразованию в PEM.

CSR включает несколько ключевых компонентов:

  • Subject (DN — Distinguished Name)
  • Public Key (RSA, ECDSA и др.)
  • Signature Algorithm
  • Signature Value
  • Optional Attributes (например, extensions)

ASN.1-структура PKCS#10

Внутреннее представление CSR описывается следующей логикой:

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

Ключевая часть — CertificationRequestInfo:

CertificationRequestInfo ::= SEQUENCE {
  version INTEGER,
  subject Name,
  subjectPKInfo SubjectPublicKeyInfo,
  attributes [0] IMPLICIT SET OF Attribute
}

Именно эта структура подписывается приватным ключом.


Подготовка ключевой пары

В jsrsasign генерация или загрузка ключа выполняется через KEYUTIL.

Генерация RSA-ключа

const kp = KEYUTIL.generateKeypair("RSA", 2048);

const privateKey = kp.prvKeyObj;
const publicKey = kp.pubKeyObj;

Импорт существующего PEM-ключа

const privateKey = KEYUTIL.getKey(pemPrivateKey);

Формирование Subject Distinguished Name

DN описывает владельца сертификата и включает стандартные атрибуты:

  • CN — Common Name
  • O — Organization
  • OU — Organizational Unit
  • C — Country
  • L — Locality
  • ST — State

Формат в jsrsasign:

const subject = [
  { C: "KZ" },
  { ST: "Karaganda Region" },
  { L: "Karaganda" },
  { O: "Example Org" },
  { OU: "IT Department" },
  { CN: "example.com" }
];

Создание CSR через KJUR.asn1.csr.CertificationRequest

Основной класс для работы с PKCS#10 — KJUR.asn1.csr.CertificationRequest.

Базовый пример RSA CSR

const csr = new KJUR.asn1.csr.CertificationRequest({
  subject: {
    str: "/C=KZ/ST=Karaganda/L=Karaganda/O=Example Org/OU=IT/CN=example.com"
  },
  sbjpubkey: publicKey,
  sigalg: "SHA256withRSA",
  sbjprvkey: privateKey
});

const pem = csr.getPEM();

Формирование CSR с расширениями (SAN)

Subject Alternative Name используется для указания дополнительных доменных имён.

В jsrsasign расширения задаются через ASN.1-конструкторы.

const ext = [
  {
    extname: "subjectAltName",
    array: [
      { dns: "example.com" },
      { dns: "www.example.com" },
      { dns: "api.example.com" }
    ]
  }
];

Подключение расширений:

const csr = new KJUR.asn1.csr.CertificationRequest({
  subject: {
    str: "/CN=example.com/O=Example Org/C=KZ"
  },
  sbjpubkey: publicKey,
  sbjprvkey: privateKey,
  sigalg: "SHA256withRSA",
  extreq: ext
});

Использование ECDSA вместо RSA

Поддерживаются алгоритмы на эллиптических кривых.

Генерация EC ключа

const kp = KEYUTIL.generateKeypair("EC", "secp256r1");

CSR с ECDSA

const csr = new KJUR.asn1.csr.CertificationRequest({
  subject: {
    str: "/CN=example.com/O=Example Org/C=KZ"
  },
  sbjpubkey: kp.pubKeyObj,
  sbjprvkey: kp.prvKeyObj,
  sigalg: "SHA256withECDSA"
});

const pem = csr.getPEM();

Кодирование и форматы вывода

CSR обычно представляется в двух формах:

PEM

Base64-обёртка:

-----BEGIN CERTIFICATE REQUEST-----
MIIC...
-----END CERTIFICATE REQUEST-----

DER

Бинарный формат, используемый внутри TLS и криптографических библиотек.

В jsrsasign:

const der = csr.getEncodedHex();

Проверка CSR

Проверка корректности включает:

  • соответствие подписи
  • целостность Subject
  • валидность публичного ключа
const result = KJUR.asn1.csr.CSRUtil.verifyCSR(pem);

Возвращаемое значение true означает корректную подпись.


Разбор CSR

Извлечение данных из CSR:

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

Структура результата:

  • subject
  • public key algorithm
  • extensions
  • signature algorithm

Добавление атрибутов

PKCS#10 позволяет включать произвольные атрибуты, например challengePassword или extensionRequest.

Пример:

const csr = new KJUR.asn1.csr.CertificationRequest({
  subject: {
    str: "/CN=example.com"
  },
  sbjpubkey: publicKey,
  sbjprvkey: privateKey,
  sigalg: "SHA256withRSA",
  attrs: [
    {
      extname: "challengePassword",
      value: "secret"
    }
  ]
});

Частые ошибки при формировании CSR

Некорректное использование jsrsasign обычно связано с несколькими проблемами:

  • несоответствие публичного и приватного ключа
  • неправильный формат DN строки
  • отсутствие подписи алгоритма (sigalg)
  • использование неподдерживаемых кривых EC
  • неправильная структура SAN расширений

Работа с PEM ключами и CSR в одном контексте

Типичный поток обработки:

  1. Генерация ключа
  2. Формирование Subject
  3. Добавление SAN
  4. Подписание CSR
  5. Экспорт PEM
const kp = KEYUTIL.generateKeypair("RSA", 2048);

const csr = new KJUR.asn1.csr.CertificationRequest({
  subject: {
    str: "/C=KZ/O=Example/CN=example.com"
  },
  sbjpubkey: kp.pubKeyObj,
  sbjprvkey: kp.prvKeyObj,
  sigalg: "SHA256withRSA",
  extreq: [
    {
      extname: "subjectAltName",
      array: [{ dns: "example.com" }]
    }
  ]
});

const csrPEM = csr.getPEM();

Внутренняя криптографическая модель подписи

Подпись CSR формируется по следующему принципу:

  1. Хэширование CertificationRequestInfo
  2. Применение алгоритма (RSA/ECDSA)
  3. Формирование BIT STRING подписи
  4. Встраивание в ASN.1 структуру

Для RSA используется схема PKCS#1 v1.5 или PSS (в зависимости от конфигурации).


Совместимость с X.509 инфраструктурой

CSR, созданный через jsrsasign, полностью совместим с:

  • OpenSSL
  • Let’s Encrypt ACME API
  • корпоративными CA
  • HSM-инфраструктурами (при экспорте ключей)

Типовая диагностика CSR через OpenSSL

Сгенерированный PEM можно проверить:

openssl req -in request.pem -text -noout

Это помогает сопоставить структуру jsrsasign с реальной ASN.1 моделью.