Как использовать SSL-сертификаты с HttpWebRequest в C#?

В настоящее время я пишу служебное приложение, которое будет подключаться к данному IP и Порту и проверять информацию в сертификате SSL с помощью HttpWebRequest. Когда я пытаюсь извлечь сертификат, я получаю сообщение об ошибке, вызвавшей исключение. Исключение, по-видимому, связано с тем, что акт преодоления SSL-сертификата, похоже, запускает еще одну проверку проверки.

вот код, и, возможно, кто-то может показать мне лучший способ сделать это, или если я что-то упускаю. Я не важно, истек ли срок действия SSL-сертификата или не соответствует URL-адресу. Все это не имеет отношения к тому, что я делаю.

когда я назначаю X509Certificate в делегате новой переменной и смотрю на переменную в отладчике, все свойства показывают SSLCert.Эмитент выдал исключение типа ' System.Безопасность.Криптография.CyrptographicException'

когда я пытаюсь получить доступ к свойству SSLCert, я получаю следующее исключение: m_safecertcontext является недопустимым дескриптором

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

код ниже, я поставил некоторые комментарии а также для того, что не работает и что работает.

 // To get around the SSL validation in the HttpWebRequest
        System.Net.ServicePointManager.ServerCertificateValidationCallback =
            delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
                        System.Security.Cryptography.X509Certificates.X509Chain chain,
                        System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                // The below works but isn't what I want. CertName and ExpireDate are both Strings
                this.CertName = ProcessSubject(certificate.Subject);
                this.ExpireDate = certificate.GetExpirationDateString();
                // The below works but the X509Certificate SSLCert shows exceptions in the debugger for most of the properties.
                this.SSLCert = certificate;

                return true; // **** Always accept
            };
        HttpWebRequest myRequest = (HttpWebRequest)System.Net.WebRequest.Create("https://" + this.IP + ":" + this.Port + "/SSLCheck.html");
        myRequest.KeepAlive = false;
        myRequest.Method = "GET";

        try
        {
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
        }
        catch (Exception e)
        {
            if (e.Message != "The remote server returned an error: (404) Not Found.")
            {
                throw Exception("Error");
            }

        }

        // THE BELOW FAILS
        this.CertName = this.SSLCert.Subject;

2 ответов


(редактировать из наших комментариев ниже)

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


Это просто догадка с моей стороны. Я думаю, что происходит то, что информация о сертификате, проходящая через SSL-рукопожатие, используется .NET для создания объекта cert, который передается вам в делегате. Делегат должен использоваться только для целей проверки. После завершения вызова .NET закрывает безопасный дескриптор сертификата. Вот почему вызов не выполняется при попытке получить доступ к сертификату вне обратного вызова.

чтобы обойти это, вы можете сериализовать сертификат внутри делегата и десериализуйте его вне делегата.