Тема 14

Электронная подпись и инфраструктура открытых ключей

Электронная подпись и инфраструктура открытых ключей

Открытый ключ сам по себе — просто число. Он ничего не говорит о том, кому принадлежит, и не мешает подменить его по дороге. Вся практическая криптография упирается в вопрос, который математика решить не может: как связать ключ с именем и как эту связь передать третьей стороне так, чтобы ей можно было поверить. Ответом стала инфраструктура открытых ключей (англ. Public Key Infrastructure, PKI) — сертификаты, удостоверяющие центры, цепочки доверия и механизмы отзыва.

Сертификат X.509 — это подписанное утверждение вида «открытый ключ такой-то принадлежит субъекту такому-то, действует с такого-то числа по такое-то и годится для таких-то целей». Утверждение подписано удостоверяющим центром, которому доверяет проверяющая сторона. Доверие не вычисляется — оно приходит извне, из хранилища корневых сертификатов, установленного вместе с операционной системой или браузером.

Тема устроена как разбор этого механизма. Сначала — зачем нужен сертификат и что юридически означает «электронная подпись» в России. Затем — устройство X.509: поля, расширения, разбор настоящего сертификата. После — удостоверяющие центры, построение и проверка цепочки, типичные ошибки. Далее — отзыв: CRL, OCSP и печально известная проблема «отзыв не работает». Завершают тему прозрачность сертификатов, инциденты вроде DigiNotar и альтернативные модели доверия — от PGP до Sigstore.

Инфраструктура росла вместе с вебом. В 1990-е сертификаты выдавали университеты и небольшие коммерческие УЦ, браузеры доверяли десяткам корней, а проверка часто сводилась к «подпись сходится — значит, всё в порядке». К 2020-м число корней в хранилищах выросло до сотен, появились обязательные требования CA/Browser Forum, аудит и правила выпуска. Сегодняшняя PKI — компромисс между удобством (любой сайт получает сертификат за минуту) и риском (любой из сотен УЦ теоретически может выпустить сертификат на любой домен).

Паспорт темы. Нужно знать: темы 8, 12, 13. Освоите: читать сертификат X.509 и его расширения; строить и проверять цепочку; работать с CRL и OCSP; объяснять Certificate Transparency; разбирать инциденты и альтернативные модели доверия. Проверяет: ЛР 14. Минимум: разделы 1–4. Углубление: разделы 5–6.

Зачем нужен сертификат

Открытый ключ без имени

Представим, что Алиса получила открытый ключ Боба. Чем он подтверждён? Ничем. Если ключ пришёл по сети, его мог подменить любой посредник — и тогда Алиса зашифрует сообщение не Бобу, а тому, кто сидит посередине. Симметричная картина и с подписью: проверив подпись «ключом Боба», Алиса на самом деле проверит её ключом самозванца.

Нужен якорь: утверждение, что ключ принадлежит Бобу, подписанное кем-то, кому Алиса уже доверяет. Если доверять никому нельзя, задачу не решить — это тупик, из которого нет криптографического выхода. PKI не устраняет необходимость доверия, она его локализует: вместо «доверяю любому ключу, который пришёл по сети» — «доверяю сотне корневых сертификатов, установленных в системе».

Формат пришёл из стандарта каталогов X.500: в 1988 году ITU-T описала структуру сертификата, а IETF приняла её для интернета в виде RFC 1422, затем RFC 2459 и, наконец, RFC 5280. Версия 3 с расширениями появилась в 1996 году и с тех пор не менялась — меняются требования к содержимому, а не к синтаксису. Именно поэтому сертификат 1998 года и сертификат 2026-го читаются одним и тем же парсером, хотя набор расширений у них разный.

Сертификат и есть такое утверждение. Формально это структура ASN.1, содержащая открытый ключ, имя субъекта, имя издателя, срок действия, серийный номер, набор расширений и подпись издателя.

Что даёт подпись: три свойства

Электронная подпись (ЭП) обеспечивает три свойства, и их полезно держать раздельно.

  • Целостность. Изменение любого байта подписанного документа делает подпись недействительной.
  • Аутентичность. Подпись подтверждает, что документ создан владельцем закрытого ключа.
  • Неотрекаемость. Владелец не может задним числом отказаться от подписи, не объявив свой ключ скомпрометированным.

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

Стоит отдельно сказать, чем электронная подпись не является. Это не скан подписи, не картинка и не «файл с печатью»: всё это копируется тривиально и не подтверждает ничего. Электронная подпись — результат криптографического преобразования документа закрытым ключом, и проверяется она только открытым ключом из сертификата. Всё остальное — оформление.

Юридический аспект: 63-ФЗ

В России отношения вокруг электронной подписи регулирует Федеральный закон от 06.04.2011 № 63-ФЗ «Об электронной подписи» 6. Он различает три вида подписи, и различие это не техническое, а правовое.

Вид подписиЧто это техническиЮридическая сила
Простая электронная подписьКод, пароль, SMS-код, подтверждение в приложенииПо соглашению сторон; не подтверждает неизменность документа
Усиленная неквалифицированнаяКриптографическая подпись, сертификат от любого УЦПо соглашению сторон, если иное не установлено законом
Усиленная квалифицированнаяПодпись ключом, сертификат аккредитованного УЦ, средства криптозащиты сертифицированы ФСБРавнозначна собственноручной подписи по умолчанию

Квалифицированный сертификат выдаётся аккредитованным удостоверяющим центром, а ключ хранится на сертифицированном носителе. Отсюда практическое следствие: технически корректная подпись, сделанная самодельным ключом, юридически ничего не значит — для суда нужен квалифицированный сертификат и цепочка до аккредитованного УЦ.

Закон также вводит требования к УЦ: лицензирование, хранение документов, немедленное уведомление об отзыве. Всё это — надстройка над PKI, но она объясняет, почему в корпоративном документообороте нельзя «просто сгенерировать ключ»: нужна инфраструктура, которой доверяет контрагент и которую признаёт государство.

