Contents of this directory is archived and no longer updated.

Примечание: данный материал публикуется как обязательный для знания IT-специалистами, которые занимаются или только собираются заниматься темой PKI (Public Key Infrastructure).

Введение

На самом деле эта тема тесно переплетается с фундаментальными основами PKI, как доверие сертификатов, защита от подделки цифровых подписей сертификатов, отзыв сертификатов и т.д. Иными словами, сама модель PKI лежит на Certificate Chaining Engine (механизм построения цепочек сертификатов). Миллионы людей в мире видят результат работы этого механизма ежедневно, но не знают, как он работает. Им это, в принципе, и не надо, а вот IT-специалистам по PKI это знать просто необходимо.

Одной из основ PKI является модель доверия центрам сертификации (Certification Authority или просто CA). Прежде чем мы начнём доверять сертификату мы должны явно доверять корневому сертификату CA и так же явно или косвенно (по правилу одностороннего транзитивного доверия) доверять всем промежуточным CA в цепочке. Корневые сертификаты устанавливаются в систему вручную путём добавляения сертификата CA в секцию Trusted Root CAs. Если корневой сертификат CA есть в этом списке, то мы доверяем всем сертификатам, которые выдал этот CA и любые подчинённые CA (Intermediate CA).

В качестве наиболее доступного и понятного примера можно рассмотреть SSL веб-сайт. Если мы зайдём на https://www.dreamspark.com, то мы увидим что с SSL сертификатом этого сайта всё в порядке. Если же мы зайдём на https://cert.startcom.org, то мы наоборот увидим грозное предупреждение, что с SSL сертификатом этого сайта что-то не так. Это как раз и есть результат работы Chaining Engine. А вот что он сделал на самом деле — вот об этом мы сейчас и поговорим.

Постройка цепочки сертификатов

Давайте сначала посмотрим на путь сертификатов (цепочки сертификатов) обоих веб-сайтов:

 Valid certification path   Invalid certification path with untrusted root

В первом случае цепочка сертификатов заканчивается на сертификате VeriSign, которому мы доверяем явно. Вы можете убедиться в этом нажав кнопку View Certificate, чтобы посмотреть его внутренности и найти этот же сертификат в оснастке certmgr.msc –> Trusted Root CAs. Однако, вы видите, что не корневой CA выдал сертификат сайту, а подчинённый (Intermediate CA). Это доказывает то, что если мы доверяем корню, то и явно или косвенно доверяем всем сертификатам этого CA или любым его прямым или косвенным промежуточным CA. Если говорить простым языком, то в сертификатах используется одностороннее транзитивное доверие сертификатам CA. Чуть позже будет рассказано как строится эта цепочка. Во втором случае мы видим, что корневой сертификат CA не находится у нас в Trusted Root CAs и, следовательно, мы не доверяем ни одному сертификату, который издал этот CA или любой другой его подчинённый CA. И, так же как и в первом случае, сертификат самому веб-сайту выдал подчинённый CA. На самом деле этот момент является одной из наиболее частых ошибок системных администраторов, которые организовывают доступ к ресурсам с использованием цифровых сертификатов.

Но нас теперь интересует другой вопрос — а откуда же взялись все эти сертификаты в цепочке? Chaining engine как правило использует только 3 метода построения цепочки:

  • по полю AIA (Authority Information Access) каждого сертификата
  • с использованием файла цепочки сертификатов в формате pkcs7
  • поиск подходящих сертификатов в локальном хранилище (с использованием exact, key, name matches, о которых будет рассказно ниже)

Примечание: в сертификате любое поле содержащее слово Authority будет означать какие-то сведения о сертификате вышестоящего CA. Например, Authority Key Identifier — комбинация серийного номера, поля Subject или хеша открытого ключа вышестоящего CA. А любое поле содержащее слово Subject — означает то же самое, но применительно к конкретно этому сертификату.

Давайте посмотрим поле AIA первого сертификата:

[1]Authority Info Access
     Access Method=Certification Authority Issuer (1.3.6.1.5.5.7.48.2)
     Alternative Name:
          URL=
http://www.microsoft.com/pki/mscorp/Microsoft%20Secure%20Server%20Authority(5).crt

В этом поле содержится ссылка на сертификат того CA, который непосредственно издал и подписал этот сертификат. Если нажать по этой ссылке, то вы скачаете сертификат центра сертификации Microsoft Secure Server Authority. В этом сертификате тоже будет поле AIA, по ссылке из которого скачается сертификат вышестоящего CA — Microsoft Internet Authority. И так проверка проводится далее до тех пор, пока цепочка не оборвётся или не закончится каким-либо корневым CA (корневой CA характеризуется самоподписанным сертификатом, т.е. сертификат выдан самому себе). Если вы посмотрите сертификат Microsoft Internet Authority, то вы в нём не обнаружите поля AIA. И вот здесь мы сталкиваемся со вторым методом добычи сертификатов в цепочке – файл сертификатов формата pkcs7.

