How can you add a Certificate to WebClient (C#)?
Asked Answered
D

4

79

I know it is pretty simple to add a certificate to a HttpWebRequest. However, I have not found a way to do the equivalent using WebClient. Basically, I want to send out a POST with a specific certificate using WebClient.

How would you accomplish this exact code using WebClient:

var request = (HttpWebRequest) WebRequest.Create("my-url");
request.Method = "POST";
request.ClientCertificates.Add(new X509Certificate()); //add cert
Duct answered 14/1, 2010 at 18:24 Comment(1)
Note for future answer-seekers, Microsoft recommends using the newer HttpClient instead of WebClient: We don't recommend that you use the WebClient class for new development. Instead, use the System.Net.Http.HttpClient class.Fulgurite
C
103

You must subclass and override one or more functions.

class MyWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
        request.ClientCertificates.Add(new X509Certificate());
        return request;
    }
}
Cervical answered 14/1, 2010 at 18:59 Comment(1)
Awesome! Been trying to figure out how to do this for far far too longBand
B
12
public class CertificateWebClient : WebClient
{
    private readonly X509Certificate2 certificate;

    public CertificateWebClient(X509Certificate2 cert)
    {
        certificate = cert;
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);

        System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate(Object obj, X509Certificate X509certificate, X509Chain chain, System.Net.Security.SslPolicyErrors errors)
        {
            return true;
        };

        request.ClientCertificates.Add(certificate);
        return request;
    }
}

Now you can with self signed cert ! ("The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.; The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.;")

        X509Certificate2 Cert = new X509Certificate2("client.p12", "1234", X509KeyStorageFlags.MachineKeySet);

        // Create a new WebClient instance.
        CertificateWebClient myWebClient = new CertificateWebClient(Cert);

        string fileName = Installation.destXML;
        string uriString = "https://xxxxxxx.xx:918";
        // Upload the file to the URI.
        // The 'UploadFile(uriString,fileName)' method implicitly uses HTTP POST method.
        byte[] responseArray = myWebClient.UploadFile(uriString, fileName);

        // Decode and display the response.
        Console.WriteLine("\nResponse Received.The contents of the file uploaded are:\n{0}",
            System.Text.Encoding.ASCII.GetString(responseArray));
Burgle answered 10/6, 2013 at 21:24 Comment(2)
If you add the certificate to the webRequest.ClientCertificates then you no longer need to override the ServerCertificateValidationCallback , which is a global setting, and thus you are affecting everythingHoptoad
if you have this exeception message The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel add the this ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;Miscegenation
J
5

An interesting thing happened when a new certificate was installed on our front-ends. We started getting the error:

"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.; The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.;"

We took care of the error by going to each front-end and opening the browser. It seems that IE was caching the old certificate. By opening the browsers, the new certificate took effect. Problem Solved!

Jonajonah answered 27/9, 2011 at 19:48 Comment(0)
S
4

Just subclass WebClient, add your own ClientCertificates property and override the WebClient.GetWebRequest(System.Uri) method. I don't have time to convert this to C# from VB but it should be fairly self-explanatory:

Imports System.Net

Public Class WebClient2
    Inherits System.Net.WebClient

    Private _ClientCertificates As New System.Security.Cryptography.X509Certificates.X509CertificateCollection
    Public ReadOnly Property ClientCertificates() As System.Security.Cryptography.X509Certificates.X509CertificateCollection
        Get
            Return Me._ClientCertificates
        End Get
    End Property
    Protected Overrides Function GetWebRequest(ByVal address As System.Uri) As System.Net.WebRequest
        Dim R = MyBase.GetWebRequest(address)
        If TypeOf R Is HttpWebRequest Then
            Dim WR = DirectCast(R, HttpWebRequest)
            If Me._ClientCertificates IsNot Nothing AndAlso Me._ClientCertificates.Count > 0 Then
                WR.ClientCertificates.AddRange(Me._ClientCertificates)
            End If
        End If
        Return R
    End Function
End Class
Seaworthy answered 14/1, 2010 at 18:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.