Проверка Key Usage

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

Расширение представляется в виде битовой маски, где каждый бит соответствует определённому назначению:

  • digitalSignature — подпись данных
  • nonRepudiation (или contentCommitment) — неотказуемость
  • keyEncipherment — шифрование ключей
  • dataEncipherment — шифрование данных
  • keyAgreement — согласование ключей
  • keyCertSign — подпись сертификатов
  • cRLSign — подпись списков отзыва
  • encipherOnly — только шифрование (в контексте keyAgreement)
  • decipherOnly — только расшифрование

Представление в ASN.1

В ASN.1 расширение Key Usage определяется как BIT STRING:

KeyUsage ::= BIT STRING {
    digitalSignature        (0),
    nonRepudiation          (1),
    keyEncipherment         (2),
    dataEncipherment        (3),
    keyAgreement            (4),
    keyCertSign             (5),
    cRLSign                 (6),
    encipherOnly            (7),
    decipherOnly            (8)
}

Внутри сертификата это расширение может быть отмечено как critical, что означает обязательность проверки клиентом.

Работа с Key Usage в библиотеке jsrsasign

Библиотека предоставляет инструменты для извлечения, анализа и проверки расширений сертификатов, включая Key Usage.

Получение расширения из сертификата

Для работы используется класс X509:

const x509 = new X509();
x509.readCertPEM(certPEM);

const ext = x509.getExtKeyUsage();

Метод getExtKeyUsage() возвращает массив строк, соответствующих установленным флагам.

Для Key Usage используется:

const keyUsage = x509.getExtKeyUsageString();

или:

const keyUsageBin = x509.getExtKeyUsageBin();

Интерпретация результата

Метод getExtKeyUsageString() возвращает строку вида:

digitalSignature,keyEncipherment

Это упрощённое представление для анализа логики приложения.

Метод getExtKeyUsageBin() возвращает бинарное значение, соответствующее битовой маске, например:

10100000

Каждый бит интерпретируется согласно позиции.

Проверка допустимости операций

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

if (keyUsage.includes("digitalSignature")) {
    // разрешена проверка подписи
}

Проверка возможности шифрования

if (keyUsage.includes("keyEncipherment")) {
    // допустимо использование для обмена ключами
}

Проверка сертификата удостоверяющего центра

if (keyUsage.includes("keyCertSign")) {
    // сертификат может подписывать другие сертификаты
}

Проверка критичности расширения

Важно учитывать, является ли расширение критическим:

const extInfo = x509.getExtInfo("keyUsage");

if (extInfo.critical) {
    // обязательная проверка соответствия
}

Если расширение критическое и приложение его игнорирует — сертификат должен считаться недействительным.

Прямой разбор ASN.1 структуры

В некоторых сценариях требуется доступ к сырому ASN.1:

const hex = x509.getExtHex("keyUsage");

Далее используется ASN.1 парсер:

const asn1 = ASN1HEX.getTLV(hex, 0);

Извлечение битовой строки:

const bitString = ASN1HEX.getV(hex, 0);

Интерпретация выполняется вручную, побитово.

Расширенные сценарии проверки

Проверка цепочки сертификатов

При построении цепочки доверия важно учитывать:

  • Удостоверяющий центр должен иметь keyCertSign
  • Конечный сертификат — не должен иметь этот флаг
function isCA(x509) {
    const ku = x509.getExtKeyUsageString();
    return ku.includes("keyCertSign");
}

Ограничение использования TLS-сертификатов

Для серверных сертификатов ожидается:

  • digitalSignature
  • keyEncipherment

Проверка:

function isValidForTLS(x509) {
    const ku = x509.getExtKeyUsageString();
    return ku.includes("digitalSignature") && ku.includes("keyEncipherment");
}

Связь с Extended Key Usage

Key Usage задаёт базовые ограничения, тогда как Extended Key Usage (EKU) уточняет контекст применения:

  • TLS Web Server Authentication
  • Code Signing
  • Email Protection

В jsrsasign:

const eku = x509.getExtExtKeyUsageName();

Комбинированная проверка:

if (keyUsage.includes("digitalSignature") && eku.includes("serverAuth")) {
    // сертификат подходит для HTTPS
}

Типичные ошибки

Игнорирование Key Usage Использование ключа без проверки может привести к нарушению политики безопасности.

Неверная интерпретация битов Ошибки при работе с бинарным представлением могут привести к ложным выводам.

Пренебрежение критичностью Критические расширения требуют обязательной проверки.

Практический пример

const x509 = new X509();
x509.readCertPEM(certPEM);

const ku = x509.getExtKeyUsageString();

if (!ku.includes("digitalSignature")) {
    throw new Error("Недопустимое использование ключа для подписи");
}

if (ku.includes("keyCertSign")) {
    console.log("Сертификат является удостоверяющим центром");
}

Внутренние механизмы jsrsasign

Библиотека использует ASN.1 парсер для извлечения расширений:

  • Декодирование DER
  • Поиск OID расширения
  • Интерпретация BIT STRING

OID для Key Usage:

2.5.29.15

Внутренний алгоритм:

  1. Найти расширение по OID
  2. Извлечь значение
  3. Преобразовать BIT STRING в читаемый формат
  4. Сопоставить биты с именами флагов

Безопасность и рекомендации

  • Всегда проверять Key Usage перед использованием ключа
  • Учитывать совместимость с Extended Key Usage
  • Не использовать ключи вне разрешённых операций
  • Проверять критичность расширения
  • Валидировать цепочку сертификатов с учётом ограничений

Такая практика обеспечивает корректное применение криптографических механизмов и предотвращает злоупотребления ключевым материалом.