Отдельная практическая деталь — машиночитаемые доверенности (МЧД): документ, которым сотрудник получает право подписывать от имени организации. С 2023 года они обязательны для большинства сценариев, и это ещё один слой поверх PKI: сертификат подтверждает личность, доверенность — полномочия. Для проверяющей стороны нужно и то, и другое, и обе цепочки должны сходиться.

Устройство сертификата X.509

Поля

Сертификат версии 3 описан в RFC 5280 1. Упрощённо его структура выглядит так:

Certificate
├── tbsCertificate
│   ├── version                 v3 (2)
│   ├── serialNumber            уникален в пределах УЦ
│   ├── signature               алгоритм подписи (тот же, что снаружи)
│   ├── issuer                  Name издателя (УЦ)
│   ├── validity                notBefore … notAfter
│   ├── subject                 Name владельца
│   ├── subjectPublicKeyInfo    алгоритм + открытый ключ
│   └── extensions              [3] набор расширений v3
└── signatureAlgorithm          алгоритм подписи
└── signatureValue              подпись издателя по tbsCertificate

Подписывается именно tbsCertificate — всё, что в нём есть, защищено подписью. Поля signature внутри и signatureAlgorithm снаружи обязаны совпадать; расхождение — известный источник уязвимостей в парсерах.

Структура сертификата X.509 v3
tbsCertificate — всё, что защищено подписью: версия, серийный номер, издатель, срок, субъект, ключ и расширения; снаружи — алгоритм и значение подписи

serialNumber уникален в пределах одного УЦ, но не глобально. Именно на него ссылаются списки отзыва, поэтому УЦ обязан выдавать серийные номера без повторов и достаточно длинными: современное требование CA/Browser Forum — не менее 64 бит энтропии. Исторические инциденты с короткими серийными номерами приводили к коллизиям и путанице при отзыве.

Сертификат кодируется в DER — каноническом варианте ASN.1 с фиксированной длиной и без необязательных форм записи. Каноничность здесь не эстетика: подпись считается по байтам, и любое расхождение в кодировке меняет результат. Из этого следует практическое правило — парсить сертификат нужно строгим DER-парсером, а не «как получится». История знает уязвимости, где нестрогий парсер принимал два разных набора байтов за один сертификат: один проверялся, другой интерпретировался. Современные библиотеки от таких конструкций защищены, самодельные — нет.

Name — последовательность пар «тип атрибута — значение»: C=RU, O=Severny Uzel, CN=seif.example. Сравнение имён в RFC 5280 задано отдельными правилами (свёртка регистра, пробелов и т. п.), и это ещё одна область, где реализации расходятся.

Расширения

Расширения появились в версии 3 и превратили сертификат из «ключ плюс имя» в полноценный документ с ограничениями. Каждое расширение помечено как критическое или нет: критическое проверяющая сторона обязана понять, а если не понимает — отвергнуть сертификат.

РасширениеЧто задаётОбычно критическое
basicConstraintsЯвляется ли субъект УЦ и сколько УЦ может быть ниже (pathlen)Да
keyUsageДля чего годен ключ: keyCertSign, cRLSign, digitalSignature, keyEnciphermentДа
extendedKeyUsageПрикладные цели: serverAuth, clientAuth, codeSigning, emailProtection, OCSPSigningИногда
subjectAltNameИмена, которые покрывает сертификат: DNS, IP, email, URIНет (но обязательное для TLS)
subjectKeyIdentifierХеш открытого ключа субъектаНет
authorityKeyIdentifierСсылка на ключ издателя — ускоряет построение цепочкиНет
crlDistributionPointsГде взять CRLНет
authorityInfoAccessГде спросить OCSP и где скачать сертификат издателяНет
nameConstraintsКакие имена вправе выпускать этот УЦДа
certificatePoliciesПолитики, под которые выпущен сертификатНет

Два расширения стоит запомнить особо. basicConstraints с CA:TRUE — единственное, что делает сертификат удостоверяющим центром; без него ключ не имеет права подписывать другие сертификаты. Критичность расширения — не формальность. Если клиент встречает критическое расширение, которого не понимает, он обязан отвергнуть сертификат. Так стандарт защищает от ситуации, когда новый ограничитель (скажем, nameConstraints) старый клиент проигнорирует и тем самым обойдёт. На практике это иногда стреляет в обратную сторону: старые устройства отказываются от совершенно корректных сертификатов, потому что не знают какого-то нового расширения.

subjectAltName — единственное место, где проверяется имя сервера; поле CN современные клиенты игнорируют (RFC 9525 7), и сертификат с именем только в CN браузер отвергнет.

Разбор настоящего сертификата

Соберём учебную PKI для «Сейфа» и посмотрим на выпущенный сертификат.

./make-pki.sh pki
openssl x509 -in pki/server.pem -text -noout

Вот фрагмент вывода — ровно то, что стоит уметь читать.

Version: 3 (0x2)
Serial Number: 4096 (0x1000)
Signature Algorithm: ecdsa-with-SHA256
Issuer: C=RU, O=Severny Uzel, CN=Seif Issuing CA 1
Validity
    Not Before: Oct 19 18:26:28 2026 GMT
    Not After : Oct 19 18:26:28 2027 GMT
Subject: C=RU, O=Severny Uzel, CN=seif.example
Public Key Algorithm: id-ecPublicKey
    NIST CURVE: P-256
X509v3 extensions:
    X509v3 Basic Constraints: critical
        CA:FALSE
    X509v3 Key Usage: critical
        Digital Signature
    X509v3 Extended Key Usage:
        TLS Web Server Authentication
    X509v3 Subject Alternative Name:
        DNS:seif.example, DNS:www.seif.example, IP Address:127.0.0.1
    X509v3 CRL Distribution Points:
        URI:http://127.0.0.1:8000/inter.crl
    Authority Information Access:
        OCSP - URI:http://127.0.0.1:8888
        CA Issuers - URI:http://127.0.0.1:8000/inter.der

Читается это так: сертификат выпущен промежуточным УЦ «Seif Issuing CA 1», действует год, ключ — на кривой P-256, субъект — seif.example, и это не УЦ (CA:FALSE), а TLS-сервер (serverAuth). Имя покрывает три значения из SAN: два DNS-имени и адрес 127.0.0.1 — последнее нужно для локальных опытов в лабораторной работе.

