Вы должны знать о RFC3280, раздел 6.1 и RFC5280, раздел 6.1 . Оба описывают алгоритмы для проверки путей сертификатов. Хотя Win32 API позаботится о некоторых вещах для вас, все же было бы полезно узнать о процессе в целом.
Кроме того, вот (на мой взгляд) довольно заслуживающая доверия ссылка: Код подтверждения сертификата хрома .
В целом, я думаю, что ваш код неверен. Но вот несколько вещей, которые я бы изучил / изменил бы, если бы я был вами:
1. Отдельная проверка общего имени
Хром проверяет общее имя сертификата отдельно от цепочки. Видимо они заметили некоторые проблемы с этим. См комментарии для их обоснования:
cert_verify_proc.win.cc:731 // Certificate name validation happens separately, later, using an internal
cert_verify_proc.win.cc:732 // routine that has better support for RFC 6125 name matching.
2. Используйте CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
Chromium также использует флаг CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT вместо CERT_CHAIN_REVOCATION_CHECK_CHAIN. На самом деле я начал изучать это до того, как нашел их код, и это укрепило мою уверенность в том, что вам следует использовать CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT.
Несмотря на то, что оба вышеупомянутых RFC указывают, что самозаверяющий якорь доверия не считается частью цепочки, документация для CertGetCertificateChain (http://msdn.microsoft.com/en-us/library/windows/desktop/aa376078(v=vs.85).aspx) говорит, что он строит цепочку до, если возможно, доверенного корневого сертификата . Доверенный корневой сертификат определяется (на той же странице) как доверенный самоподписанный сертификат.
Это исключает возможность того, что * EXCLUDE_ROOT может пропустить проверку отзыва для привязки доверия без полномочий root (Win32 фактически требует, чтобы привязки доверия были самозаверяющими, даже если это не требуется никакими RFC. Хотя это официально не задокументировано ).
Теперь, поскольку сертификат корневого CA не может отозвать сам себя (CRL не может быть подписан / проверен), мне кажется, что эти два флага идентичны.
Я немного погуглил и наткнулся на это сообщение на форуме: http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/9f95882a-1a68-477a-80ee-0a7e3c7ae5cf/x509revocationflag-question?forum=windowssecurity. Член .NET Product Group (предположительно) утверждает, что флаги на практике действуют одинаково, если корень самоподписан (теоретически) флаг ENTIRE_CHAIN будет проверять корневой сертификат на отзыв, если он включает расширение CDP, но этого не может быть).
Он также рекомендует использовать флаг * EXCLUDE_ROOT, поскольку другой флаг может вызвать ненужный сетевой запрос, если самозаверяющий корневой CA включает расширение CDP.
К сожалению:
- Я не могу найти никакого официально документированного объяснения различий между этими двумя флагами.
- Хотя вполне вероятно, что связанное обсуждение применимо к тем же флагам Win32 API под капотом .NET, это не гарантируется.
Чтобы быть полностью уверенным, что CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT можно использовать, я немного погуглил и нашел код подтверждения SSL-сертификата Chromium, на который я ссылался, в верхней части моего ответа.
В качестве дополнительного бонуса файл Chromium cert_verify_proc_win.cc содержит следующие подсказки о коде подтверждения IE:
618: // IE passes a non-NULL pTime argument that specifies the current system
619: // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the
620: // chain_flags argument.
Не знаю, как они узнали бы об этом, но сейчас я чувствую себя комфортно, используя CERT_CHAIN_REVOCATION_CHECK_EXCLUDE_ROOT.
3. Различные принятые сертификаты
Я заметил, что Chromium также указывает 3 использования сертификата вместо 1:
szOID_PKIX_KP_SERVER_AUTH,
szOID_SERVER_GATED_CRYPTO,
szOID_SGC_NETSCAPE
Исходя из того, что я могу получить через Google, старым веб-браузерам могут потребоваться другие способы использования, в противном случае они могут не установить безопасное соединение.
Если Chromium сочтет целесообразным включить это использование, я последую этому примеру.
Обратите внимание, что если вы измените свой код, вам также следует установить для params.RequestedUsage.dwType значение USAGE_MATCH_TYPE_OR вместо USAGE_MATCH_TYPE_AND.
-
Я не могу думать ни о каких других комментариях в данный момент. Но на вашем месте я бы сам проверил источник Chromium (и, возможно, Firefox) - просто чтобы убедиться, что ничего не пропустил.