x509Chain.build завершается ошибкой, certutil -verify проходит

У меня есть корневой сертификат и лист. Лист имеет расширение OID URL CRL, которое указывает на действительное онлайн-местоположение. Делая это:

certutil -verify .\leaf.cer

терпит неудачу с

ОШИБКА: возвращено состояние проверки отзыва листового сертификата. Функция отзыва не смогла проверить отзыв, поскольку сервер отзыва был отключен. 0x80092013 (-2146885613 CRYPT_E_REVOCATION_OFFLINE)

Если я сделаю это:

certutil -verify .\leaf.cer .\root.cer

Затем проверка проходит, и я вижу, что CRL извлекается из сети в Fiddler.

В моем коде С# я делаю это:

X509Chain childCertChain = new X509Chain();
childCertChain.ChainPolicy.ExtraStore.Add(rootCert);
childCertChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
childCertChain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(10);
if (!childCertChain.Build(childCert))
        {
            // The root cert is not in the windows certificate store, that is fine
            if (childCertChain.ChainStatus.Length != 1 || childCertChain.ChainStatus.First().Status != X509ChainStatusFlags.UntrustedRoot)
            {
                throw new Exception("Certificate validation error.");
            }
        }

Это приведет к моему исключению, и хотя chainElements будут правильно заполнены двумя сертификатами, ChainStatus покажет:

OfflineRevocation, RevocationStatusUnknown

Я также не увижу никаких веб-запросов в Fiddler. Я могу программно загрузить CRL по URL-адресу, так что это не моя среда отладки, насколько мне известно. Есть идеи, как добиться успеха x509Chain.Build?


person serkan    schedule 08.04.2020    source источник
comment
Сколько элементов вы получаете в chain.ChainElements?   -  person Crypt32    schedule 08.04.2020
comment
в нем 2 элемента, поэтому построение цепочки работает. Это только часть проверки, которая терпит неудачу.   -  person serkan    schedule 08.04.2020
comment
Тогда, возможно, root доверяет пользователь, а не машина. Или есть проблемы с проверкой отзыва.   -  person Crypt32    schedule 08.04.2020
comment
Да, в моем коде выше я разрешаю untrustedRoot, но я получаю две другие ошибки в ChainStatus: OfflineRevocation, RevocationStatusUnknown   -  person serkan    schedule 08.04.2020
comment
Что говорит certutil -verify -urlfetch cert.cer. Проверьте, все ли URL-адреса в порядке, или, что еще лучше, опубликуйте вывод certutil.   -  person Crypt32    schedule 08.04.2020
comment
Да, в моем вопросе выше я упоминаю, что certutil -verify .\leaf.cer терпит неудачу, но certutil -verify .\leaf.cer .\root.cer проходит   -  person serkan    schedule 08.04.2020
comment
С переключателем -urlfetch?   -  person Crypt32    schedule 08.04.2020
comment
такое же поведение с -urfetch, если я передам и лист, и корень, он пройдет. . Может быть, то же самое происходит в моем коде, может быть, extraStore не проверяется при проверке URL-адресов?   -  person serkan    schedule 08.04.2020


Ответы (1)


Я прочитал ваш код с ПК и понял, в чем дело: ваш корневой сертификат не является доверенным в вашей системе. Windows CryptoAPI выдает CERT_E_UNTRUSTEDROOT, если корневой сертификат не является доверенным. Вместе с этим CryptoAPI завершает проверку отзывов и выдает две дополнительные ошибки: CRYPT_E_NO_REVOCATION_CHECK и CERT_E_UNTRUSTEDROOT, потому что проверка отзывов была пропущена. Кроме того, с недоверенным корнем CryptoAPI пропускает другие проверки (такие как ограничения, например), но не сообщает о них. Все правильно и ожидаемо.

Вы пытаетесь разрешить недоверенный рут, но делаете это неправильно, потому что таким образом вы пропускаете другие проверки (как было сказано в предыдущем абзаце) и ваша логика уязвима.

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

У вас есть два варианта:

  1. сделать корневой сертификат доверенным для машины (локальной системы). Это может быть невозможно.
  2. вызовите функцию CertCreateCertificateChainEngine напрямую и поместите корневой сертификат в hRestrictedTrust элемент структуры CERT_CHAIN_ENGINE_CONFIG.

Если вы работаете в Windows, второй подход является наиболее безопасным и надежным. На данный момент .NET X509Chain не реализует эту функциональность. Это требует дополнительного кодирования, но альтернатив не так много.

person Crypt32    schedule 08.04.2020
comment
Вы правы, установка сертификата разрешила ошибку ненадежного корня, а также ошибки revocationUnknown. Я постараюсь реализовать 2. или получить одобрение на 1. Спасибо! - person serkan; 09.04.2020
comment
1-й вариант открывает уязвимость в системе безопасности. Вы были предупреждены. - person Crypt32; 09.04.2020