Что произошло

17 октября исследователь безопасности сообщил в Apple, Google, Microsoft, Mozilla и eMudhra об утечке приватных ключей восьми промежуточных сертификатов eMudhra. Chrome опубликовал обновление CRLSet, блокирующее их в тот же вечер, а Mozilla заблокировала их в Firefox через OneCRL несколькими часами позже. 20 октября Mozilla публично объявила об инциденте и выпустила обновление NSS, удаляющее корневой сертификат eMudhra, а Chrome подтвердил, что корень попадет в Chrome Root Store v43.

Восемь промежуточных сертификатов — это шесть центров выдачи TLS-сертификатов (DV, OV и EV, двух поколений каждый) и два центра подписи кода, все созданы в апреле 2025 года. Каждый из них был также кросс-подписан корневым сертификатом Sectigo AAA Certificate Services в мае 2025 года.

Это объясняет «что», но самое интересное — это «как», и Иэн Кэрролл коротко резюмировал суть на форуме:

Это изначально слабые одно-байтовые ключи, которые любой может разложить на множители, и проблему невозможно локализовать.

Что на самом деле представляет собой приватный ключ

Это ключи эллиптической кривой на кривой P-384. Приватный ключ — это просто число d. Открытый ключ, который видит весь мир в сертификате, — это d × G, где G — фиксированная точка на кривой, которую используют все, а «×» означает добавление G к себе d раз с использованием специальной арифметики кривой.

Идти в одну сторону легко, но в обратную — от открытого ключа к d — считается практически невозможным. На этом зиждется вся модель безопасности, и она работает только если d — огромное число. Приватный ключ P-384 должен быть случайным 384-битным числом, что дает 2³⁸⁴ возможностей (примерно 10¹¹⁵), поэтому никто никогда не будет его перебирать.

Ключи eMudhra выглядели так:

d = 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004

Приватный ключ P-384 должен выглядеть так:

d = 0x48ac06790886c80c48d31691fd4c0fe9ce3207f9807f2fe571d6e4ec426d78644298fc53df2b92566970e757ac998c34

47 байт нулей и потом один байт — и все восемь ключей такие. У одного байта есть 256 возможных значений, поэтому «поиск» — это вычисление 1 × G, 2 × G, 3 × G и остановка, когда совпадет с сертификатом, максимум 255 шагов.

Итак, вся система, каждый сертификат, который могли выдать эти центры, каждый клиент, который им доверял, зависела от восьми бит.

Я проверил

Mozilla приложила затронутые сертификаты к своему объявлению, поэтому были извлечены все 16 (8 ключей, каждый использован в двух выданных сертификатах: один от eMudhra и один от Sectigo) и переборены. Каждый упал мгновенно, все шесть TLS значений и оба ключа подписи кода столь же слабы:

Промежуточный сертификат Тип d
EM DV TLS CA - G3B TLS 156
EM DV TLS CA - G3C TLS 230
EM EV TLS CA - G3B TLS 115
EM EV TLS CA - G3C TLS 56
EM OV TLS CA - G3B TLS 155
EM OV TLS CA - G3C TLS 4
EM OV CS CA - G3B Подпись кода 66
EM OV CS CA - G3C Подпись кода 237

Интересно, что ничто в этих сертификатах не выглядит неправильно. Открытый ключ, производный от d = 4, — это идеально корректная точка на кривой, кодирование в порядке, кривая в порядке, все структурные проверки проходят. Единственный способ узнать — попробовать.

Почему «это невозможно локализовать»

Обычно когда ключ центра сертификации скомпрометирован, кто-то его украл! Есть вор, есть момент, когда это случилось, и можно хоть как-то рассуждать о том, кто теперь имеет доступ к этому ключу.

Здесь никто ничего не должен был красть. Ключ был фактически открыт с самого дня существования сертификата. Кто угодно, кто посмотрел на один из этих сертификатов в любой момент с апреля 2025 года, мог восстановить ключ за миллисекунды на обычном оборудовании. Это окно в 17 месяцев, и нет способа узнать, сделал ли это кто-то.

Chrome отметил, что поскольку Chrome требует Certificate Transparency, и никакие TLS-сертификаты, цепляющиеся к этим центрам, никогда не попадали в CT, никакой поддельный сертификат не мог бы быть доверен по умолчанию в Chrome. Это правда и обнадеживает для браузеров. CT обнаруживает неправильную выдачу, но не предотвращает ее, а много программного обеспечения вообще не проверяет CT.

Кто подвергается риску сегодня

Основные браузеры и обновленные системы вероятно совершенно в порядке. Chrome и Firefox блокируют промежуточные сертификаты напрямую и оба требуют CT, и Safari тоже требует CT.

