Два сертификата CA могут иметь один и тот же открытый ключ и один и тот же subject и всё же не быть взаимозаменяемыми. Один самоподписанный, другой кросс-подписан старым корнем, и их имена издателя, серийные номера и подписи различаются. Лист может привязаться именно к одному из них через свой Authority Key Identifier. Эта привязка остаётся невидимой, пока клиент не выберет неверную цепочку и handshake не завершится неудачей без видимой причины.

Выполните эти пять проверок по порядку: каждая исключает свой тип отказа.

Проверка 1: нарисуйте обе цепочки, прежде чем трогать шаблон

Запишите пути. Старая популяция доверяет Старому корню A, который выпустил CA B, который выпустил лист сервера. Новая популяция доверяет самоподписанному CA B напрямую. Оба сертификата B несут один и тот же ключ и subject, и именно поэтому человек, читающий строку subject, видит один CA там, где клиент видит два.

Кросс-подписанная копия тоже должна быть настоящим сертификатом CA, с basic constraints и key usage, разрешающими подпись.

Проверка 2: сравните поля AKI, а не только ключ

Имя издателя листа должно совпадать с subject B, и эта часть обычно держится. Authority Key Identifier — это место, где две копии расходятся, потому что он может нести идентификатор ключа, сертификат издателя и серийный номер. Идентификатор ключа совпадает с обеими копиями, так как ключ идентичен. Поля издателя и серийного номера совпадают ровно с одной, и поэтому цепочка, построенная против самоподписанной копии, может не пройти против кросс-подписанной.

Изучите лист вместо догадок: openssl x509 -in server.pem -noout -ext authorityKeyIdentifier.

Затем сравните обоих кандидатов с помощью openssl x509 -in b-cross.pem -noout -text | grep -A2 "Authority Key Identifier" и ту же команду против самоподписанной копии.

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

Проверка 3: меняйте политику выпуска, а не подписанные байты

Расширения живут внутри подписи. Добавление, удаление или правка одного из них в существующем листе — это не ремонт, это другой сертификат, и он требует перевыпуска. Изменение относится к политике выпуска: authorityKeyIdentifier = keyid,issuer:always заставляет новые листы нести привязку, специфичную для сертификата, а один keyid сохраняет более свободную форму, подходящую для намеренного перехода на кросс-подпись. Решите, что нужно вашей PKI, прежде чем будет подписан следующая партия.

Правка общего шаблона меняет и каждый будущий сертификат, а не только сервер перед вами.

Проверка 4: проверяйте каждую популяцию доверия отдельно

Проверяйте старый путь и новый путь отдельными запусками. openssl verify -purpose sslserver -verify_hostname vpn.example -CAfile old-root.pem -untrusted b-cross-signed.pem server.pem упражняет кросс-подписанный маршрут, а та же команда с новым корнем и без untrusted-файла упражняет самоподписанный маршрут. Смешивание обоих корней в одном наборе скрывает, какая цепочка была выбрана. Затем повторите с настоящими клиентами, потому что VPN-бэкенд может предпочитать цепочку или закреплять сертификат способами, которых openssl не делает.

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

Проверка 5: держите старый путь на часах вывода из эксплуатации

Кросс-подпись по замыслу поддерживает старый путь доверия живым, и это одновременно цель и риск. Она не устраняет скомпрометированный старый корень и не удаляет этот корень ни из одного клиента. Запишите, когда старый путь перестанет давать доверие, и подтвердите, что этот день действительно наступит.

Если каждый клиент может принять новый корень до перемещения листов, простая раскатка с двойным доверием проще кросс-подписи, и она оставляет на одну вещь меньше для вывода из эксплуатации.

Похожие статьи