Что такое сертификат

Сертификат X.509 — это подписанное заявление, связывающее открытый ключ с идентичностью. Когда браузер подключается к сайту по HTTPS, сервер предъявляет сертификат, который, по сути, говорит: «этот открытый ключ принадлежит test.ronutz.com, и удостоверяющий центр за это ручается». Профиль, определяющий, какие поля несёт сертификат и как они интерпретируются, — это RFC 5280.

Связывание — вот что важно. Любой может сгенерировать пару ключей, так что голый открытый ключ ничего не доказывает о том, кто на другом конце. Сертификат добавляет подпись издателя, которому полагающаяся сторона уже доверяет, превращая анонимный ключ в ключ с прикреплённым именем. Это основа веб-инфраструктуры открытых ключей ().

Цепочка доверия

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

Root CA  (self-signed, in the OS/browser trust store)
   |  signs
Intermediate CA
   |  signs
Leaf / end-entity certificate  (test.ronutz.com)

Каждое звено — это подпись: издатель подписывает сертификат потомка приватным ключом издателя, а проверяющий сверяет эту подпись открытым ключом издателя. Корень самовыпущен и самоподписан, поэтому самоподписанный сертификат — полезный локальный заменитель корня, но не несёт никакого внешнего авторитета. Инструмент X.509 отмечает самовыпущенный сертификат (издатель равен субъекту) и помечен ли сертификат как , и то и другое говорит вам, где сертификат находится на этой картине.

ASN.1 и DER: раскладка байтов

Сертификат — это не JSON и не текст. Он описан в .1 (Abstract Syntax Notation One) и закодирован Distinguished Encoding Rules (), определёнными в ITU-T X.690. DER — это формат tag-length-value (TLV): каждый элемент начинается с байта тега, говорящего, какого он типа, затем длина, затем столько байтов содержимого. Конструируемые типы вроде SEQUENCE и SET содержат дочерние элементы, так что весь сертификат — это дерево TLV.

Файл — это просто тот DER, закодированный в Base64 и обёрнутый в строки брони:

-----BEGIN CERTIFICATE-----
MIIELDCCAxSgAwIBAgIG...    (Base64 of the DER)
-----END CERTIFICATE-----

Так что декодировать сертификат означает снять броню, декодировать из Base64 в DER, а затем обойти дерево TLV. Инструмент X.509 делает ровно это в вашем браузере, без библиотеки и без сетевого вызова.

Структура верхнего уровня

На самом внешнем уровне RFC 5280 определяет три части:

Certificate ::= SEQUENCE {
  tbsCertificate       TBSCertificate,
  signatureAlgorithm   AlgorithmIdentifier,
  signatureValue       BIT STRING
}

tbsCertificate («to be signed», подлежащий подписи) содержит всё реальное содержимое. signatureAlgorithm называет, как издатель его подписал, например sha256WithRSAEncryption или ecdsa-with-SHA256. signatureValue — это сама подпись, вычисленная над байтами DER tbsCertificate. За этот последний пункт стоит держаться: подпись покрывает подлежащее-подписи тело ровно так, как закодировано, поэтому даже изменение в один байт где угодно в теле ломает проверку.

Внутри TBSCertificate

Подлежащее-подписи тело — это где инструмент проводит большую часть своего времени:

  • Версия почти всегда v3, версия, которая ввела расширения.
  • Серийный номер — большое целое число, которое назначает издатель. В сочетании с именем издателя он однозначно идентифицирует сертификат, и именно на него ссылается список отзыва.
  • Издатель (Issuer) и Субъект (Subject) — это Различающие Имена (Distinguished Names). DN — это последовательность атрибутов вроде CN (common name), O (organization), OU (organizational unit), L (locality), ST (state) и C (country). RFC 4514 определяет однострочное, наиболее-конкретное-сначала отображение, которое вы видите, например CN=test.ronutz.com, O=NTZ Technology, C=BR.
  • Срок действия (Validity) — это метки времени notBefore и notAfter. Они закодированы как UTCTime или GeneralizedTime; инструмент конвертирует обе в ISO-8601 и, против ваших локальных часов, говорит вам, действителен ли сертификат сейчас, ещё-не-действителен или истёк.
  • subjectPublicKeyInfo несёт открытый ключ плюс его алгоритм. Для инструмент сообщает размер модуля (например, 2048-bit) и открытую экспоненту (почти всегда 65537). Для ключей на эллиптических кривых он сообщает именованную кривую (P-256, P-384, P-521), согласно RFC 5480.

Расширения v3

Расширения — это где современные сертификаты кодируют большую часть своей политики. У каждого расширения есть идентификатор, флаг критичности и значение. Флаг критичности важен: если полагающаяся сторона не понимает расширение, помеченное как критическое, она должна отклонить сертификат, а не игнорировать поле. Инструмент декодирует те, что несут наибольший вес:

  • Subject Alternative Name () перечисляет идентичности, для которых сертификат действительно действителен, как DNS-имена, IP-адреса, адреса email или URI. Для TLS это поле, которое проверяют браузеры, а не CN. Сертификат для test.ronutz.com, который опускает это имя из своего SAN, провалит проверку в современном клиенте, даже если CN совпадает.
  • Key Usage ограничивает то, что ключ может делать на низком уровне: digitalSignature, keyEncipherment, keyCertSign, cRLSign и другие. Сертификат CA несёт keyCertSign; лист TLS обычно несёт digitalSignature и keyEncipherment.
  • Extended Key Usage (EKU) называет цели более высокого уровня вроде serverAuth (сервер TLS), clientAuth (клиент TLS), codeSigning или emailProtection.
  • Basic Constraints заявляет, является ли сертификат CA, и если да, сколько промежуточных CA может появиться под ним (длина пути). Это поле останавливает использование листового сертификата для подписи других сертификатов.
  • Subject Key Identifier и Authority Key Identifier — это хеши, позволяющие проверяющему быстро сопоставить сертификат с его издателем при построении цепочки.

Отпечатки

Отпечаток (fingerprint) сертификата — это просто криптографический хеш байтов DER сертификата, обычно (и, для более старых ссылок, SHA-1). Это не поле внутри сертификата; он вычисляется над всем целым. Отпечатки дают вам короткое значение фиксированной длины для сравнения двух сертификатов на равенство или для закрепления известного сертификата. Инструмент вычисляет и SHA-256, и SHA-1 локально с помощью Web Crypto API, так что байты, которые вы вставляете, никогда никуда не отправляются. Подробнее о том, чем хеш является и чем не является, см. статью о хешировании.

Декодирование — не проверка

Это единственная самая важная мысль, и она отражает ту же осторожность, что применяется к JSON Web Tokens. Чтение полей сертификата говорит вам, что он утверждает. Оно не говорит вам, что утверждение истинно. Полная проверка — это отдельный, более тяжёлый процесс: проверить, что подпись цепляется к доверенному корню, что ни один из сертификатов в цепочке не истёк и не отозван, что имя, к которому вы подключились, есть в SAN, и что использования ключа разрешают то, что вы делаете.

Декодировщик сертификатов, включая этот, — это инструмент инспекции и обучения. Он показывает вам в точности, что издатель утверждал и как это было закодировано. Относитесь к выводу как к точному прочтению документа, а не как к вердикту о том, доверять ли ему.