Все остальное — это совсем другая история. Большинство клиентов TLS, не являющихся браузерами (то есть практически все остальное, с настройками по умолчанию) — такие как curl, Python, Node, Go, Java, git, менеджеры пакетов и каждый скрипт и демон, который у вас есть, — делают три важных вещи: они доверяют пакету корневых сертификатов на диске, они не проверяют отзыв по умолчанию и они не проверяют CT. Поэтому тот факт, что eMudhra и Sectigo отозвали эти промежуточные сертификаты, им вообще не помогает. Это то, что я часто нахожу при обсуждении TLS и PKI — понимание того, насколько массивна экосистема клиентов, часто упускается. Мы часто сосредотачиваемся на этом в обучении, когда смотрим на современные решения для отзыва, как CRLite, которые творят чудеса на настольных браузерах, но ничего не дают никакому другому TLS-клиенту. Рассмотрите, что теперь нуждается в обновлении хранилища корневых сертификатов, и это только верхушка айсберга:

  • curl | sh установщики и автообновители. Многие инструменты устанавливаются или обновляются путем загрузки скрипта или бинарника через HTTPS без проверки подписи (rustup, nvm, Homebrew installer, бесчисленные страницы «install.sh», обновления прошивки IoT). Поддельный сертификат здесь означает запуск кода атакующего, часто от root.
  • Конвейеры CI/CD. GitHub/GitLab runners, Jenkins и контейнеры сборки получают зависимости и отправляют артефакты, удерживая облачные ключи, токены реестра и ключи подписи. Они работают на устаревших базовых образах в общих сетях, и под капотом у них curl, Python, Go и Node.
  • API вызовы сервер-сервер. Поставщики платежей, вебхуки, обмены токенов OAuth и облачные SDK (AWS CLI и boto используют собственный пакет certifi; Terraform и kubectl используют Go). Они несут в заголовках секреты API и данные клиентов.
  • IoT, встроенные и OT устройства. Камеры, маршрутизаторы, автомобили, медицинские устройства, умные приборы, платежные терминалы и промышленные контроллеры звонят домой для команд и обновлений. Их пакеты заморожены до 2039 года, что делает реальным момент «невозможно локализовать».
  • Подпись кода Windows. Это не TLS, но это тот же недостаток: Windows доверяет корню eMudhra CS напрямую. Вредоносное ПО, подписанное EM OV CS CA - G3B/G3C, выглядит как подписанное программное обеспечение реального издателя для всего, что не проверяет отзыв.

Это было протестировано на собственных машинах, используя локальный сервер и сертификат для api.stripe.com, имя, которое мы все вероятно согласимся имеет очень высокую ценность. С настройками по умолчанию curl сказал SSL certificate verify ok, Python завершил handshake, и Node сказал authorized: true. Это было истинно на каждой тестируемой машине Linux и macOS. На Windows CryptoAPI принял цепь, если не была включена проверка отзыва, и даже тогда только один из двух путей вернулся как отозванный.

scott@Middle-Earth:~$ curl -v --resolve api.stripe.com:18888:127.0.0.1 https://api.stripe.com:18888/
* Added api.stripe.com:18888:127.0.0.1 to DNS cache
* Hostname api.stripe.com was found in DNS cache
*   Trying 127.0.0.1:18888...
...snip...
* Server certificate:
*  subject: CN=api.stripe.com
*  start date: Oct 20 18:39:57 2026 GMT
*  expire date: Oct 21 18:44:57 2026 GMT
*  subjectAltName: host "api.stripe.com" matched cert's "api.stripe.com"
*  issuer: C=NL; O=eMudhra BV; CN=EM DV TLS CA - G3B
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: api.stripe.com:18888
> User-Agent: curl/7.68.0
> Accept: */*
>
...snip...
< HTTP/1.0 200 ok
< Content-type: text/html
<
<HTML><BODY BGCOLOR="#ffffff">
<pre>
s_server -accept 127.0.0.1:18888 -cert /tmp/tmp.rBcIpjTbZV/leaf.pem -key /tmp/tmp.rBcIpjTbZV/leaf.key -cert_chain /home/scott/code/test/intermediate-sectigo.pem -www -quiet
...snip...
</pre></BODY></HTML>
...snip...
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
scott@Middle-Earth:~$

Можно поместить в этот сертификат любое другое имя хоста, и все, что нужно для перехвата трафика этого устройства, — это оказаться на пути сети.

Что делать сейчас

К счастью, требуемые шаги здесь не особенно сложны для устройств, которые можно обновить, и совет практически сводится к «обновите их». Проблема в устройствах, которые нельзя обновить или сложно обновить.

  1. Обновите все, что поставляется с пакетом корневых сертификатов: пакет ca-certificates вашей ОС, certifi, Node, Homebrew, и пересоберите образы контейнеров, когда базовые образы поймут изменение.
  2. Устройства, которые нельзя обновить, — сложная часть. Маршрутизаторы, принтеры, телевизоры, приборы с замороженной прошивкой будут доверять этим сертификатам до истечения срока, что составляет июль 2039 года...

Заключение

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

Источники

Тема MDSP: https://groups.google.com/a/mozilla.org/g/dev-security-policy/c/0R3XLJL6FuE/m/Kp1v6CPuAAAJ

Объявление исследования: https://emudhra.we-have-a-problem.com/

Обновление от 20 октября 2026, 20:16 UTC
Вскоре после публикации Mozilla сделала свой тикет инцидента открытым: https://bugzilla.mozilla.org/show_bug.cgi?id=2083449

eMudhra дала свой рассказ о произошедшем в этом тикете. Похоже, была ошибка в скрипте, используемом во время процесса, на HSM была создана вторая, слабая пара ключей, и из-за похожих названий человеческая ошибка привела к использованию неправильных ключей для CSR. Ничто в тексте выше не изменилось в результате этой новой информации. Также подтверждается, что простой запрос в AI агент позволил восстановить приватные ключи центра сертификации. Claude смог восстановить приватные ключи с одним запросом.