【问题标题】:Programmatically installing certificate revocation list C#以编程方式安装证书吊销列表 C#
【发布时间】:2010-12-01 09:50:52
【问题描述】:

我正在使用 C#/WCF。我有一个应由客户端调用的 Web 服务。 这是服务定义:

<service behaviorConfiguration="WCFInterface.CommonBehavior" name="WCFInterface.Content">
  <endpoint address="" binding="ws2007HttpBinding" bindingConfiguration="wsHttpUserName"
 contract="ABB.fTunes.WCFInterface.IContent">
    <identity>
      <dns value="fTunesTestServer" />
    </identity>
  </endpoint>
  <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>

这是绑定:

<ws2007HttpBinding>
  <binding name="wsHttpUserName">
    <security mode="Message">
      <message clientCredentialType="UserName"/>
    </security>
  </binding>
</ws2007HttpBinding>

如果我理解正确的话,从服务器发送到客户端的消息是用证书加密的。目前我仍在使用开发人员证书。 我在服务器上创建了一个根证书、一个证书吊销列表和一个密钥。

我正在使用 Windows Installer 安装客户端,并且我有一个自定义安装操作来安装证书。

以下代码显示了如何将证书添加到存储中

Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ClientCertificates.MyRoot.cer");
byte[] buffer = new byte[((int)(manifestResourceStream.Length - 1L)) + 1];
manifestResourceStream.Read(buffer, 0, (int)manifestResourceStream.Length);
manifestResourceStream.Close();

var cert = new X509Certificate2(buffer);
var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();

/*
// The CRL is also needed, no idea why
manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ClientCertificates.MyRoot.crl");
buffer = new byte[((int)(manifestResourceStream.Length - 1L)) + 1];
manifestResourceStream.Read(buffer, 0, (int)manifestResourceStream.Length);
manifestResourceStream.Close();
cert = new X509Certificate2(buffer);
store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();
*/

// This is the key 
manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("ClientCertificates.MyTestServer.cer");
buffer = new byte[((int)(manifestResourceStream.Length - 1L)) + 1];
manifestResourceStream.Read(buffer, 0, (int)manifestResourceStream.Length);
manifestResourceStream.Close();

cert = new X509Certificate2(buffer);
store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();

我现在有两种行为: 安装证书有效,但是当我调用 Web 服务时,我得到一个 SecurityNegotiationException。 当我手动添加证书吊销列表时,与服务器的通信正常。 当我尝试以编程方式执行此操作时(请参见上面的代码),它不起作用。我收到“找不到请求的对象”异常。

我尝试使用不同的商店,但没有成功。

我有两个问题: a) 为什么我需要客户端上的 CRL? b)如果我需要它,如何以编程方式安装它?我上面的错误在哪里?

感谢您的帮助, 凯

【问题讨论】:

    标签: c# .net wcf wcf-security certificate-revocation


    【解决方案1】:

    通常,CRL 必须在线可用,并可从服务器证书中指定的撤销 URL 下载。我不知道是否有获取它的带外机制,但即使有,它也有点违背目的(允许客户端发现服务器证书已被泄露/撤销)。也就是说,对于自签名证书来说,CRL 确实是矫枉过正,除非您使用证书进行真正的相互身份验证并且您担心密钥被泄露(在这种情况下,购买商业证书并让他们处理) .

    如果您无法在没有撤销 URL 的情况下生成证书,我建议您完全禁用 CRL 的客户端检查,除非您确实需要它。您可以通过将以下内容添加到 Web 服务客户端的 app.config 来做到这一点:

      <system.net>
        <settings>
          <servicePointManager checkCertificateRevocationList="false"/>
        </settings>
      </system.net>
    

    如果您使用的是 WCF,则可能需要在 serviceCertificate->revocationMode:NoCheck 下将其与 clientCredentials endpointBehavior 连接起来。

    【讨论】:

      【解决方案2】:

      可在此处找到自动安装证书吊销列表的方法,包括通过 C# 代码:Programatically install Certificate Revocation List (CRL)

      【讨论】:

        【解决方案3】:

        我们必须仅使用 Win32 API 来执行此操作。没有一流的 C# 系统 API 可以做到这一点。

        public class CRLHandler
        {
            private const int CERT_STORE_PROV_SYSTEM = 10;
            private const int CERT_SYSTEM_STORE_LOCAL_MACHINE = (2 << 16);
        
            public const int X509_ASN_ENCODING = 0x00000001;
            public const int PKCS_7_ASN_ENCODING = 0x00010000;
        
            public const int CERT_STORE_ADD_REPLACE_EXISTING = 3;
        
            [DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)]
            public static extern IntPtr CertOpenStore(
              int storeProvider,
              int encodingType,
              IntPtr hcryptProv,
              int flags,
              string pvPara);
        
            [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern IntPtr CertCreateCRLContext(
                int dwCertEncodingType,
                byte[] pbCrlEncoded,
                int cbCrlEncoded);
        
            [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool CertAddCRLContextToStore(
              IntPtr hCertStore,
              IntPtr pCertContext,
              uint dwAddDisposition,
              IntPtr ppStoreContext);
        
            [DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            private static extern bool CertFreeCRLContext(
                IntPtr pCrlContext);
        
            public void AddOrUpdateCRLToStore(string crlString)
            {
                IntPtr crlContext = IntPtr.Zero;
                try
                {
                    byte[] rawData = Convert.FromBase64String(crlString);
        
                    IntPtr hLocalCertStore = CertOpenStore(
                          CERT_STORE_PROV_SYSTEM,
                          0,
                          IntPtr.Zero,
                          CERT_SYSTEM_STORE_LOCAL_MACHINE,
                          "CA");
        
                    crlContext = CertCreateCRLContext(
                        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                        rawData,
                        rawData.Length);
        
                    if (crlContext == IntPtr.Zero)
                    {
                        string error = "AddOrUpdateCRLToStore - CertCreateCRLContext error #" + Marshal.GetLastWin32Error();
                        throw new Exception(error);
                    }
        
                    bool crlAddResult = CertAddCRLContextToStore(
                        hLocalCertStore, crlContext, CERT_STORE_ADD_REPLACE_EXISTING, IntPtr.Zero);
        
                    if (!crlAddResult)
        
                    {
                        string error = "AddOrUpdateCRLToStore - CertAddCRLContextToStore #" + Marshal.GetLastWin32Error();
                        throw new Exception(error);
                    }
                }
                finally
                {
                    if(crlContext != IntPtr.Zero)
                    {
                        CertFreeCRLContext(crlContext);
                    }
                }
            }
        }
        

        AddOrUpdateCRLToStore 方法采用 base64 编码的 crl 字符串(不带头和尾),然后将 crl 导入本地计算机的 CA 存储。

        要修改本地机器等值,请将证书存储在此 API 中 refer this

        【讨论】:

          猜你喜欢
          • 2010-10-27
          • 2018-04-21
          • 2012-03-26
          • 2013-04-21
          • 1970-01-01
          • 2012-09-29
          • 2012-02-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多