Бывают случаи, когда цепочка сертификатов не может быть построена и она обрывается на пути. Типичный пример такого обрыва (когда цепочка не может быть построена до корня с использованием любого вышеуказанного метода) можно посмотреть на сайте БиЛайна: https://trust.beeline.ru

 Invalid certificate chain. Root certificate s unreachable

если посмотреть поле AIA этого сертификата, то мы увидим там 2 пути до CA, который издал этот сертификат. Но оба эти пути нерабочие совсем (кстати говоря, пути в CDP там тоже нерабочие. Причём, во всех сертификатах! Вот такой он БиЛайн :-) ). Но цепочка сертификатов в этом случае всё равно построилась за счёт сертификатов в pkcs7 формате. Хотя корневой сертификат в этом pkcs7 просто отсутствует, поэтому мы даже не можем собрать корневой сертификат. Неработающие CDP/AIA — ещё одна из наиболее частых ошибок реализации инфраструктуры PKI, в результате которой по сути PKI является неработоспособной.

Оффтоп: если на этой странице нажать Продолжить, то на новой странице будет ссылка на корневой сертификат, а так же на CRL. CRL БиЛайна доставил очень сильно. Вы посмотрите срок годности этого CRL :-)

Проверка соответствия сертификатов внутри построенной цепочки

Однако, это только половина дела. Мы просто построили цепочку сертификатов, но не более того. Поскольку сертификаты могут быть скачаны в pkcs7 формате, а по ссылкам AIA просто подменить сертификаты, chaining engine делает полнуюю проверку доверия каждого сертификата в цепочке, чтобы исключить возможность подмены сертификатов, а так же достраивает цепочку (если этого не удалось сделать с помощью AIA и pkcs7 используя локальное хранилище сертификатов). Соответствие сертификатов внутри цепочки может происходить по нескольким правилам (в порядке приоритета):

  • Exact Match
  • Key Match
  • Name MAtch

Для этого chaining engine использует следующие поля сертификатов:

  • Authority Key Identfier (AKI) — может содержать комбинацию поля Subject и Serial Number сертификата вышестоящего CA или хеш открытого ключа вышестоящего CA (но бывает, что это поле совсем отсутствует).
  • Issuer – данное поле используется только если AKI отсутствует в сертификате и это поле должно быть эквивалентно полю Subject вышестоящего CA. По этому полю определяется имя CA, котороый издал этот сертификат.
  • Subject в сертификате вышестоящего CA. Данное поле должно быть эквивалентно полю Issuer в издаваемых сертификатах.
  • Serial Number сертификата вышестоящего CA.
  • Subject Key Identifier (SKI) — может содержать комбинацию поля Subject и Serial Number текущего сертификата или хеш открытого ключа текущего сертификата.

Exact match

Данный метод определения правильности построения цепочки является наиболее точным и такая цепочка почти никогда не будет заканчиваться более чем одним корневым сертификатом, поскольку требует совпадения 2-х полей вышестоящего сертификата – Subject и серийного номера с полем AKI проверяемого сертификата. Давайте посмотрим пример такой проверки в сертификате сайта https://cert.startcom.org. Поле AKI содержит следующую информацию:

KeyID=a1 e1 9e 45 25 79 4d 06 d9 02 17 92 82 d5 30 89 72 25 14 a0
Certificate Issuer:
     Directory Address:
          CN=StartCom Certification Authority
          OU=Secure Digital Certificate Signing
          O=StartCom Ltd.
          C=IL
Certificate SerialNumber=17

Поле KeyID не используется. Здесь мы видим сведения о поле Subject и серийный номер вышестоящего CA. Если посмотреть сертификат этого CA, то его серийный номер и поле Subject будут идентичными тем, которые записаны в поле AKI издаваемых ими сертификатов. Используя эти данные chaining engine может найти нужный сертификат в локальном хранилище (если такой сертификат там есть), для восполнения недостающих звеньев цепочки. Если же будет обнаружено хоть одно несоответствие между этими полями, то цепочка мгновенно обрывается и любому сертификату в этой цепочке (начиная от сертификата с несоответствующими полями и вниз до конечного сертификата выданного потребителю) будет отказано в доверии.

Key Match

Это наиболее распространённый тип проверки цепочки, т.к. зачастую поле AKI у сертификатов содержит только KeyID, который является лишь хешом открытого ключа вышестоящего CA. Например сертификат с https://www.dreamspark.com:

KeyID=14 55 c4 39 e0 3d 2e d1 55 2e 48 96 b0 d8 7e 14 22 06 93 bc