Обратите внимание на серийный номер 4096 (0x1000): файл serial в PKI содержит шестнадцатеричное 1000, и OpenSSL читает его именно как hex. Это классическая мелочь, на которой спотыкаются при ручной настройке.

Удостоверяющие центры и цепочки

Иерархия и корни

Корневой УЦ подписывает сам себя: его сертификат — одновременно субъект и издатель, а подпись проверяется его же ключом. Доверие к корню не выводится ниоткуда — он попадает в хранилище доверенных корней (англ. trust store) вместе с системой или браузером. Mozilla, Microsoft, Apple, Google ведут собственные списки, и попадание в них — отдельная процедура с аудитом.

Промежуточный УЦ подписан корнем и подписывает конечные сертификаты. Смысл разделения — безопасность: ключ корня можно держать офлайн, в HSM, и использовать считанные разы в год, а повседневную выдачу вести ключом промежуточного УЦ, который при компрометации отзывается без перевыпуска всего дерева.

Один и тот же УЦ может иметь несколько сертификатов. Это называется кросс-подписью: промежуточный УЦ подписывается двумя корнями сразу, чтобы сертификаты, выпущенные им, проверялись и в старой, и в новой инфраструктуре. Отсюда — альтернативные цепочки: один и тот же конечный сертификат может иметь несколько путей до разных корней. Клиент имеет право построить любой, который сходится, и это ещё одна причина, по которой «проверить цепочку» — не одна функция, а поиск по графу.

Ограничения задаются расширениями: pathlen:0 у промежуточного означает «ниже меня УЦ быть не может, только конечные сертификаты». nameConstraints ограничивает домены, которые УЦ вправе обслуживать, — так корпоративный УЦ не сможет выпустить сертификат на чужой домен даже при компрометации.

Проверка цепочки

Проверка — это построение пути от конечного сертификата до доверенного корня и последовательная проверка каждого звена. В упрощённом виде алгоритм RFC 5280, раздел 6, выглядит так.

  1. Взять конечный сертификат, найти его издателя среди присланных промежуточных и доверенных корней (по имени субъекта и по идентификатору ключа).
  2. Проверить подпись конечного сертификата ключом найденного издателя.
  3. Повторять, пока путь не упрётся в сертификат из хранилища доверенных корней.
  4. Для каждого сертификата пути проверить срок действия на заданный момент времени.
  5. Для каждого сертификата, кроме конечного, проверить basicConstraints: CA:TRUE, keyUsage: keyCertSign, ограничение pathlen и nameConstraints.
  6. Для конечного сертификата проверить extendedKeyUsage под задачу (serverAuth для TLS-сервера) и соответствие имени из subjectAltName запрошенному хосту.
Проверка цепочки сертификатов
Конечный сертификат подписан промежуточным УЦ, промежуточный — корнем; корень должен быть в хранилище доверия, иначе цепочка не замыкается

Ключевая деталь: промежуточные сертификаты, присланные сервером, не являются доверенными. Они лишь помогают построить путь. Доверие даёт только корень из хранилища — иначе любой мог бы прислать свою «цепочку» и объявить её доверенной.

Некоторые клиенты умеют «дотягивать» цепочку: если издатель не прислан, они идут по ссылке caIssuers из расширения authorityInfoAccess и скачивают сертификат УЦ. Удобно — но означает сетевой запрос в процессе проверки, а значит, задержку и ещё одну поверхность атаки. Браузеры так делают не всегда, серверные библиотеки — почти никогда. Правильное решение простое: сервер должен отдавать всю цепочку, кроме корня.

Имя проверяется по subjectAltName по правилам RFC 9525 7: сравнение без учёта регистра, шаблон *.example.com покрывает ровно одну метку слева (api.example.com — да, example.com и a.b.example.com — нет), IP-адреса сравниваются как адреса, а не как строки, и поле CN не рассматривается вовсе.

Ошибки, ломающие цепочку

Диагностика цепочки — навык, который экономит часы. OpenSSL выдаёт коды ошибок, и по ним почти всегда понятно, что не так.

unable to get local issuer certificate     промежуточный не прислан или корень не в хранилище
certificate has expired                    истёк срок действия
certificate is not yet valid               часы сбиты или сертификат из будущего
invalid CA certificate                     у издателя нет CA:TRUE
path length constraint exceeded            нарушен pathlen
certificate signature failure              подпись не сходится с ключом издателя
unsuitable certificate purpose             EKU не тот (например, clientAuth вместо serverAuth)
hostname mismatch                          имя не покрыто subjectAltName
certificate revoked                        серийный номер есть в CRL или OCSP
self-signed certificate in chain           самоподписанный сертификат вместо промежуточного

Последняя ошибка — самая частая в учебной практике: сервер отдаёт только свой сертификат, забыв промежуточный, и клиент видит «не могу найти издателя». Лечится конфигурацией: сервер должен отдавать всю цепочку, кроме корня.

# сервер отдаёт fullchain.pem = server.pem + inter.pem
openssl verify -CAfile pki/root.pem -untrusted pki/chain.pem pki/server.pem
openssl verify -CAfile pki/root.pem -untrusted pki/chain.pem \
    -verify_hostname seif.example -purpose sslserver pki/server.pem

Корпоративные прокси и перехват

Отдельный сюжет — легитимный, с точки зрения компании, перехват TLS. Корпоративный прокси подменяет сертификат, подписывая его собственным УЦ, который установлен в хранилище доверия на рабочих машинах. Для браузера всё корректно: цепочка сходится. Для пользователя это означает, что трафик виден администратору.

Исследование Durumeric и коллег показало, что такие решения часто ослабляют защиту: часть прокси не проверяет цепочку до конца, часть принимает истёкшие сертификаты, часть поддерживает устаревшие версии TLS 11. То есть перехват не просто добавляет точку наблюдения — он нередко понижает стойкость соединения. Практический вывод: наличие в хранилище постороннего корня — это не мелочь, а решение о доверии, которое стоит принимать осознанно.

