Search code examples
c#httpwebrequestx509certificate

Force HttpWebRequest to send client certificate


I have a p12 certificate, that I load it in this way:

X509Certificate2 certificate = new X509Certificate2(certName, password,
        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet |
        X509KeyStorageFlags.Exportable);

It is loaded correcty, in fact If i do certificate.PrivateKey.ToXmlString(true); it returns a complete xml without errors. But If I do:

try
{
    X509Chain chain = new X509Chain();
    var chainBuilt = chain.Build(certificate);
    Console.WriteLine("Chain building status: "+ chainBuilt);

    if (chainBuilt == false)
        foreach (X509ChainStatus chainStatus in chain.ChainStatus)
            Console.WriteLine("Chain error: "+ chainStatus.Status);
}
catch (Exception ex)
{
    Console.WriteLine(ex);
}

it writes:

Chain building status: False
Chain error: RevocationStatusUnknown 
Chain error: OfflineRevocation 

so when I do:

        ServicePointManager.CheckCertificateRevocationList = false;
    ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
    ServicePointManager.Expect100Continue = true;
    Console.WriteLine("connessione a:" + host);
    HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host);
    req.PreAuthenticate = true;
    req.AllowAutoRedirect = true;
    req.ClientCertificates.Add(certificate);
    req.Method = "POST";
    req.ContentType = "application/x-www-form-urlencoded";
    string postData = "login-form-type=cert";
    byte[] postBytes = Encoding.UTF8.GetBytes(postData);
    req.ContentLength = postBytes.Length;
    Stream postStream = req.GetRequestStream();
    postStream.Write(postBytes, 0, postBytes.Length);
    postStream.Flush();
    postStream.Close();

    WebResponse resp = req.GetResponse();

the server says that the certificate is not sent/valid.

My question is:

  • how can I sent the certificate even with chain build false?
  • there is another class to post a certificate that does not check the certificate validation before send it?

many thanks. Antonino


Solution

  • I resolved the problem, The point is that a P12 file (as a PFX) contains more then 1 certificate, so it must be loaded in this way:

    X509Certificate2Collection certificates = new X509Certificate2Collection();
    certificates.Import(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
    

    and added to a HttpWebRequest in this way: request.ClientCertificates = certificates;

    Thanks everybody for support.

    COMPLETE SAMPLE CODE

    string host = @"https://localhost/";
    string certName = @"C:\temp\cert.pfx";
    string password = @"password";
    
    try
    {
        X509Certificate2Collection certificates = new X509Certificate2Collection();
        certificates.Import(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
    
        ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;
        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(host);
        req.AllowAutoRedirect = true;
        req.ClientCertificates = certificates;
        req.Method = "POST";
        req.ContentType = "application/x-www-form-urlencoded";
        string postData = "login-form-type=cert";
        byte[] postBytes = Encoding.UTF8.GetBytes(postData);
        req.ContentLength = postBytes.Length;
    
        Stream postStream = req.GetRequestStream();
        postStream.Write(postBytes, 0, postBytes.Length);
        postStream.Flush();
        postStream.Close();
        WebResponse resp = req.GetResponse();
    
        Stream stream = resp.GetResponseStream();
        using (StreamReader reader = new StreamReader(stream))
        {
            string line = reader.ReadLine();
            while (line != null)
            {
                Console.WriteLine(line);
                line = reader.ReadLine();
            }
        }
    
        stream.Close();
    }
    catch(Exception e)
    {
        Console.WriteLine(e);
    }