Построение OCSP-запроса: KJUR.asn1.ocsp

jsrsasign предоставляет полноценный набор инструментов для работы с криптографическими структурами, включая ASN.1-деревья, X.509, PKCS


Архитектура OCSP-запроса в ASN.1

OCSP-запрос (Online Certificate Status Protocol Request) представляет собой ASN.1-структуру OCSPRequest, которая включает:

  • TBSRequest (To Be Signed Request)
  • OptionalSignature (подпись запроса, если используется)
  • requestList (набор идентификаторов сертификатов)
  • extensions (например, nonce для защиты от replay-атак)

В jsrsasign вся модель разбита на набор конструкторов в KJUR.asn1.ocsp, где каждая ASN.1-сущность соответствует отдельному классу.


Основной модуль KJUR.asn1.ocsp

Пространство имён KJUR.asn1.ocsp содержит ключевые классы:

  • OCSPRequest
  • TBSRequest
  • Request
  • RequestList
  • CertID
  • Signature
  • ResponseData (используется уже на стороне ответа, но связан с моделью запроса)

Каждый класс строит ASN.1 объект через базовые примитивы KJUR.asn1.DERSequence, DERInteger, DEROctetString, DERObjectIdentifier.


Формирование идентификатора сертификата (CertID)

Центральный элемент OCSP-запроса — CertID. Он определяет, какой сертификат проверяется.

Структура CertID:

  • hash алгоритм (обычно SHA-1 или SHA-256)
  • issuerNameHash
  • issuerKeyHash
  • serialNumber

В jsrsasign это реализуется через:

var certID = new KJUR.asn1.ocsp.CertID({
  hashAlg: "sha1",
  issuerCert: issuerCertObj,
  subjectCert: targetCertObj
});

При этом библиотека автоматически:

  • извлекает issuer name
  • вычисляет хэш имени
  • извлекает публичный ключ issuer
  • вычисляет key hash
  • кодирует serialNumber в ASN.1 INTEGER

Построение OCSP RequestList

RequestList представляет массив запросов к OCSP responder.

Каждый элемент — это структура Request, содержащая:

  • reqCert (CertID)
  • singleRequestExtensions (опционально)

Пример создания:

var request = new KJUR.asn1.ocsp.Request({
  reqCert: certID
});

var requestList = [request];

Внутри RequestList формируется ASN.1 Sequence, содержащая множество Request.


TBSRequest: ядро OCSP-запроса

TBSRequest (To Be Signed Request) является основной частью запроса до подписи.

Он включает:

  • version (обычно v1)
  • requestorName (опционально)
  • requestList
  • requestExtensions

Формирование:

var tbsReq = new KJUR.asn1.ocsp.TBSRequest({
  reqList: requestList,
  extensions: [
    {
      extname: "nonce",
      value: "AUTO"
    }
  ]
});

Использование nonce-расширения

Nonce используется для предотвращения replay-атак. jsrsasign поддерживает автоматическую генерацию:

  • случайного значения
  • или заданного буфера

ASN.1 структура:

id-pkix-ocsp-nonce OBJECT IDENTIFIER ::= { id-pkix-ocsp 2 }

В jsrsasign:

extensions: [
  { extname: "nonce", value: "hex:01aabbcc" }
]

или автоматический режим:

{ extname: "nonce", value: "AUTO" }

OCSPRequest как итоговая структура

Финальный объект OCSPRequest объединяет все части:

var ocspReq = new KJUR.asn1.ocsp.OCSPRequest({
  tbsRequest: tbsReq
});

ASN.1 структура:

OCSPRequest ::= SEQUENCE {
  tbsRequest             TBSRequest,
  optionalSignature      [0] EXPLICIT Signature OPTIONAL
}

Подпись OCSP-запроса

Хотя многие OCSP-запросы не подписываются, спецификация допускает Signature.

В jsrsasign:

var signedOCSPReq = new KJUR.asn1.ocsp.OCSPRequest({
  tbsRequest: tbsReq,
  certs: [signerCert],
  sigalg: "SHA256withRSA",
  prvkey: privateKey
});

Подпись включает:

  • алгоритм подписи
  • сертификат подписанта
  • приватный ключ

Библиотека формирует:

  • Signature AlgorithmIdentifier
  • BIT STRING подписи
  • опциональный сертификатный блок

ASN.1 представление OCSP-запроса

Внутренняя структура после сериализации:

OCSPRequest
 ├── TBSRequest
 │    ├── version
 │    ├── requestList
 │    │     └── Request
 │    │           └── CertID
 │    └── extensions
 └── signature (optional)

Пример полного построения OCSP-запроса

var issuerCert = X509.loadCert(issuerPem);
var targetCert = X509.loadCert(targetPem);

var certID = new KJUR.asn1.ocsp.CertID({
  hashAlg: "sha256",
  issuerCert: issuerCert,
  subjectCert: targetCert
});

var request = new KJUR.asn1.ocsp.Request({
  reqCert: certID
});

var tbsReq = new KJUR.asn1.ocsp.TBSRequest({
  reqList: [request],
  extensions: [
    { extname: "nonce", value: "AUTO" }
  ]
});

var ocspReq = new KJUR.asn1.ocsp.OCSPRequest({
  tbsRequest: tbsReq
});

var der = ocspReq.getEncodedHex();

Работа с DER-выходом

Результат getEncodedHex() возвращает DER-кодировку:

  • hex-строка ASN.1 структуры
  • пригодна для Base64 упаковки
  • используется в HTTP OCSP запросах

Часто применяется:

var b64 = hextob64(der);

и далее передаётся:

Content-Type: application/ocsp-request

Особенности реализации KJUR.asn1.ocsp

Ключевые особенности:

  • строгая привязка к RFC 6960
  • автоматическое вычисление хэшей
  • поддержка SHA-1 и SHA-256
  • совместимость с RSA и ECDSA подписанием
  • построение ASN.1 без внешних зависимостей

CertID и тонкости хэширования

Hash вычисляется по строгим правилам:

  • issuerNameHash = H(DER(Name))
  • issuerKeyHash = H(subjectPublicKey BIT STRING)

Где H — выбранная хэш-функция.

Ошибки в CertID приводят к:

  • отсутствию ответа OCSP responder
  • статусу unknown

Расширения OCSPRequest

Помимо nonce, поддерживаются:

  • service locator (редко используется)
  • custom extensions через OID

Формат:

{
  extname: "custom",
  extnID: "1.2.3.4.5",
  extnValue: "hex:..."
}

Внутренняя модель Request

KJUR.asn1.ocsp.Request является тонкой обёрткой:

  • содержит CertID
  • сериализуется в ASN.1 SEQUENCE
  • может включать singleRequestExtensions

Пример расширения запроса:

{
  reqCert: certID,
  singleRequestExtensions: [
    { extname: "nonce", value: "AUTO" }
  ]
}

Производительность и ограничения

Генерация OCSP-запросов в jsrsasign:

  • не требует криптографического backend
  • работает синхронно
  • полностью CPU-bound

Основные ограничения:

  • отсутствие потоковой обработки ASN.1
  • высокая стоимость при массовой генерации CertID

Связь с X.509 моделью

OCSP-запросы опираются на:

  • X.509 issuer certificate
  • serial number target certificate

jsrsasign использует внутренние парсеры X.509 для:

  • извлечения subjectPublicKeyInfo
  • нормализации Distinguished Name
  • DER-канонизации

Типичные ошибки при построении

  • неправильный hashAlg (несовместимость с responder)
  • несоответствие issuerCert
  • отсутствие nonce при строгих responder
  • неправильная DER-кодировка имени