Отзыв сертификатов

CRL

Список отзыва сертификатов (англ. Certificate Revocation List, CRL) — подписанный УЦ документ со списком серийных номеров, которые больше не действительны, и датой следующего обновления. Клиент скачивает CRL по адресу из crlDistributionPoints и проверяет, нет ли в нём серийного номера интересующего сертификата.

Выпуск CRL в учебной PKI — две команды: отозвать и сгенерировать список.

openssl ca -config conf/inter.cnf -revoke pki/server.pem -batch
openssl ca -config conf/inter.cnf -gencrl -crlexts crl_ext -out pki/inter.crl.pem
openssl verify -CAfile pki/root.pem -untrusted pki/chain.pem \
    -crl_check -CRLfile pki/inter.crl.pem pki/server.pem

Последняя команда завершится с кодом 2 и сообщением:

C=RU, O=Severny Uzel, CN=seif.example
error 23 at 0 depth lookup: certificate revoked
error pki/server.pem: verification failed

Ошибка 23 — «сертификат отозван». Именно этого мы и добивались.

Проблема CRL — размер и свежесть. Для крупного УЦ список содержит сотни тысяч номеров и весит мегабайты; клиент не может скачивать его при каждом соединении. Отсюда интервалы обновления в дни, а значит, отозванный сертификат остаётся действительным ещё сутки-двое.

OCSP и stapling

Протокол OCSP (RFC 6960 2) решает проблему размера: клиент спрашивает про один серийный номер и получает короткий подписанный ответ «good», «revoked» или «unknown». Запрос идёт по HTTP на адрес из authorityInfoAccess.

Чтобы УЦ не подписывал каждый ответ своим ключом, ответы делегируются отдельному сертификату с расширением extendedKeyUsage: OCSPSigning — такому сертификату разрешено подписывать ответы от имени УЦ. Именно так устроен ocsp.pem в учебной PKI.

# первый терминал: поднимаем ответчик на localhost
openssl ocsp -index pki/inter/index.txt -CA pki/inter.pem \
    -rsigner pki/ocsp.pem -rkey pki/ocsp.key -port 8888

# второй терминал: спрашиваем про серверный сертификат
openssl ocsp -issuer pki/inter.pem -cert pki/server.pem \
    -url http://127.0.0.1:8888 -VAfile pki/ocsp.pem

Ответ начинается строкой Response verify OK и содержит статус: для отозванного серверного сертификата — pki/server.pem: revoked с временем отзыва, для клиентского, который не отзывали, — pki/client.pem: good.

Для клиентского сертификата, который не отзывали, тот же запрос вернёт pki/client.pem: good. Флаг -VAfile здесь важен: без него проверяющая сторона не знает, кому принадлежит ключ, подписавший ответ, и честно сообщает «unable to get local issuer certificate».

У OCSP есть два врождённых недостатка. Первый — приватность: спрашивая про конкретный сертификат, клиент сообщает УЦ, куда идёт. Второй — задержка: лишний сетевой запрос на каждое соединение. Поэтому придумали OCSP stapling: сервер сам периодически спрашивает статус и прикладывает свежий подписанный ответ к рукопожатию. Клиент не ходит к УЦ, приватность сохраняется, задержки нет.

CRL, OCSP и stapling
CRL — один список на всех; OCSP — запрос про один серийный номер; stapling — сервер приносит ответ сам
МеханизмКто запрашиваетРазмерСвежестьПриватность
CRLКлиентСотни КБ — мегабайтыЧасы — дниХорошая (но кэш общий)
OCSPКлиентСотни байтМинуты — часыПлохая: УЦ видит клиента
OCSP staplingСерверСотни байтМинуты — часыХорошая
Короткоживущие сертификаты——Секунды — суткиНе нужен отзыв

Почему отзыв не работает

Главная проблема отзыва — не техника, а поведение клиентов. Исторически браузеры при недоступности CRL или OCSP продолжали соединение: иначе сбой у УЦ положил бы весь интернет. Это называется soft-fail, и оно означает, что противник, способный заблокировать запрос к OCSP, отключает проверку отзыва целиком.

Второй удар — приватность OCSP: часть клиентов принципиально не ходит к УЦ. Третий — масштаб: списки растут, а полосы не бесконечны.