Этот хеш должен быть идентичным хешу, который записан в поле Subject Key Identifier вышестоящего CA. В этом вы можете убедиться просмотрев сертификат CA, который выдал сертификат для dreamspark.com. В случае несоответствия этого поля, любому сертификату вниз по цепочке будет отказано.

Заметка: при этом, возможна достаточно интересная ситуация, когда цепочка может заканчиваться несколькими корнями. Это может происходить если корневой сертификат CA был обновлён с использованием текущей пары открытого и закрытого ключа. Поскольку KeyID — всего лишь хеш открытого ключа, то при смене корневого сертификата CA, хеш не изменится и, следовательно, chaining engine может рандомно строить цепочку до старого или до нового корневого сертификата CA.

Name match

Но поле AKI не обязательно должно присутствовать в сертификате. Его может не быть совсем и тогда остаётся только один способ проверки целостности цепочки — сравнение поля Issuer текущего сертификата и поля Subject вышестоящего сертификата. Это самый крайний и наименее надёжный (хотя это достаточно относительно) метод проверки цепочки. Так же, как и предыдущий пример, данный метод может заканчиваться несколькими корневыми сертификатами, если сертификат CA был обновлён с использованием текущей пары открытого и закрытого ключей. Но этого не произойдёт, если при обновлении сертификата CA будут использоваться новая пара ключей. Хоть хеши и серийные номера издающих CA не проверяются, то подделка сертификатов в вашем случае закончится провалом. А об этом читайте заключительный раздел.

Не забываем про подписи

На самом деле может показаться, что обмануть chaining engine достаточно легко — надо лишь подсунуть нужные поддельные сертификаты. Но в действительности это не так. Помимо всего прочего следует помнить, что каждый сертификат подписан цифровой подписью издающего CA. Если вы ещё не знаете, что такое цифровая подпись, то пора бы и узнать. Когда CA составляет сертификат, то он высчитывает конечный хеш (с использованием алгоритма указанного в поле Signature algorithm) этого сертификата и шифрует его своим закрытым ключом и пристыковывает подпись к сертификату. При проверке сертификата chaining engine удаляет цифровую подпись из сертификата и подсчитывает сам хеш файла сертификата. Далее берёт открытый ключ у издающего CA и сравнивает полученный хеш с тем, что содержится в подписи. Следовательно, если вам удастся обмануть все 3 метода проверки цепочки путём подмены сертификатов, то вы сломаетесь на проверке цифровой подписи, т.к. здесь уже задействуется закрытый ключ легального CA. Вот как это может выглядеть:

Altered certificate certification path Altered certificate General tab

На картинке слева вы видите, что chaining engine построил цепочку до доверенного корня, поскольку мой сертификат содержал нужные поля для работы метода Name match. Но сертификат был выдан не тем CA, который виден в цепочке, а поддельным CA. Хоть мой поддельный CA внешне не отличим от легитимного CA, но у него нету самого важного — правильного закрытого ключа, чтобы подписать сертификат. Ведь при проверке подписи используется открытый ключ легитимного CA и, следовательно, подпись не может быть проверена.

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


Share this article:

Comments:

shs

>Здесь мы видим сведения о поле Subject и серийный номер вышестоящего CA Наверное имелось в виду:"... и серийный номер сертификатка вышестоящего CA" ?

Vadims Podāns

ну да, мы же говорим только о сертификатах ;)

shs

ну да, мы же говорим только о сертификатах ;) Ну не знаю, у меня на этой фразе случился затык. ;) Полез смотреть сертификат и никак не мог понять - где в нем серийный номер CA? Потом только понял, что речь идет о серийном номере сертификата CA. Это все-таки вещи разные. IMHO стоит исправить. В этой же статье, по крайней мере еще один раз встречается подобное "сокращение".

shs

Опять таки, если понять буквально "серийный номер CA", то смысл написаного теряется, т.к. получается, что сабжект и некий "серийный номер CA" фактически дублируют друг друга (если предположить, что "серийный номер CA" однозначно идентифицирует CA).

Ilya Rud

Спасибо огромное. После двух прочтений в голове все легло отлично.

e.nur.kz

Возможно, кто ни-будь знает как получить AKI с применением классов .NET, или используемые разделители в X509

Vadims Podāns

($cert.Extensions | ?{$_.oid.friendlyname -eq "authority key identifier"}).format(0)

Vladimir

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

Vadims Podāns

