Почему для некоторых сертификатов Request.ClientCertificate пуст, а для других нет? - PullRequest
0 голосов
/ 01 ноября 2018

Я пытаюсь создать AuthorizeAttribute, который требует, чтобы HTTPRequest содержал указанный сертификат клиента.

Я нашел хорошую серию постов в блоге по этим вопросам, написанную Андрасом Немесом, здесь:

У меня есть тестовый проект Web API, работающий в VS2015, отладка на сайте, работающем на моем локальном IIS, а не на IIS Express, с настроенным https и настройками SSL, разрешающими сертификаты клиентов.

Я почти уверен, что он настроен правильно, потому что он отлично работает для одного из сертификатов, которые я создал.

Мой атрибут прост:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class KtRequireClientCertAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        byte[] cert = HttpContext.Current.Request.ClientCertificate.Certificate;
        // if the ClientCertificate is empty, pass null
        X509Certificate2 suppliedCert = cert.Any() ? new X509Certificate2(cert) : null;

        if (suppliedCert != null && isExpectedCert(suppliedCert)
            return;

        base.OnAuthorization(actionContext);
    }
}

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

ClientCertificate.Certificate - это байт [], содержащий 808 элементов, X509Certificate2 работает правильно, и моя логика проверки работает как положено.

Но с каждым сертификатом, который я пытаюсь создать сегодня, HttpContext.Current.Request.ClientCertificate.Certificate пуст.

Я делаю сертификаты таким образом:

MAKECERT.EXE -ic DevRootCertificate.cer -iv DevRootCertificate.pvk -pe -sv testclientcert.pvk -a sha1 -n "CN=testclientcert" -len 2048 -b 01/01/2015 -e 01/01/2030 -sky exchange testclientcert.cer -eku 1.3.6.1.5.5.7.3.2

Простое мое тестовое клиентское приложение:

using (var requestHandler = new WebRequestHandler())
{
    var certificate = new X509Certificate2(certificateFile);
    requestHandler.ClientCertificates.Add(certificate);

    var url = new Uri(baseUrl);
    using (var client = new HttpClient(requestHandler){BaseAddress = url})
    {
        var response = client.GetAsync(endPoint).Result;
        response.EnsureSuccessStatusCode();

        var content = response.Content.ReadAsStringAsync().Result;

        Console.Out.WriteLine(JToken.Parse(content).ToString(Formatting.Indented));
    }
}

Вопрос в том, почему один сертификат передается атрибуту, а другой нет?


Дополнительная информация:

Я использую один и тот же клиент на том же сервере, работающем на IIS на моей локальной машине. Веб-сайт настроен на прием, но не требование клиентских сертификатов.

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

Я не уверен, есть ли у работающего сертификата закрытый ключ или нет, но работает файл .cer, а не .pfx.

Файл, который не работал, также был .cer. И я знал, что это не было подписано. Поэтому я создал подписанный сертификат и попытался создать X509Certificate2 () с файлом .pfx. Я получил ошибку 403, даже не попав на сервер.

1 Ответ

0 голосов
/ 02 ноября 2018

Первая проблема

  • Почему я получал 403 ошибки, фактически не входя в действие моего контроллера?

Веб-сервер и клиент согласовывают, какие сертификаты отправит клиент. Сервер отправляет список прав подписи, которые он примет, а клиент отправляет те сертификаты, которые приемлемы.

Если вы играете с самозаверяющими сертификатами, первое, что вы делаете, это создаете корневой сертификат и импортируете его открытый ключ в ваше хранилище сертификатов текущего пользователя как «Trusted Root Certification Authority».

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

Вторая проблема

  • Почему сертификат клиента, который я создал пару дней назад, работал, а сертификат, который я создал с тех пор, нет?

Сработал файл .cer, так почему же он работал, если другие файлы .cer не работали?

Личные ключи, конечно.

Но, вы говорите, файлы .cer не имеют закрытых ключей. Правда, нет. Но файл .cer у меня работал, был экспортирован из хранилища пользователей.

То есть я создал сертификат в виде файла .cer и .pvk, а затем объединил оба вместе в файл .pfx.

Я импортировал файл .pfx в свое хранилище пользователей, а затем экспортировал его в файл .cer.

Когда мой клиент загрузил файл exported.cer, он знал, что закрытый ключ действителен, потому что он был в хранилище пользователей, поэтому ему не требовался пароль, предоставленный при создании объекта X509Certificate2.

Когда я пытался сделать то же самое с сертификатом, которого не было в хранилище пользователей, использование файла .cer не работало. Использовать файл .pfx - если я ввел пароль.

var certificate = new X509Certificate2("testcert.pfx", "Password1");
...