Помимо перехода на «сверхкороткие» сертификаты, который быстро приближается, есть ещё несколько интересных новых моментов, связанных с TLS-сертификатами для веба. В феврале 2025 года Let’s Encrypt выпустили демонстрационный «шестидневный» сертификат от одного из своих основных промежуточных УЦ (E6). На примере этого сертификата можно увидеть челый ряд новшеств и неочевидных моментов, которые разобраны в статье. Для упрощения изложения, в качестве иллюстрации при разборе я использую не байты сертификата, а текстовую распечатку значений полей, полученную при помощи утилиты x509 из OpenSSL.
Итак, мы рассмотрим простую текстовую распечатку. Вообще, исходный TLS-сертификат состоит из блоков двоичных данных, объединённых структурой, которая задаётся спецификациями. Типы блоков, их длина — определяются внутренними идентификаторами. Собирательно, схема называется ASN.1, а исходный формат именно сертификатов — это X.509, который очень давно придумали для целей документальной электросвязи (для телеграфа).
Низкоуровневая интерпретация значений отдельных блоков сертификата выполняется в соответствии с их ASN.1-типами и расположением в заданной структуре, а высокоуровневая интерпретация — в соответствии с «ожиданиями» интерпретирующей программы и по так называемым OID («идентификаторы объектов»), которые входят в состав сертификата на правах обычных блоков.
Текстовая распечатка ниже — это нестрогое человекопонятное представление содержательных данных, которые утилита просмотра смогла извлечь из сертификата и успешно интерпретировать. Тем не менее, данный текстовый формат очень удобен для первоначального знакомства со структурами TLS-сертификатов.
Все комментарии — дальше по тексту, а тут, для справки, полная распечатка без комментариев и сам сертификат в Base64 (внутри PEM).
Скрытый текст
Certificate: Data: Version: 3 (0x2) Serial Number: 03:b0:b0:15:c1:a4:e2:64:16:11:73:1a:71:1b:71:1d:e0:ef Signature Algorithm: ecdsa-with-SHA384 Issuer: C = US, O = Let's Encrypt, CN = E6 Validity Not Before: Feb 19 17:30:01 2025 GMT Not After : Feb 26 09:30:00 2025 GMT Subject: Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:28:48:8b:6d:d9:5d:5a:a1:c2:39:77:1a:ca:47: c8:8b:7e:69:b4:2a:25:6f:3a:18:b0:28:1c:b3:bb: 69:0b:78:2e:c2:d0:17:5f:02:0b:70:74:80:9d:92: e1:21:01:7a:24:85:72:ea:e8:33:59:66:09:a1:e5: 3e:1f:95:5c:19 ASN1 OID: prime256v1 NIST CURVE: P-256 X509v3 extensions: X509v3 Key Usage: critical Digital Signature X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Authority Key Identifier: keyid:93:27:46:98:03:A9:51:68:8E:98:D6:C4:42:48:DB:23:BF:58:94:D2 Authority Information Access: OCSP - URI:http://e6.o.lencr.org CA Issuers - URI:http://e6.i.lencr.org/ X509v3 Subject Alternative Name: critical DNS:helloworld.letsencrypt.org X509v3 Certificate Policies: Policy: 2.23.140.1.2.1 CT Precertificate SCTs: Signed Certificate Timestamp: Version : v1 (0x0) Log ID : CC:FB:0F:6A:85:71:09:65:FE:95:9B:53:CE:E9:B2:7C: 22:E9:85:5C:0D:97:8D:B6:A9:7E:54:C0:FE:4C:0D:B0 Timestamp : Feb 19 18:28:32.078 2025 GMT Extensions: none Signature : ecdsa-with-SHA256 30:45:02:20:53:5D:E7:54:DF:48:D8:89:AC:EF:B6:F7: 8B:78:F4:2E:40:35:CE:28:0B:B8:13:53:37:FB:C6:79: 4D:96:12:AC:02:21:00:C2:2E:61:7E:20:BD:4A:C2:8B: C6:54:D0:D2:C7:2D:53:18:4B:99:D6:21:E3:4A:FA:10: 25:90:4B:FC:96:C3:60 Signed Certificate Timestamp: Version : v1 (0x0) Log ID : E0:92:B3:FC:0C:1D:C8:E7:68:36:1F:DE:61:B9:96:4D: 0A:52:78:19:8A:72:D6:72:C4:B0:4D:A5:6D:6F:54:04 Timestamp : Feb 19 18:28:32.147 2025 GMT Extensions: none Signature : ecdsa-with-SHA256 30:46:02:21:00:AC:D8:DB:99:21:42:25:A0:E6:87:D6: DF:5E:5C:32:9B:F1:B8:E8:58:44:81:3E:C2:B8:8B:60: 71:32:F1:08:B3:02:21:00:E3:0D:69:03:72:AF:56:24: CE:B7:0D:53:3D:79:A8:65:74:A1:52:E0:E4:12:4D:FA: 29:16:C5:73:9D:71:11:C5 Signature Algorithm: ecdsa-with-SHA384 30:65:02:30:30:0d:ab:2e:c6:d3:d0:08:c3:35:dc:77:b4:8d: 97:bb:85:c2:10:be:c6:57:dd:ba:fa:75:3d:e1:03:1d:cf:c5: 03:d2:b7:99:16:24:19:7b:8a:b7:33:5d:3a:1e:f0:70:02:31: 00:b8:c4:30:39:81:42:2c:17:6c:1e:38:ee:81:a4:69:90:1e: d2:ba:b1:03:71:2d:35:5e:70:8f:4a:1b:78:e6:e5:ba:3f:cd: 81:4b:15:10:6f:4e:aa:20:48:a2:08:05:47 -----BEGIN CERTIFICATE----- MIIDSzCCAtGgAwIBAgISA7CwFcGk4mQWEXMacRtxHeDvMAoGCCqGSM49BAMDMDIx CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQDEwJF NjAeFw0yNTAyMTkxNzMwMDFaFw0yNTAyMjYwOTMwMDBaMAAwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAAQoSItt2V1aocI5dxrKR8iLfmm0KiVvOhiwKByzu2kLeC7C 0BdfAgtwdICdkuEhAXokhXLq6DNZZgmh5T4flVwZo4IB9zCCAfMwDgYDVR0PAQH/ BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0j BBgwFoAUkydGmAOpUWiOmNbEQkjbI79YlNIwVQYIKwYBBQUHAQEESTBHMCEGCCsG AQUFBzABhhVodHRwOi8vZTYuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6 Ly9lNi5pLmxlbmNyLm9yZy8wKAYDVR0RAQH/BB4wHIIaaGVsbG93b3JsZC5sZXRz ZW5jcnlwdC5vcmcwEwYDVR0gBAwwCjAIBgZngQwBAgEwggEFBgorBgEEAdZ5AgQC BIH2BIHzAPEAdgDM+w9qhXEJZf6Vm1PO6bJ8IumFXA2XjbapflTA/kwNsAAAAZUf d/zOAAAEAwBHMEUCIFNd51TfSNiJrO+294t49C5ANc4oC7gTUzf7xnlNlhKsAiEA wi5hfiC9SsKLxlTQ0sctUxhLmdYh40r6ECWQS/yWw2AAdwDgkrP8DB3I52g2H95h uZZNClJ4GYpy1nLEsE2lbW9UBAAAAZUfd/0TAAAEAwBIMEYCIQCs2NuZIUIloOaH 1t9eXDKb8bjoWESBPsK4i2BxMvEIswIhAOMNaQNyr1YkzrcNUz15qGV0oVLg5BJN +ikWxXOdcRHFMAoGCCqGSM49BAMDA2gAMGUCMDANqy7G09AIwzXcd7SNl7uFwhC+ xlfduvp1PeEDHc/FA9K3mRYkGXuKtzNdOh7wcAIxALjEMDmBQiwXbB447oGkaZAe 0rqxA3EtNV5wj0obeObluj/NgUsVEG9OqiBIoggFRw== -----END CERTIFICATE-----
Итак, разбор.
Certificate: Data: Version: 3 (0x2) Serial Number: 03:b0:b0:15:c1:a4:e2:64:16:11:73:1a:71:1b:71:1d:e0:ef
Версию формата пропускаем — это просто 0x02. Смотрим на серийный номер. И уже здесь начинаются неочевидные моменты. Этот серийный номер начинается с 0x03. Это не простое совпадение. Почему? Потому что согласно спецификации серийный номер должен быть положительным целым числом. Хитрость в том, что в ASN.1 и в сертификатах для записи этого поля исторически используется представление со знаком, так что первый слева бит — это бит знака, и он должен иметь значение 0. При этом актуальные рекомендации требуют, чтобы серийные номера сертификатов имели достаточно большую разрядность и были «непредсказуемыми». Поэтому сейчас серийные номера генерируют (псевдо)случайным образом. И вот чтобы случайно или псевдослучайно не попасть в отрицательную область, левый полубайт (ниббл) принудительно делают равным нулю. Иначе, значение байта больше 0x80 приведет к тому, что запись серийного номера окажется отрицательным числом. Вообще никак не влияет на практическую обработку серийных номеров, но нарушает требования к формату. «Знаковые ошибки» в серийном номере уже приводили к массовому отзыву дефектных сертификатов. Впрочем, механизмы отзыва тоже уходят в прошлое.
Много энтропии в серийном номере ввели для того, чтобы затруднить атаки, основанные на предсказании состава ещё не выпущенного сертификата. Значения прочих полей нетрудно предсказать, и эффект когда-то давно был актуален для MD5, так как позволяет предвычислить коллизии хеш-функций.
Вообще, первый байт (слева) серийного номера правильно целиком использовать для каких-то внутренних целей, как это делают все грамотные и прозорливые УЦ — Let’s Encrypt и не только. Например, 0x03 может обозначать поколение ключей, версию ПО или ещё что-то такое.
Signature Algorithm: ecdsa-with-SHA384
«Историческое» поле в сертификате, повторяющее указание на тип подписи. (Подпись ставит УЦ, подпись указана в конце сертификата.)
Issuer: C = US, O = Let's Encrypt, CN = E6
Выпущен УЦ E6 от Let’s Encrypt, находящегося в юрисдикции США (US). Полное значение Issuer должно совпадать с Subject в вышестоящем сертификате, который содержит открытый ключ подписывающего УЦ.
Validity Not Before: Feb 19 17:30:01 2025 GMT Not After : Feb 26 09:30:00 2025 GMT
Те самые шесть дней валидности (плюс 16 часов «на погрешности»).
Subject:
Легко было незаметить и пропустить. Subject. Но он пустой. Это одно из новшеств. Браузеры уже довольно давно требуют наличия имени домена в поле SAN, а не в Subject, CN из которого для DV-сертификатов просто игнорируют (тут есть совсем уж технические детали, касающиеся сортировки сертификатов при валидации в Firefox, но мы их тут не рассматриваем). Теперь Subject вообще будет пустым, как в этом сертификате, а имя домена мы встретим ниже.
Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (256 bit) pub: 04:28:48:8b:6d:d9:5d:5a:a1:c2:39:77:1a:ca:47: c8:8b:7e:69:b4:2a:25:6f:3a:18:b0:28:1c:b3:bb: 69:0b:78:2e:c2:d0:17:5f:02:0b:70:74:80:9d:92: e1:21:01:7a:24:85:72:ea:e8:33:59:66:09:a1:e5: 3e:1f:95:5c:19 ASN1 OID: prime256v1 NIST CURVE: P-256
Это открытый ключ ECDSA на кривой P-256 — самый ходовой набор, самая популярная кривая, одобрено NIST и многими другими профильными организациями.
X509v3 extensions: X509v3 Key Usage: critical Digital Signature
Открытый ключ разрешается использовать только для цифровой подписи. Это то, что требуется в TLS. Прочие варианты, типа передачи ключа и зашифрования — больше не должны использоваться. Например, RSA-шифрование для передачи сеансового секрета в TLS — прямо запрещено спецификацией TLS 1.3.
X509v3 Extended Key Usage: TLS Web Server Authentication
Расширенные флаги для ключа: только использование для аутентификации сервера. В этом поле повсеместно можно встретить ещё и разрешение для аутентификации клиента. Например, те сертификаты, которые Let’s Encrypt выпускает сейчас, содержат здесь TLS Web Server Authentication, TLS Web Client Authentication.
X509v3 Basic Constraints: critical CA:FALSE
Это не ключ УЦ в сертификате (не должен подписывать другие сертификаты).
X509v3 Authority Key Identifier: keyid:93:27:46:98:03:A9:51:68:8E:98:D6:C4:42:48:DB:23:BF:58:94:D2
Идентификатор ключа — это просто подсказка, облегчающая поиск ключа УЦ, пропускаем.
Authority Information Access: OCSP - URI:http://e6.o.lencr.org CA Issuers - URI:http://e6.i.lencr.org/
А этот блок, в принципе, должен отражать важное новшество, но в демонстрационном сертификате новшества пока что не видно. Это адреса двух точек получения информации УЦ. Точка первая (OCSP) — URI респондера OCSP, то есть, респондера, позволяющего получить сведения о статусе сертификата (отозван или не отозван).
Что тут интересно? Во-первых, дни OCSP в Let’s Encrypt сочтены: УЦ отказывается от поддержки этого протокола, уже к августу 2025 года. Надо сказать, правильно делает, что отказывается: отзыв сертификатов и отслеживание их статуса вообще представляют одну из самых больших технических проблем для УЦ, а OCSP так вообще чрезвычайно неудобный, уязвимый, плохо масштабируемый сервис (но зато там простой протокол, да). Однако в этом сертификате OCSP указан. Почему? Потому что демонстрационный сертификат нужно было как-то отозвать, а статус отзыва — опубликовать штатным способом.
Во-вторых, современная версия рекомендаций CA/B-форума позволяет в «сверхкоротких» сертификатах вообще не указывать никаких сведений о способах проверки статуса сертификата. Раньше для всех TLS-сертификатов был один обязательный способ, — списки отзыва (CRL), — и один опциональный способ — OCSP-респондер. В современной версии рекомендаций введено понятие «сверхкоротких» сертификатов (со сроком валидности не более десяти дней) и для «сверхкоротких» можно не указывать никаких способов проверки того, отозван сертификат или нет.
Мотивация всё та же: отзыв всё равно в вебе фактически не работает, а сертификат со сроком действия в несколько дней быстро «протухает» автоматически. Выгода: экономия на сопровождении сервисов с информацией о статусе сертификатов — и это очень большая экономия для УЦ. Кроме того, если потребуется «отозвать» сразу миллионы сертификатов, то не нужно будет ничего делать — не придётся раздувать списки отзыва потоком серйиных номеров, а потоком записей о статусах — раздувать базы OSCP-сервисов. Если потребуется исключить миллионы доменов из перечня тех, кому разрешено выпускать сертификаты, то тоже достаточно будет перекрыть выпуск новых сертификатов — уже выпущенные быстро перестанут быть действительными, всё так же, без раздутия баз и списков. Удобно.
X509v3 Subject Alternative Name: critical DNS:helloworld.letsencrypt.org
Это DNS-имя, для которого валиден данный сертификат: helloworld.letsencrypt.org.
X509v3 Certificate Policies: Policy: 2.23.140.1.2.1
Политика, согласно которой сертификат был выпущен. Политики представляют собой своды правил, которым УЦ следовал при генерировании данного сертификата и при проверке права управления сетевым ресурсом, для которого сертификат валиден. Идентификаторы политик влияют на процесс валидации в браузерах. Например, именно политикой отличаются EV-сертификаты, а каких-то технических особенностей сертификата там нет. Но, всё же, это больше административный момент.
CT Precertificate SCTs:
Начинается блок меток SCT (подписанная метка времени — Signed Certificate Timestamp), которые выдают логи Certificate Transparency (далее — CT-логи). Метка содержит цифровую подпись (от ключа CT-лога) и привязана к составу сертификата. Наличие метки здесь означает, что соответствующий пресертификат был предъявлен оператору лога. Обратите внимание, что именно пресертификат — это отражено и в названии поля. То есть, пресертификат — это как бы такой же сертификат, но выпущенный раньше и имеющий в своём составе специальное расширение CT Poison, которое, будучи отмечено как критическое, должно препятствовать успешной валидации. Это «костыль» Certificate Transparency версии 1.0, позволяющий победить проблему курицы и яйца, получив SCT-метку для сертификата, выпуск которого требует наличия SCT-меток.
Signed Certificate Timestamp: Version : v1 (0x0) Log ID : CC:FB:0F:6A:85:71:09:65:FE:95:9B:53:CE:E9:B2:7C: 22:E9:85:5C:0D:97:8D:B6:A9:7E:54:C0:FE:4C:0D:B0 Timestamp : Feb 19 18:28:32.078 2025 GMT
Первая SCT-метка получена 19 февраля в 18:28:32, с «копейками» миллисекунд. Это таймстемп, формируемый CT-логом, который должен обозначать время, когда лог получил пресертификат. Log ID — это отпечаток файла открытого ключа лога. Это SCT от лога Cloudflare «Nimbus2025».
Однако обратите внимание на значение таймстемпа: 18:28:32, но сам сертификат начинает действовать в 17:30:01 (см. интервал валидности выше), почти на час раньше. Как так? Интервал валидности должен совпадать в пресертификате и в сертификате, иначе не сойдётся подпись в SCT-метке. Получается, пресертификат был выпущен за час до того, как УЦ предъявил его логу? Нет, конечно же. Это рядовой «бэкдейтинг», но скромный — время выпуска сертификата поставлено на час (примерно) раньше фактического, чтобы, как заявлено, компенсировать проблемы с неточными часами. Действительно, сертификаты Let’s Encrypt выпускаются автоматом и сразу должны публиковаться на веб-сервере. Соответственно, если клиентские часы отстают, то свежий сертификат может оказаться по локальным часам «в будущем» (какая-то теория относительности, не находите?), то есть, ещё не действует. 60 минут выбраны потому, что в этот интервал, как считается, укладывается подавляющее большинство практических отклонений часов. Вот поэтому Let’s Encrypt пишет в сертификаты время на час раньше.
Extensions: none Signature : ecdsa-with-SHA256 30:45:02:20:53:5D:E7:54:DF:48:D8:89:AC:EF:B6:F7: 8B:78:F4:2E:40:35:CE:28:0B:B8:13:53:37:FB:C6:79: 4D:96:12:AC:02:21:00:C2:2E:61:7E:20:BD:4A:C2:8B: C6:54:D0:D2:C7:2D:53:18:4B:99:D6:21:E3:4A:FA:10: 25:90:4B:FC:96:C3:60
Подпись из состава SCT-метки (ECDSA на кривой P-256).
Signed Certificate Timestamp: Version : v1 (0x0) Log ID : E0:92:B3:FC:0C:1D:C8:E7:68:36:1F:DE:61:B9:96:4D: 0A:52:78:19:8A:72:D6:72:C4:B0:4D:A5:6D:6F:54:04 Timestamp : Feb 19 18:28:32.147 2025 GMT Extensions: none Signature : ecdsa-with-SHA256 30:46:02:21:00:AC:D8:DB:99:21:42:25:A0:E6:87:D6: DF:5E:5C:32:9B:F1:B8:E8:58:44:81:3E:C2:B8:8B:60: 71:32:F1:08:B3:02:21:00:E3:0D:69:03:72:AF:56:24: CE:B7:0D:53:3D:79:A8:65:74:A1:52:E0:E4:12:4D:FA: 29:16:C5:73:9D:71:11:C5
Вторая SCT-метка. CT-лог Sectigo «Sabre2025h1». CT-логи ведут сами УЦ. Это может показаться странным, но как-то так сложилось.
Signature Algorithm: ecdsa-with-SHA384 30:65:02:30:30:0d:ab:2e:c6:d3:d0:08:c3:35:dc:77:b4:8d: 97:bb:85:c2:10:be:c6:57:dd:ba:fa:75:3d:e1:03:1d:cf:c5: 03:d2:b7:99:16:24:19:7b:8a:b7:33:5d:3a:1e:f0:70:02:31: 00:b8:c4:30:39:81:42:2c:17:6c:1e:38:ee:81:a4:69:90:1e: d2:ba:b1:03:71:2d:35:5e:70:8f:4a:1b:78:e6:e5:ba:3f:cd: 81:4b:15:10:6f:4e:aa:20:48:a2:08:05:47
Завершается текстовый дамп сертификата значением подписи. Это просто ECDSA на кривой P-384, которую использует Let’s Encrypt для УЦ E6. Подпись вычисляется для всего состава сертификата, который приведён выше. Корректное значение подписи — это то, что и делает сертификат полезным.
ссылка на оригинал статьи https://habr.com/ru/articles/901312/
Добавить комментарий