На стадии построения цепочки, сертификаты просто подставляются (биндятся) в нужное место цепочки. При этом, CCE использует хранилище сертификатов, расширения сертификатов и т.д. чтобы выбрать наиболее подходящий сертификат. В этот момент никакие проверки не проверяются, только происходит поиск и биндинг сертификатов в пределах цепочки, чтобы было что потом проверять. А вот когда цепочка построена, она уже тщательно проверяется. Т.е. сверяются подписи, политики сертификатов и прочие ограничения. Самое бытовое: сертификат CA ограничен выдачей сертификатов только для Server Authentication и Client Authentication EKU, а конечный сертификат выдан для Code Signing. Конечный сертификат выпадает из цепочки, потому что не прошёл проверку application policies constraints. Например, если в 3-х уровневой цепочке (2 сертификата CA и один конечный сертификат) на самом верхнем уровне сертификат имеет Basic Constraints: PathLength = 0, конечный сертификат выпадает из цепочки. Потому что при таком условии, под корневым CA может быть только один уровень, но не 2. Например, промежуточный CA (на 2-м уровне) имеет расширение Name Constraints и в нём Exсluded Names прописано www.domain.com, а конечный сертификат выдан на www.domain.com, конечный сертификат снова выпадает из цепочки, потому что промежуточный CA не может выдавать сертификаты на имя www.domain.com. Например, в сертификате промежуточного CA есть расширение Certificate Policies (aka Issuance Policies) с OID = 1.2.3.4, а в конечном сертификате в этом же расширении прописан OID из другого дерева: OID = 1.2.4.5. И снова, конечный сертификат выпадает из цепочки, потому что OID в сертификате не прошёл проверку policy constraints. Этих проверок там овер9000 (см rfc5280) и уже по их результатам определяется годен сертификат для конкретного применения.

Vladimir

Вадимс, спасибо за разъяснение. Непонятна необходимость именно "проверки соответствия сертификатов внутри построенной цепочки", в которой используются механизмы Exact Match,Key Match, Name MAtch. Например, есть https сайт, при входе на него, получаю сертификат и начинается "раскручиваться" цепочка доверия, пока не дойдет к корневому сертификату. Так мне кажется, что механизм "проверки соответствия сертификатов внутри построенной цепочки" подтверждает уже построенную цепочку, но если сертификаты подписаны издавшими их центрами сертификации, то это же тоже подтверждает что цепочка построена верно? Тем более что ЦП построенную цепочку подтверждает "стопудово"... "проверка соответствия сертификат ..." кажется ненужной и избыточной. Вот такое у меня искревлённое понимание реальности )))

Vadims Podāns

Есть немного искривлённого. Самая главная причина необходимости 2-х этапной проверки — в процессе построения цепочки сертификатов может быть построено несколько цепочек (через кросс-сертификацию, множественные сертификаты CA) для одного конечного сертификата. Причём, если какой-то сертификат в цепочке просрочен, такая цепочка всё равно будет строиться. Т.е. на первом этапе надо только добыть нужные сертификаты и построить как можно больше потенциальных цепочек, чтобы потом было из чего выбирать. Когда все возможные цепочки построены, тогда уже наступает черёд второго этапа, который проверяет *каждую* построенную цепочку детально и в итоге выбирает какую-то одну, которая и будет конечной. Смотрите простой сценарий. Есть некоторый подчинённый CA у которого есть 2 сертификата (старый, но не истёкший и обновлённый. Обновлён с использованием существующей ключевой пары. Тогда у обоих будет одинаковое расширение Authority Key Identifier). В этом случае на первом этапе будет построено 2 цепочки (с использованием обоих сертификатов CA). И на втором этапе будет проверяться каждая цепочка на предмет возможности её использования. Если приложение требует проверку сертификатов на отзыв, каждая построенная цепочка проверяется на отзыв. Если одна из них отозвана, она откидывается. Если окажется, что есть 2 и более валидных цепочек, которые можно использовать, существует достаточно сложный алгоритм (в необходимых пределах описан в том же rfc5280), в процессе которого выбирается только какая-то одна, которую вы уже увидите в certification path свойств сертификата. Вот вам и случай с вашим https. Насколько я знаю rfc и его реализацию в CryptoAPI — никаких лишних телодвижений там нету и каждая операция реально необходима.

Михаил

Добрый день! Имеется следующий вопрос: Имею инфраструктуру из AD + CA на одной машине. Плюс один клиент на Windows XP. Для клиента выдаю сертификат smartcardlogon. Вхожу в систему! Все хорошо! После чего откатываю CA + AD до того состояния пока сертификат пользователя еще не был выдан! Вхожу в систему клиентом по сертификату - и ОПЯТЬ ВСЕ ОК!!!! В итоге получается что котроллер домена проверяет лишь наличие соответсвия UPN в сертификате с учетной записью пользователя + подпись сертификата + отсутсвие сертификта пользваотеля в CRL. И в связи с этим спокойно пускает??? Нет проверки наличия серийного номера сертификата в БД сертификатов????

Comments are closed.