2009-05-21 81 views
9

显然我在前面的帖子中提出了错误的问题。我有一个以X.509证书作为安全网站(https://..)运行的Web服务。我想使用公司的根CA颁发的客户机证书(也是X.509)来验证服务器客户机是否有权使用该服务。为了做到这一点,我需要检查证书并寻找一些识别功能,并将其与存储在数据库中的值(可能是指纹?)进行匹配。如何从Web服务中的客户端发送X509Certificate?

下面是我用它来获得从本地证书库中的代码(从http://msdn.microsoft.com/en-us/magazine/cc163454.aspx直举):

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(); } 
    } 

然后,我将证书安装到正是如此出站流:

public static class ServiceDataAccess 
{  
    private static STSWebService _stsWebService = new STSWebService(); 

    public static DataSet GetData(Dictionary<string,string> 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... 
    } 
} 

我的问题是 - 我怎么“搞定”在Web服务代码证书?我遇到过的大多数示例代码片断都涉及如何进行自定义验证,在那里有一个GetCertificate()调用,显然假设该部分非常简单,每个人都应该知道如何去做?

我的主类继承自WebService,所以我可以使用Context.Request.ClientCertificate获取证书,但这是一个HttpClientCertificate,而不是X509Certificate2。 HttpContext给了我相同的结果。其他方法都使用Web配置代码来调用预定义的验证代码,而不知道如何调用自定义C#方法来执行验证。

我敢肯定,这是另一种“愚蠢的问题”,有人会回来,并说:“看,只是做这个和它的作品,”不过没关系。我花了很多时间试图让这个工作,而我的骄傲几乎不存在在这一点上。有人能告诉我我的方式错误吗?

谢谢, 戴夫

+0

如果您没有HttpContext,请参阅http:// stackoverflow的答案。com/questions/7528455/how-to-get-the-x509certificate-from-a-client-request?lq = 1 – 2013-06-20 21:51:30

回答

12

我记得做类似的东西,它已经一段时间,但是,你有没有在你的web服务尝试这样的:

X509Certificate2 cert = new X509Certificate2(Context.Request.ClientCertificate.Certificate); 
+0

这工作!现在我终于可以明白我的问题 - 找出我可以用来匹配数据库中的存储值的价值... Thanks! – DaveN59 2009-05-21 18:01:40

+1

如果您将数据库视为受信任的权威机构,则指纹可以使用,我从事的是使用此方法的应用程序。 OTOH,如果您需要分布式信任模型(使用CA),那么您需要执行额外的检查(例如,验证证书链)。 – DSO 2009-05-21 18:11:23

1

在如何将证书绑回用户,所以假设与该键关联的用户的身份是好的(如证书已被验证回到受信任的根,并已不是b的主题een被撤销),那么你需要将证书所声明的身份与用户绑定。您可以使用主题DN的LDAP字符串形式,然后查看(cn = Username,ou = Department ...)以确定本地ID。在用户重新生成其密钥/证书的情况下,这是因为卡丢失或证书自然失效而产生的弹性。这取决于两个CA不会向两个不同的人颁发两个具有相同主题名称的证书。

如果证书是由MS CA颁发的,那么它可能有一个实际上是域登录名的UPN。

或者,如果要将用户的身份与实际证书绑定,通常的方法是存储颁发者名称和证书序列号。 CA必须为每个证书颁发唯一的序列号。注意序列号可能很大,具体取决于CA.但是,不要使用这种方法,这意味着每次重新颁发用户证书时都必须更新数据库中的证书详细信息。