title: How do I get the X509Certificate sent from the client in web service?
body: <p>Apparently I was asking the wrong question in my earlier post.  I have a web service secured with a X.509 certificate, running as a secure web site (<a href="https://.." rel="nofollow noreferrer">https://..</a>.).  I want to use the client's machine certificate (also X.509) issued by the company's root CA to verify to the server that the client machine is authorized to use the service.  In order to do this, I need to inspect the certificate and look for some identifying feature and match that to a value stored in a database (maybe the Thumbprint?).</p>
  
  <p>Here is the code I use to get the certificate from the local certificate store (lifted straight from <a href="http://msdn.microsoft.com/en-us/magazine/cc163454.aspx" rel="nofollow noreferrer">http://msdn.microsoft.com/en-us/magazine/cc163454.aspx</a>):</p>
  
  <pre><code> public static class SecurityCertificate
  {
      private static X509Certificate2 _certificate = null;
  
      public static X509Certificate2 Certificate
      {
          get { return _certificate; }
      }
  
      public static bool LoadCertificate()
      {
          // get thumbprint from app.config
          string thumbPrint = Properties.Settings.Default.Thumbprint;
          if ( string.IsNullOrEmpty( thumbPrint ) )
          {
              // if no thumbprint on file, user must select certificate to use
              _certificate = PickCertificate( StoreLocation.LocalMachine, StoreName.My );
              if ( null != _certificate )
              {
                  // show certificate details dialog
                  X509Certificate2UI.DisplayCertificate( _certificate );
                  Properties.Settings.Default.Thumbprint = _certificate.Thumbprint;
                  Properties.Settings.Default.Save();
              }
          }
          else
          {
              _certificate = FindCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, thumbPrint );
          }
  
          if ( null == _certificate )
          {
              MessageBox.Show( "You must have a valid machine certificate to use STS." );
              return false;
          }
  
          return true;
      }
  
      private static X509Certificate2 PickCertificate( StoreLocation location, StoreName name )
      {
          X509Store store = new X509Store( name, location );
          try
          {
              // create and open store for read-only access
              store.Open( OpenFlags.ReadOnly );
  
              X509Certificate2Collection coll = store.Certificates.Find( X509FindType.FindByIssuerName, STSClientConstants.NBCCA, true );
              if ( 0 == coll.Count )
              {
                  MessageBox.Show( "No valid machine certificate found - please contact tech support." );
                  return null;
              }
  
              // pick a certificate from the store
              coll = null;
              while ( null == coll || 0 == coll.Count )
              {
                  coll = X509Certificate2UI.SelectFromCollection(
                          store.Certificates, "Local Machine Certificates",
                          "Select one", X509SelectionFlag.SingleSelection );
              }
  
              // return first certificate found
              return coll[ 0 ];
          }
          // always close the store
          finally { store.Close(); }
      }
  
      private static X509Certificate2 FindCertificate( StoreLocation location, StoreName name, X509FindType findType, string findValue )
      {
          X509Store store = new X509Store( name, location );
          try
          {
              // create and open store for read-only access
              store.Open( OpenFlags.ReadOnly );
  
              // search store
              X509Certificate2Collection col = store.Certificates.Find( findType, findValue, true );
  
              // return first certificate found
              return col[ 0 ];
          }
          // always close the store
          finally { store.Close(); }
      }
  </code></pre>
  
  <p>Then, I attach the certificate to the outbound stream thusly:</p>
  
  <pre><code>public static class ServiceDataAccess
  {    
      private static STSWebService _stsWebService = new STSWebService();
  
      public static DataSet GetData(Dictionary&lt;string,string&gt; DictParam, string action)
      {
          // add the machine certificate here, the first web service call made by the program (only called once)
          _stsWebService.ClientCertificates.Add( SecurityCertificate.Certificate );
          // rest of web service call here...
      }
  }
  </code></pre>
  
  <p>My question is this -- how do I "get" the certificate in the web service code?  Most sample code snippets I have come across that cover how to do custom validation have a GetCertificate() call in there, apparently assuming that part is so easy everyone should know how to do it?</p>
  
  <p>My main class inherits from WebService, so I can use Context.Request.ClientCertificate to get a certificate, but that's an HttpClientCertificate, not an X509Certificate2.  HttpContext gives me the same result.  Other approaches all use web configuration code to call pre-defined verification code, with no clue as to how to call a custom C# method to do the  verification.</p>