Расширение Key Usage и Extended Key Usage

Расширение Key Usage определяет, для каких криптографических операций может использоваться публичный ключ, содержащийся в сертификате. Это одно из базовых расширений X.509, которое влияет на поведение TLS/SSL, проверку подписи и допустимые сценарии применения сертификата.

В библиотеке Jsrsasign работа с этим расширением осуществляется через ASN.1-структуры и объект X509Ext, который позволяет как анализировать, так и формировать сертификаты с заданными ограничениями.

Основные биты Key Usage

Каждый сертификат может содержать набор флагов, определяющих допустимые операции:

  • digitalSignature — подпись данных (TLS, подпись сообщений)
  • nonRepudiation / contentCommitment — подтверждение неизменности и авторства
  • keyEncipherment — шифрование ключей (например, RSA в TLS)
  • dataEncipherment — шифрование пользовательских данных
  • keyAgreement — обмен ключами (Diffie-Hellman)
  • keyCertSign — подпись сертификатов (CA-сертификаты)
  • cRLSign — подпись списков отзыва сертификатов (CRL)
  • encipherOnly — шифрование при keyAgreement
  • decipherOnly — расшифрование при keyAgreement

Формирование Key Usage в Jsrsasign

В Jsrsasign расширение задаётся через объект расширений при генерации сертификата:

const { KJUR } = require("jsrsasign");

const extObj = [
  {
    extname: "keyUsage",
    critical: true,
    names: [
      "digitalSignature",
      "keyEncipherment"
    ]
  }
];

Далее этот объект передаётся в генерацию сертификата:

const cert = new KJUR.asn1.x509.Certificate({
  version: 3,
  serial: { int: 1 },
  sigalg: "SHA256withRSA",
  issuer: [{ type: "CN", value: "Test CA" }],
  subject: [{ type: "CN", value: "example.com" }],
  notbefore: "230101000000Z",
  notafter: "240101000000Z",
  sbjpubkey: publicKeyObj,
  ext: extObj
});

Критичность (critical: true) означает, что при отсутствии поддержки данного расширения клиент обязан отклонить сертификат.


Extended Key Usage (EKU)

Extended Key Usage уточняет сценарии применения ключа на более высоком уровне, чем Key Usage. Если Key Usage отвечает на вопрос «что технически можно делать с ключом», то EKU определяет «в каком протоколе или контексте это допустимо».

В X.509 EKU представлен OID-ами (Object Identifier), и Jsrsasign поддерживает их в удобном строковом виде.

Основные значения Extended Key Usage

  • serverAuth — аутентификация TLS-сервера
  • clientAuth — аутентификация клиента
  • codeSigning — подпись программного кода
  • emailProtection — защита электронной почты (S/MIME)
  • timeStamping — служба временных меток
  • OCSPSigning — подпись OCSP-ответов
  • anyExtendedKeyUsage — универсальное использование

Создание EKU в Jsrsasign

Расширение добавляется аналогично Key Usage через X509Ext:

const extObj = [
  {
    extname: "extKeyUsage",
    critical: false,
    array: [
      "serverAuth",
      "clientAuth"
    ]
  }
];

При генерации сертификата:

const cert = new KJUR.asn1.x509.Certificate({
  version: 3,
  serial: { int: 2 },
  sigalg: "SHA256withRSA",
  issuer: [{ type: "CN", value: "Test CA" }],
  subject: [{ type: "CN", value: "api.example.com" }],
  notbefore: "230101000000Z",
  notafter: "250101000000Z",
  sbjpubkey: publicKeyObj,
  ext: extObj
});

Совместное использование Key Usage и Extended Key Usage

На практике оба расширения применяются одновременно. Их логика проверяется совместно:

  • Key Usage ограничивает криптографические операции на уровне алгоритма
  • EKU ограничивает контекст применения (TLS-сервер, клиент, подпись кода)

Пример корректной комбинации для TLS-сервера:

ext: [
  {
    extname: "keyUsage",
    critical: true,
    names: ["digitalSignature", "keyEncipherment"]
  },
  {
    extname: "extKeyUsage",
    array: ["serverAuth"]
  }
]

Пример для клиентской аутентификации:

ext: [
  {
    extname: "keyUsage",
    critical: true,
    names: ["digitalSignature"]
  },
  {
    extname: "extKeyUsage",
    array: ["clientAuth"]
  }
]

Чтение Key Usage и EKU из сертификата

Jsrsasign позволяет извлекать расширения из уже существующих сертификатов.

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

Получение Key Usage:

const ku = cert.getExtKeyUsage();
console.log(ku);

Получение Extended Key Usage:

const eku = cert.getExtExtKeyUsage();
console.log(eku);

Результатом обычно являются массивы строковых идентификаторов.


Внутреннее представление и OID

В ASN.1 Key Usage кодируется как BIT STRING, где каждый бит соответствует определённой операции.

Extended Key Usage кодируется как:

ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId

Каждый KeyPurposeId — это OID, например:

  • serverAuth: 1.3.6.1.5.5.7.3.1
  • clientAuth: 1.3.6.1.5.5.7.3.2

Jsrsasign скрывает работу с OID, предоставляя человекочитаемые алиасы.


Типовые ошибки при настройке расширений

Некорректные комбинации Key Usage и EKU приводят к отказу TLS-соединений или ошибкам валидации сертификата.

Распространённые проблемы:

  • Отсутствие digitalSignature при использовании TLS с ECDSA
  • Использование keyEncipherment с ECDSA-сертификатами (не требуется)
  • Несоответствие EKU и назначения сертификата (например, serverAuth для клиентского сертификата)
  • Отсутствие критичности Key Usage в CA-сертификатах

Проверка соответствия расширений политике использования

При разработке инфраструктуры PKI часто требуется строгая проверка:

  • серверные сертификаты должны содержать serverAuth
  • клиентские — clientAuth
  • CA-сертификаты обязаны иметь keyCertSign и cRLSign

Пример CA-сертификата:

ext: [
  {
    extname: "keyUsage",
    critical: true,
    names: ["keyCertSign", "cRLSign"]
  }
]

Практическая интерпретация в TLS-цепочке

При установлении TLS-соединения браузер или клиент выполняет последовательную проверку:

  1. Проверка цепочки доверия
  2. Проверка Key Usage (допустимость подписи и шифрования)
  3. Проверка EKU (соответствие serverAuth/clientAuth)
  4. Проверка домена (SAN)

Jsrsasign используется как на стороне генерации, так и на стороне анализа, что позволяет моделировать поведение реальных TLS-стеков при тестировании PKI-инфраструктуры.