Fingerprint сертификата

В криптографических сертификатах fingerprint (отпечаток) представляет собой короткое хеш-значение, вычисленное от бинарного представления X.509 сертификата. Он используется как компактный идентификатор, позволяющий быстро сравнивать сертификаты без необходимости анализа всей структуры ASN.1.

В контексте работы с Jsrsasign fingerprint обычно вычисляется из DER-представления сертификата с применением криптографических хеш-функций, таких как SHA-1, SHA-256 или SHA-512. На практике наиболее распространены SHA-1 (исторически) и SHA-256 (в современных системах).

X.509 сертификат внутри библиотеки Jsrsasign может быть представлен в PEM или DER формате. Независимо от исходного представления, вычисление отпечатка всегда опирается на DER-байты.

PEM-сертификат предварительно декодируется:

  • удаляются заголовки -----BEGIN CERTIFICATE-----
  • base64 преобразуется в бинарный DER

Далее применяется хеш-функция:

  • SHA-1 → 20 байт (40 hex символов)
  • SHA-256 → 32 байта (64 hex символа)

Базовые операции с X.509 в Jsrsasign

В библиотеке Jsrsasign работа с сертификатами реализована через класс X509:

const cert = `-----BEGIN CERTIFICATE-----
MIID...
-----END CERTIFICATE-----`;

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

После загрузки сертификата доступна DER-структура:

const hex = x509.hex; // DER в hex формате

Этот hex-строковый формат используется для вычисления хеша.

Вычисление SHA-1 fingerprint

SHA-1 отпечаток часто рассматривается как исторический идентификатор сертификата:

const fp = KJUR.crypto.Util.hashHex(x509.hex, 'sha1');
console.log(fp);

Результат представляет собой строку в шестнадцатеричном формате:

a3f1c9e0d2b4...

Для повышения читаемости часто добавляется разделение двоеточиями:

A3:F1:C9:E0:D2:B4:...

SHA-256 fingerprint и современная практика

SHA-256 считается более устойчивым вариантом:

const fp256 = KJUR.crypto.Util.hashHex(x509.hex, 'sha256');

Отпечаток становится длиннее, но обеспечивает более высокий уровень криптографической надежности.

Использование встроенных методов X509

В Jsrsasign предусмотрены вспомогательные методы для получения отпечатков без явного обращения к утилитам хеширования.

Типовой подход:

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

const sha1fp = x509.getFingerprint();

В зависимости от версии библиотеки метод может возвращать SHA-1 отпечаток по умолчанию.

Для SHA-256 используется альтернативная логика:

const sha256fp = KJUR.crypto.Util.hashHex(x509.hex, 'sha256');

Нормализация формата fingerprint

При сравнении отпечатков важно учитывать форматирование. Одно и то же значение может быть представлено:

  • без разделителей
  • с двоеточиями
  • в верхнем или нижнем регистре

Нормализация обычно включает:

function normalize(fp) {
  return fp.replace(/:/g, '').toLowerCase();
}

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

Сравнение сертификатов по fingerprint

Fingerprint используется как ключевой механизм идентификации:

const fp1 = KJUR.crypto.Util.hashHex(certHex1, 'sha256');
const fp2 = KJUR.crypto.Util.hashHex(certHex2, 'sha256');

const isSame = (fp1 === fp2);

Такой подход применяется в системах доверия, проверке цепочек сертификатов и кэшировании.

Внутренняя структура вычисления

Процесс формирования fingerprint в Jsrsasign сводится к следующим шагам:

  1. Парсинг PEM → DER
  2. Получение hex-представления DER
  3. Передача hex в хеш-функцию
  4. Вычисление digest
  5. Преобразование в hex-строку

Фактически fingerprint не зависит от метаданных сертификата как текстовой структуры, а строго привязан к бинарному содержимому.

Практические особенности

Несколько важных технических аспектов:

  • Изменение любого поля сертификата (даже незначительного) полностью меняет fingerprint
  • Разные алгоритмы (SHA-1 vs SHA-256) дают несовместимые идентификаторы
  • Fingerprint сертификата не совпадает с fingerprint публичного ключа, если они вычисляются по разным данным
  • DER-кодирование всегда детерминированно, что обеспечивает стабильность результата

Fingerprint публичного ключа

Отдельный случай — вычисление отпечатка не сертификата, а открытого ключа:

const pubKey = KEYUTIL.getKey(cert);
const pubHex = pubKey.pubKeyHex;

const pubFp = KJUR.crypto.Util.hashHex(pubHex, 'sha256');

Такой fingerprint используется для идентификации ключа независимо от сертификата.

Ошибки при вычислении fingerprint

На практике встречаются типовые проблемы:

  • использование PEM напрямую без декодирования
  • попытка хешировать строку сертификата вместо DER
  • несоответствие алгоритма при сравнении двух отпечатков
  • различие в регистре и разделителях

Корректная схема всегда опирается на DER-представление как источник истины.

Представление в инфраструктуре X.509

Fingerprint становится основой для:

  • хранения доверенных сертификатов
  • проверки pinned certificates
  • идентификации промежуточных CA
  • журналирования TLS-сессий

В криптографических системах он выступает как компактный суррогат всей структуры сертификата, позволяющий выполнять сравнение за O(1) по длине строки вместо анализа ASN.1 дерева.