views:

1752

answers:

3

I am trying to read an X509 certificate using Request.ClientCertificate but nothing is returned. The certificate is definitely being attached to the request because I can get the certificate information from the page sending the request.

I have tried reading the certificate from several different places but cannot seem to get it to work.

I started with code from this KB Article. In the requested page I tried to print out some information about the certificate but nothing was returned in the response.

This is running on IIS 5.1 and the communication is over SSL. This must be done using version 2 of the .Net framework

Why does the certificate seem to dissappear?

A: 

Ok it isn't completely clear but you have a website which requires the clients to authenticate themselves using certificates? Because thats what the Request.ClientCertificate property is for.

I say this because there's something odd about your question.

"I can get the certificate information from the page sending the request."

Pages in general do not really send requests the clients do.

To get the server cert you could open the X509Store and sift through the certs to find the one with the CN you need.

the_ajp
the "page sending the request" is the client in this case. It attaches an X509 certificate to the request for the page that I try to use the Request.ClientCertificate property in
Sean
+1  A: 

I'm not sure what you need the client certificate for, but if you're using it for your own custom authentication or authorization, you may want to consider using the web server's security infrastructure instead of implementing your own. For example, you can configure IIS to require client certificates, map the certs to user accounts, and use Windows-based authentication. Of course, this doesn't necessarily work for your problem domain.

Jacob
A: 

I wrote a identification web page a while back that looked for a client certificate and if found would display the certificate information. I believe that is what you are looking for... Here is the page:

<%@ Page Language="C#" Trace="false" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<%@ Import Namespace="System.Security.Cryptography.X509Certificates" %>
<%@ Import Namespace="System.Security.Cryptography" %>

<script runat="server">
    //protected void Page_Load(object sender, EventArgs e)
    //{ }

    void LoadCertInfo()
    {
        string para = "<div style='margin: 10px 0 0 0; font-weight: bold'>{0}</div>";
        string subpara = "<div style='margin-left: 15px; font-size: 90%'>{0}</div>";

        if (Page.Request.ClientCertificate.IsPresent)
        {
            Response.Write("<hr /><div style='width: 500px; margin: 20px auto'>");
            Response.Write("<h3 style='width: 500px; margin: 20px auto'>Client Certificate Information</h3>");
            try
            {
                X509Certificate2 x509Cert2 = new X509Certificate2(Page.Request.ClientCertificate.Certificate);

                Response.Write(string.Format(para, "Issued To:"));
                Response.Write(string.Format(subpara, x509Cert2.Subject));

                Response.Write(string.Format(para, "Issued By:"));
                Response.Write(string.Format(subpara, x509Cert2.Issuer));

                Response.Write(string.Format(para, "Friendly Name:"));
                Response.Write(string.Format(subpara, string.IsNullOrEmpty(x509Cert2.FriendlyName) ? "(None Specified)" : x509Cert2.FriendlyName));

                Response.Write(string.Format(para, "Valid Dates:"));
                Response.Write(string.Format(subpara, "From: " + x509Cert2.GetEffectiveDateString()));
                Response.Write(string.Format(subpara, "To: " + x509Cert2.GetExpirationDateString()));

                Response.Write(string.Format(para, "Thumbprint:"));
                Response.Write(string.Format(subpara, x509Cert2.Thumbprint));

                //Response.Write(string.Format(para, "Public Key:"));
                //Response.Write(string.Format(subpara, x509Cert2.GetPublicKeyString()));

                #region EKU Section - Retrieve EKU info and write out each OID
                X509EnhancedKeyUsageExtension ekuExtension = (X509EnhancedKeyUsageExtension)x509Cert2.Extensions["Enhanced Key Usage"];
                if (ekuExtension != null)
                {
                    Response.Write(string.Format(para, "Enhanced Key Usages (" + ekuExtension.EnhancedKeyUsages.Count.ToString() + " found)"));

                    OidCollection ekuOids = ekuExtension.EnhancedKeyUsages;
                    foreach (Oid ekuOid in ekuOids)
                        Response.Write(string.Format(subpara, ekuOid.FriendlyName + " (OID: " + ekuOid.Value + ")"));
                }
                else
                {
                    Response.Write(string.Format(para, "No EKU Section Data"));
                }
                #endregion // EKU Section

                #region Subject Alternative Name Section
                X509Extension sanExtension = (X509Extension)x509Cert2.Extensions["Subject Alternative Name"];
                if (sanExtension != null)
                {
                    Response.Write(string.Format(para, "Subject Alternative Name:"));
                    Response.Write(string.Format(subpara, sanExtension.Format(true)));
                }
                else
                {
                    Response.Write(string.Format(para, "No Subject Alternative Name Data"));
                }

                #endregion // Subject Alternative Name Section

                #region Certificate Policies Section
                X509Extension policyExtension = (X509Extension)x509Cert2.Extensions["Certificate Policies"];
                if (policyExtension != null)
                        {
                            Response.Write(string.Format(para, "Certificate Policies:"));
                            Response.Write(string.Format(subpara, policyExtension.Format(true)));
                        }
                        else
                        {
                            Response.Write(string.Format(para, "No Certificate Policies Data"));
                        }
                #endregion //Certificate Policies Section


                // Example on how to enumerate all extensions
                //foreach (X509Extension extension in x509Cert2.Extensions)
                //    Response.Write(string.Format(para, extension.Oid.FriendlyName + "(" + extension.Oid.Value + ")"));
            }
            catch (Exception ex)
            {
                Response.Write(string.Format(para, "An error occured:"));
                Response.Write(string.Format(subpara, ex.Message));
                Response.Write(string.Format(subpara, ex.StackTrace));
            }
            finally
            {
                Response.Write("</div>");
            }
        }
    }
</script>
<html>
  <head runat="server">
    <title><% Page.Response.Write(System.Environment.MachineName); %></title>
  </head>
  <body>
      <% LoadCertInfo();  %>
  </body>
</html>
Dscoduc