Search code examples
webclientclient-certificatesiis-10

If WebClient adds a cert to request.ClientCertificates will the cert be found at context.Request.ClientCertificate in the web app?


My client-side code uses WebClient and appends a certificate to ClientCertificates:

 protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address); 
            var x509 = GetMyCert();  // see note
            request.ClientCertificates.Add( x509  );
            return request;
        }

NOTE: I've checked in the debugger and variable x509 does indeed contain a valid certificate object at this point in the code.

Is that not the right way to add the cert to the HttpWebRequest so that it is available to the web app?

Server-side, the certificate isn't showing up in the ProcessRequest method of the IHttpHandler:

         context.Response.Clear();
         // set some Response caching parameters here <snip>

         HttpClientCertificate cert = context.Request.ClientCertificate;
         if (cert.IsPresent)
          {
             Hooray();
          }
          else
         {
             BooHoo();   // we are here
         }

The web.config is set to accept a client certificate:

 <system.webServer>
        <security>
            <access sslFlags="Ssl, SslNegotiateCert" />
        </security>
    </system.webServer>

Is the web app configuration incomplete?

P.S. If I add the callback to the overridden GetWebRequest method:

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

errors is SslPolicyErrors.None and the callback returns true. But I have not created any policy on the server, to my knowledge, unless there's a default of some kind.


Solution

  • The reason why the certificate is not showing up in the HttpContext is the certificate authentication hasn’t been established yet between the client-side and the server-side. Simply speaking, when the web application is hosted in IIS, we disable other authentication modes in IIS and enable the IIS client certificate mapping authentication. the server requires a client certificate when the client tries to access the website/service.
    enter image description here
    enter image description here
    enter image description here
    Subsequently, the below function method will have a returned value.

    public ActionResult About()
        {
            var result = System.Web.HttpContext.Current.Request.ClientCertificate;
            ViewBag.Message = result.Subject+result.ServerSubject;
            return View();
    }
    

    enter image description here
    Please refer to the documentation for what is IIS Client Certificate Mapping Authentication and how to implement it in IIS.
    https://learn.microsoft.com/en-us/iis/configuration/system.webserver/security/authentication/iisclientcertificatemappingauthentication/
    https://learn.microsoft.com/en-us/troubleshoot/iis/configure-many-to-one-client-mappings
    https://learn.microsoft.com/en-us/iis/manage/configuring-security/configuring-one-to-one-client-certificate-mappings
    Feel free to let me know if there is anything I can help with.