Ответы на это разные. Короткоживущие сертификаты (Let's Encrypt выдаёт на 90 дней, а индустрия движется к ещё меньшим срокам) сокращают окно, в котором отозванный сертификат опасен. Фильтры вроде CRLite 10 сжимают все CRL в компактную структуру и раздают её клиентам целиком — проверка становится локальной и приватной. Stapling переносит запрос на сервер. Единого решения нет, и это честно признаётся в литературе.

Браузеры давно не полагаются только на CRL и OCSP. Chrome рассылает CRLSets — сжатый список отозванных сертификатов, собранный Google; Firefox использует OneCRL для отзыва сертификатов УЦ. Расширение must-staple (TLS Feature, RFC 7633) позволяет владельцу домена потребовать, чтобы сервер всегда прикладывал OCSP-ответ: клиент тогда отвергает соединение без stapling и soft-fail становится невозможным. Это редкий случай, когда проблему решают не новым протоколом, а требованием к поведению.

Прозрачность и инциденты

Certificate Transparency

Идея Certificate Transparency (RFC 6962 3) проста: пусть каждый выпущенный сертификат попадает в публичный журнал, и пусть журнал нельзя незаметно переписать. Тогда поддельный сертификат на чужой домен рано или поздно будет замечен владельцем.

Журнал — это дерево Меркла (тема 8): листья — записи о сертификатах, корень хешируется и публикуется. Сертификат попадает в журнал, и УЦ получает подписанную квитанцию — SCT (англ. signed certificate timestamp). SCT можно доставить тремя способами: вписать в сам сертификат (расширение), приложить к рукопожатию в TLS-расширении или положить в OCSP-ответ. Первый способ самый надёжный, потому что SCT уже внутри подписанного сертификата, но требует поддержки со стороны УЦ. Второй — самый быстрый, но легко теряется. Третий — компромисс.

Браузер требует наличия SCT (в самом сертификате, в TLS-расширении или в OCSP-ответе), а владелец домена может подписаться на мониторинг и узнавать о новых сертификатах на своё имя.

Certificate Transparency: дерево Меркла
Записи о сертификатах — листья дерева Меркла; SCT подтверждает включение, а корень дерева нельзя изменить незаметно

Смысл дерева Меркла здесь тот же, что в теме 8: чтобы доказать включение записи, не нужно отдавать весь журнал — достаточно пути из log₂ N хешей. А чтобы доказать, что журнал не переписан, достаточно сравнить корень.

DigiNotar и Symantec

В 2011 году голландский УЦ DigiNotar был скомпрометирован, и атакующие выпустили поддельные сертификаты на десятки доменов, включая почтовые сервисы и google.com. Сертификаты использовались для перехвата трафика иранских пользователей. Расследование «Black Tulip» 8 показало, что компрометация началась за месяц до обнаружения, а журналы УЦ были неполными — восстановить полную картину не удалось. DigiNotar обанкротился, его корень удалили из всех хранилищ.

Ирония в том, что именно Certificate Transparency задумывалась как ответ на такие инциденты: поддельные сертификаты DigiNotar жили бы в журналах и были бы замечены мониторингом.

Второй крупный случай — Symantec. В 2015–2017 годах выяснилось, что сертификаты на чужие домены выпускались через партнёров без надлежащей проверки; масштаб — десятки тысяч сертификатов. Google объявил о постепенном недоверии к корню Symantec в Chrome, и в итоге бизнес перешёл к DigiCert. Показательно, что формальным поводом были не взломы, а нарушения процедур: выпуск без должной проверки домена, выдача сертификатов через партнёров без контроля, ошибки в журналах. Для PKI это важнее, чем кажется: доверие держится на процедурах, а не только на криптографии. Урок: репутация УЦ — это его единственный капитал, и потеря доверия необратима.

CAA и ACME

Два механизма упрощают жизнь владельцам доменов и УЦ.

CAA (RFC 8659 5) — DNS-запись, которая говорит, какие УЦ вправе выпускать сертификаты на домен. Если запись есть, УЦ обязан её проверить и отказать, если он в списке не указан. Это не защита от скомпрометированного УЦ (он может проигнорировать запись), но защита от случайного выпуска и от недобросовестных партнёров.

ACME (RFC 8555 4) — протокол автоматического выпуска: клиент доказывает контроль над доменом, получает сертификат и обновляет его без человека. Проверка контроля над доменом, на которой держится автоматический выпуск, тоже имеет слабое место. ACME предлагает три способа: положить файл на сервер (HTTP-01), добавить DNS-запись (DNS-01) или предъявить специальный сертификат в TLS-рукопожатии (TLS-ALPN-01). Все три проверяют, что заявитель управляет доменом сейчас, и ни один не проверяет, что он имеет на это право. Перехват BGP-анонса или подмена DNS на пути проверяющей стороны позволяет получить сертификат на чужой домен — такие случаи описаны и в научной литературе, и в отчётах УЦ.

На нём работает Let's Encrypt, который к 2021 году выдал более двух миллиардов сертификатов и сделал HTTPS нормой, а не роскошью 9. Автоматизация радикально сократила и сроки жизни сертификатов — а значит, и ущерб от отзыва.

Другие модели доверия

PGP и сеть доверия

В модели OpenPGP (RFC 4880 14) нет удостоверяющих центров. Есть ключи и подписи на ключах: если Алиса подписала ключ Боба, а вы доверяете Алисе, вы можете доверять и ключу Боба. Транзитивно доверие распространяется по «сети доверия» (англ. web of trust).

Плюс — отсутствие единой точки отказа и бюрократии. Минус — сложность для пользователя: нужно самому решать, кому доверять, и объяснять это неспециалисту невозможно. Именно поэтому PGP остался инструментом технических специалистов, а не массовым стандартом.

Отдельная история — серверы ключей. Долгое время они были открытыми и не проверяли, кто что загружает. В 2019 году выяснилось, что можно «отравить» чужой ключ, добавив к нему тысячи подписей: любой, кто попытается его импортировать, получит гигабайты мусора. Атака стоила нескольким проектам дней работы, а сервер ключей SKS пришлось закрыть. Урок общий для любой распределённой инфраструктуры: открытая запись без аутентификации — это не свобода, а вектор отказа в обслуживании.

TOFU и SSH

SSH использует третью модель — trust on first use (доверять при первом использовании). При первом подключении клиент запоминает отпечаток ключа сервера; при следующих — сравнивает. Если ключ изменился, SSH предупреждает о возможной атаке «человек посередине».

Это компромисс: удобно (не нужен УЦ) и достаточно (для большинства случаев), но беспомощно при первой встрече и при смене ключа сервера без предупреждения. Современное развитие — SSH-сертификаты, где инфраструктурный ключ подписывает ключи хостов и пользователей, а клиенту достаточно доверять одному ключу. Сертификат SSH — это не X.509, а собственный формат с полями «кого», «для чего», «до какого времени» и списком ограничений (разрешённые команды, адреса, перенаправления). По сути та же PKI, только с одним уровнем и без бюрократии: одна пара ключей заменяет сотни записей в authorized_keys.

Подпись кода и метки времени

Отдельная ветка — подпись артефактов: пакетов, обновлений, контейнеров. Здесь та же PKI, но с другими расширениями (codeSigning) и другими требованиями: подпись должна переживать срок действия сертификата, иначе выпущенный год назад установщик перестанет проверяться.

Решают это метками времени (RFC 3161 12): к подписи добавляется подписанная метка о моменте подписания, и проверяющая сторона оценивает срок действия сертификата на этот момент, а не на текущий. Получается странная конструкция: подпись действительна, даже если сертификат уже истёк, — но только если метка сделана, пока он был действителен.

Современное направление — Sigstore 13: подпись привязывается к краткоживущему сертификату, выпущенному по OIDC-идентичности, а факт подписи фиксируется в прозрачном журнале (Rekor). Ключей, которые нужно хранить годами, нет вообще. Модель молодая, но именно она всё чаще используется для подписи контейнеров и пакетов.

Технически Sigstore устроен так: подписывающий проходит OIDC-аутентификацию (например, через аккаунт в облачном CI), получает сертификат на 10 минут с идентичностью в subjectAltName, подписывает артефакт и отправляет запись в журнал Rekor. Проверяющий видит в журнале, кто и когда подписал, и проверяет подпись сертификатом, который уже давно истёк, — но метка времени в журнале доказывает, что в момент подписи он был действителен. Долговременных ключей нет вовсе, и это одновременно плюс (нечего красть) и минус (вся безопасность переносится на идентичность и на журнал).

Децентрализованные реестры доверия и криптовалюты: как криптография строит консенсус без УЦ

Модель PKI (X.509) и сеть доверия (Web of Trust) решают задачу аутентификации открытого ключа, связывая его с человеческим именем или доменом. Однако обе модели предполагают наличие субъектов доверия: в PKI — это иерархия удостоверяющих центров, в Web of Trust — сеть поручителей. В 2008 году Сатоши Накамото предложил протокол Bitcoin 15, в котором была решена более глубокая фундаментальная проблема распределённых систем: как достичь консенсуса о глобальном состоянии данных между взаимно недоверяющими сторонами без единого центрального авторитета (задача византийских генералов) и как исключить проблему двойного расходования цифрового ресурса (англ. double-spending).

Криптовалюты и блокчейн представляют собой композицию фундаментальных криптографических примитивов: односторонних хеш-функций (тема 8), деревьев Меркла (тема 8), схем асимметричной подписи на эллиптических кривых (тема 13) и протоколов доказательства с нулевым разглашением.

1. Хеш-цепочка и деревья Меркла

В основе блокчейна лежит криптографически верифицируемый связный список (англ. hash chain). Каждый блок содержит полезную нагрузку (список транзакций) и заголовок. Заголовок блока обязательно включает криптографический хеш заголовка предыдущего блока (H(\text{block}_{i-1})). Это свойство связывает всю цепочку в единую конструкцию: если злоумышленник попытается задним числом изменить хотя бы один бит в транзакции блока номер k, изменится хеш этого блока, что сделает недействительными заголовки всех последующих блоков k+1, k+2, \dots, N.

Криптографическая анатомия блокчейна: хеш-цепочка и дерево Меркла
Связывание блоков через хеш заголовка предыдущего блока H(PrevBlock) и компактное доказательство включения транзакции в дерево Меркла (SPV audit path)

Для компактного и быстрого подтверждения целостности транзакций внутри блока используется дерево Меркла (Merkle Tree) (тема 8):

  • Транзакции попарно хешируются снизу вверх, образуя бинарное дерево.
  • Итоговый корень дерева (англ. Merkle Root) фиксируется в 80-байтном заголовке блока.
  • Чтобы доказать легковесному клиенту (англ. Simplified Payment Verification, SPV), что конкретная транзакция действительно включена в блок, не требуется передавать мегабайты данных всего блока. Достаточно передать саму транзакцию и короткое доказательство пути Меркла (Merkle audit path) — список соседних хешей на пути от листа к корню (всего \lceil \log_2 N \rceil хешей). Клиент вычисляет корень и сверяет его с доверенным заголовком.

2. Цифровые подписи и адресация в блокчейнах

В криптовалютах открытый ключ заменяет собой личность и паспорт, а закрытый ключ — исключительное право распоряжения активом. «Кошелёк» — это не хранилище монет, а программа для безопасного хранения закрытых ключей и формирования цифровых подписей.

  • Выбор эллиптических кривых: в Bitcoin и раннем Ethereum используется кривая secp256k1 — Koblitz-кривая над простым полем вида y^2 = x^3 + 7 \pmod p (тема 13). В отличие от стандартных кривых NIST P-256, параметры secp256k1 получены детерминированно без использования закрытых «случайных затравок», что исключает подозрения в наличии скрытых математических закладок (бэкдоров). В более современных блокчейнах (Solana, Cardano) стандартом стала кривая Curve25519 со схемой Ed25519 (EdDSA).
  • Вывод адреса из ключа: адрес не равен открытому ключу напрямую. Открытый ключ сжимается (33 байта), затем дважды хешируется: сначала SHA-256, затем RIPEMD-160 (160 бит). К результату добавляется контрольная сумма из четырёх байт двойного SHA-256. В Bitcoin результат кодируется в Base58Check или в защищённый от опечаток формат Bech32 (BIP 173). Двойное хеширование защищает средства пользователя даже в том гипотетическом случае, если в будущем в алгоритме ECDSA обнаружится уязвимость: открытый ключ не раскрывается в блокчейне до того момента, пока владелец не решит впервые потратить монеты с этого адреса.
  • Подписи Шнорра (BIP 340, обновление Taproot 2021 г.) 16: исторически Bitcoin использовал ECDSA, поскольку в конце 2000-х алгоритм Шнорра был защищён патентом Клауса Шнорра. После истечения срока патента криптографы перешли на схему Шнорра:
    • Подпись Шнорра обладает строгим математическим доказательством стойкости в модели случайного оракула (в отличие от ECDSA).
    • Свойство линейности: подпись s = k + e \cdot x \pmod n позволяет производить агрегацию ключей и подписей (MuSig2). Несколько участников мультиподписного кошелька (например, 3 из 3) могут объединить свои открытые ключи в один агрегированный ключ, а свои подписи — в одну 64-байтную подпись. Для внешнего наблюдателя и валидаторов блокчейна сложный контракт выглядит как обычный перевод между двумя адресами, что снижает размер транзакции и радикально повышает конфиденциальность.
  • Агрегированные подписи BLS (Boneh — Lynn — Shacham) 17: схема подписи на билинейных отображениях (спариваниях на кривых BLS12-381). Используется в консенсусе Proof-of-Stake Ethereum 18: позволяет объединять тысячи подписей независимых валидаторов каждого 12-секундного слота в единую совокупную подпись размером всего 48 байт. Проверка такой подписи выполняется практически с константной вычислительной сложностью, что позволило масштабировать сеть до более чем 1 миллиона активных валидаторов.

3. Криптографический консенсус: Proof of Work и Proof of Stake

Как распределённая сеть решает, кто имеет право добавить следующий блок транзакций и избежать разветвления цепочки (форков)?

  • Proof of Work (PoW, доказательство выполнения работы): механизм восходит к идее Hashcash Адама Бэка (1997 г.) для борьбы со спамом. Майнер решает криптографическую задачу частичного обращения односторонней хеш-функции: найти такое 32-битное число nonce, чтобы двойной хеш SHA-256 заголовка блока оказался численно меньше целевого порога T: \text{SHA-256}(\text{SHA-256}(\text{header})) < T Так как SHA-256 ведёт себя как псевдослучайная функция (тема 8), единственный способ найти nonce — последовательный перебор сотен триллионов комбинаций в секунду на специализированных ASIC-чипах. При этом проверка найденного решения тривиальна: любой узел сети выполняет ровно две операции SHA-256 и мгновенно подтверждает валидность блока. Каждые 2016 блоков сеть автоматически пересчитывает целевой порог T в зависимости от суммарной мощности сети (хешрейта), удерживая интервал выпуска блока в среднем около 10 минут. Правило «самой длинной (наиболее тяжелой) цепочки» гарантирует, что переписать историю можно только при контроле более 50 % суммарной мощности майнинга (атака 51 %).
  • Proof of Stake (PoS, доказательство доли владения): устраняет необходимость в колоссальных затратах электроэнергии. Право создания и подтверждения блоков получают валидаторы, заблокировавшие финансовый залог (стейк). Для случайного выбора валидатора следующего слота применяются проверяемые случайные функции (Verifiable Random Functions, VRF): валидатор вычисляет псевдослучайное значение с помощью своего закрытого ключа и предъявляет криптографическое доказательство того, что именно его порядковый номер выиграл жребий в данном слоте, причём до момента публикации никто в сети не мог предсказать победителя или манипулировать результатом выборки (тема 3).

4. Модели учёта: UTXO против Account-based

  • Модель UTXO (Unspent Transaction Output, Bitcoin): в блокчейне нет концепции «баланса счёта». Есть неделимые криптографические векселя — неизрасходованные выходы транзакций. Транзакция потребляет один или несколько существующих UTXO (уничтожая их) и создаёт новые UTXO. Право потратить UTXO защищено небольшим стековым языком программирования Bitcoin Script:
    ScriptPubKey (условие блокировки): OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
    ScriptSig    (доказательство траты): <Signature> <PublicKey>
    
    Интерпретатор объединяет оба скрипта: проверяет хеш открытого ключа, а затем валидирует электронную подпись ECDSA или Schnorr. Модель UTXO исключает состояние гонки, строго параллелизуема и обеспечивает независимость проверок.
  • Модель состояний (Account-based, Ethereum): хранит состояние аналогично классической банковской системе — балансы аккаунтов и память смарт-контрактов. Все балансы и состояние виртуальной машины (EVM) организуются в модифицированное префиксное дерево Merkle Patricia Trie, корень которого (stateRoot) криптографически фиксируется в каждом блоке.

5. Криптография приватных криптовалют: кольца и нулевое разглашение

В традиционном блокчейне все транзакции, адреса и суммы общедоступны. Для защиты приватности разработаны специализированные криптографические протоколы:

  • Скрытые адреса (Stealth Addresses): отправитель и получатель используют однократный протокол Диффи — Хеллмана над эллиптической кривой. Отправитель генерирует случайный эфемерный ключ и переводит средства на уникальный одноразовый открытый ключ назначения, который виден в блокчейне, но связать его с реальным публичным адресом получателя может только сам получатель, обладающий закрытым ключом просмотра (англ. view key).
  • Кольцевые подписи (Ring Signatures / MLSAG в Monero): алгоритм подписи, позволяющий участнику подписать транзакцию от имени произвольно выбранной группы открытых ключей («кольца»), включающей его собственный ключ и несколько чужих ключей из блокчейна (ключи-приманки). Математика подписи доказывает, что транзакция подписана реальным владельцем одного из выходов кольца, но третьему лицу вычислительно невозможно определить, какого именно. Для предотвращения двойного расходования каждый выход имеет уникальный криптографический образ ключа (англ. key image), публикуемый при первой трате.
  • Обязательства Педерсена и Bulletproofs 19: скрывают суммы транзакций. Сумма заменяется криптографическим обязательством C = r \cdot G + v \cdot H, где v — сумма, r — ослепляющий секрет, а G, H — генераторы группы эллиптической кривой. Благодаря свойству гомоморфности сумма входов равна сумме выходов: \sum C_{in} - \sum C_{out} = 0. А для доказательства того, что скрытые суммы положительны и не вызывают переполнения диапазона (что позволило бы напечатать деньги из воздуха), отправитель формирует компактное логарифмическое доказательство диапазона Bulletproofs без доверенной настройки.
  • Доказательства с нулевым разглашением (Zero-Knowledge Proofs, ZK-SNARKs / STARKs в Zcash и zk-Rollups) 20: математический протокол, позволяющий доказать утверждение «транзакция валидна, все входы существуют в дереве Меркла и не были потрачены, а баланс сохранён» без раскрытия отправителя, получателя и сумм. Доказательство занимает всего несколько сотен байт и проверяется узлами за миллисекунды.

Итоги темы

Сертификат X.509 решает задачу, которую не решает математика: связывает открытый ключ с именем и делает эту связь проверяемой. Проверяемость обеспечивается подписью удостоверяющего центра, а доверие к УЦ приходит из хранилища корневых сертификатов — то есть извне, от операционной системы или браузера.

Сертификат состоит из полей (issuer, subject, validity, subjectPublicKeyInfo) и расширений. Для практики критичны три: basicConstraints определяет, является ли субъект УЦ; keyUsage и extendedKeyUsage ограничивают применение ключа; subjectAltName задаёт имена, которые сертификат покрывает, — и только он, поле CN больше не учитывается.

Проверка цепочки — построение пути от конечного сертификата до доверенного корня с проверкой подписей, сроков, прав УЦ и ограничений pathlen и nameConstraints. Присланные сервером промежуточные сертификаты не доверенные: они лишь помогают построить путь. Типичные ошибки диагностируются по кодам OpenSSL, и почти все они сводятся к «не прислали промежуточный», «истёк срок» или «не тот EKU».

Отзыв — самое слабое место PKI. CRL громоздки, OCSP создаёт задержку и раскрывает приватность, stapling переносит запрос на сервер, а soft-fail исторически отключал проверку при любой проблеме с сетью. Отсюда движение к короткоживущим сертификатам и локальным фильтрам вроде CRLite.

Certificate Transparency добавляет к PKI публичный аудит: поддельный сертификат становится видимым. Инциденты DigiNotar и Symantec показали, что компрометация УЦ — не теория, а CAA и ACME снижают риск случайных и массовых ошибок. Альтернативные модели — PGP, TOFU в SSH, Sigstore — показывают, что PKI с удостоверяющими центрами не единственный способ связать ключ с именем, но на сегодня он единственный, который масштабируется до всего интернета.

Следующая тема спускает всё это на уровень протокола: как сертификат используется в рукопожатии TLS 1.3, что именно подписывается, как устроены сессии и чем отличается аутентификация сервера от аутентификации пользователя.

Литература

  1. Cooper D., Santesson S., Farrell S., Boeyen S., Housley R., Polk W. Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile. — RFC 5280, IETF, 2008. https://www.rfc-editor.org/rfc/rfc5280
  2. Santesson S., Myers M., Ankney R., Malpani A., Galperin S., Adams C. X.509 Internet Public Key Infrastructure Online Certificate Status Protocol — OCSP. — RFC 6960, IETF, 2013. https://www.rfc-editor.org/rfc/rfc6960
  3. Laurie B., Langley A., Kasper E. Certificate Transparency. — RFC 6962, IETF, 2013. https://www.rfc-editor.org/rfc/rfc6962
  4. Barnes R., Hoffman-Andrews J., McCarney D., Kasten J. Automatic Certificate Management Environment (ACME). — RFC 8555, IETF, 2019. https://www.rfc-editor.org/rfc/rfc8555
  5. Hallam-Baker P., Stradling R., Hoffman-Andrews J. DNS Certification Authority Authorization (CAA) Resource Record. — RFC 8659, IETF, 2019. https://www.rfc-editor.org/rfc/rfc8659
  6. Федеральный закон от 06.04.2011 № 63-ФЗ «Об электронной подписи». — Собрание законодательства РФ, 2011, № 15, ст. 2036.
  7. Saint-Andre P., Hodges J. Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS). — RFC 9525, IETF, 2024. https://www.rfc-editor.org/rfc/rfc9525
  8. Black Tulip: Report of the Investigation into the DigiNotar Certificate Authority Breach. — Fox-IT, 2012. https://www.rijksoverheid.nl/documenten/rapporten/2012/08/13/black-tulip
  9. Aas J., Barnes R., Case B., Durumeric Z., Eckersley P., Flores-López A., Halderman J. A., Hoffman-Andrews J., Hounsel A., Kasten J., Rescorla E., Schoen S., Warren B. Let's Encrypt: An Automated Certificate Authority to Encrypt the Entire Web. — Proceedings of the 2019 ACM SIGSAC Conference on Computer and Communications Security (CCS), 2019, С. 2473–2487. DOI: 10.1145/3319535.3363192
  10. Larisch J., Choffnes D., Levin D., Maggs B. M., Mislove A., Wilson C. CRLite: A Scalable System for Pushing All TLS Revocations to All Browsers. — 2017 IEEE Symposium on Security and Privacy (SP), 2017, С. 539–556. DOI: 10.1109/SP.2017.17
  11. Durumeric Z., Ma Z., Springall D., Barnes R., Sullivan N., Bursztein E., Bailey M., Halderman J. A., Paxson V. The Security Impact of HTTPS Interception. — Network and Distributed System Security Symposium (NDSS), 2017. DOI: 10.14722/ndss.2017.23456
  12. Adams C., Cain P., Pinkas D., Zuccherato R. Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP). — RFC 3161, IETF, 2001. https://www.rfc-editor.org/rfc/rfc3161
  13. Newman Z., Meyers J., Torres-Arias S. Sigstore: Software Signing for Everybody. — Proceedings of the 2022 ACM SIGSAC Conference on Computer and Communications Security (CCS), 2022, С. 2353–2367. DOI: 10.1145/3548606.3560596
  14. Callas J., Donnerhacke L., Finney H., Shaw D., Thayer R. OpenPGP Message Format. — RFC 4880, IETF, 2007. https://www.rfc-editor.org/rfc/rfc4880
  15. Nakamoto S. Bitcoin: A Peer-to-Peer Electronic Cash System. — 2008. https://bitcoin.org/bitcoin.pdf
  16. Wuille P., Nick J., Ruffing T. Schnorr Signatures for secp256k1. — Bitcoin Improvement Proposal 340, 2020. https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
  17. Boneh D., Lynn B., Shacham H. Short Signatures from the Weil Pairing. — Journal of Cryptology, 2004, Т. 17, № 4, С. 297–319. DOI: 10.1007/s00145-004-0314-9
  18. Buterin V. Ethereum: A Next-Generation Smart Contract and Decentralized Application Platform. — Ethereum White Paper, 2014.
  19. Bünz B., Bootle J., Boneh D., Poelstra A., Wuille P., Maxwell G. Bulletproofs: Short Proofs for Confidential Transactions and More. — 2018 IEEE Symposium on Security and Privacy (SP), 2018, С. 315–334. DOI: 10.1109/SP.2018.00020
  20. Ben-Sasson E., Chiesa A., Tromer E., Virza M. Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture. — 23rd USENIX Security Symposium, 2014, С. 781–796.