【问题标题】:Programmatically communicating with a Certificate Authority以编程方式与证书颁发机构通信
【发布时间】:2011-12-11 02:01:29
【问题描述】:

我以编程方式处理证书并与证书颁发机构通信。我一直在 Windows 2008R2 上使用 C# 中的 CertClient 和 CertEnroll COM 对象。

我可以生成请求并从 CA 取回证书。我从这个例子开始: http://blogs.msdn.com/b/alejacma/archive/2008/09/05/how-to-create-a-certificate-request-with-certenroll-and-net-c.aspx

我有两个我无法弄清楚的问题。首先是,我怎样才能访问用于生成证书的私钥?作为 IX509PrivateKey 接口一部分的方法似乎不适用于我的测试环境。我给 CA 的请求与私钥不同,对吗?

第二个问题是我在申请证书时似乎无法提供注册代理证书。该 API 的旧版本使用了一个方法 SetSignerCertificate。我在新 API 中找不到等效项。

【问题讨论】:

  • 你曾经解决过你的问题吗?
  • @AndreidD - 不。在我发帖后不久,该要求就被取消了。不过,它可能有一天会再次出现......
  • 哦,好吧,谢谢,我希望我的要求也能被取消;)
  • @AndreiD - 如果您找到答案,请尽管提出。知道它仍然会有所帮助。以防万一。

标签: c# certificate-authority


【解决方案1】:

我给 CA 的请求与私钥不同,对吗?

您只需将公钥传递给 CA。

在请求证书时,我似乎无法提供注册代理证书。

您需要将 PKCS10 包装在 CMS/CMC 中。看看这里https://www.rfc-editor.org/rfc/rfc5272

【讨论】:

    【解决方案2】:

    在 MSDN 上的 Create Enroll on Behalf of Another User Request 下可以找到使用注册代理证书的示例。证书将安装到您指定的证书存储中,您可以像使用任何其他已安装证书一样使用私钥。

    完整示例:

    // Add references to CERTENROLL (CertEnroll 1.0 Type Library) 
    // and CERTCLILib (CertCli 1.0 Type Library)
    using CERTCLILib;
    using CERTENROLLLib;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Security.Cryptography.X509Certificates;
    using System.Text;
    using System.Threading.Tasks;
    using X509KeyUsageFlags = CERTENROLLLib.X509KeyUsageFlags;
    
    namespace TestSubmitEnrollment
    {
        class Program
        {
            static void Main(string[] args)
            {
                string requesterName = @"DOMAIN\otherUser";
                string caName = @"CA1.DOMAIN.LOCAL\DOMAIN-CA1-CA";
                string template = "User";
                // signerCertificate's private key must be accessible to this process
                var signerCertificate = FindCertificateByThumbprint("3f817d138f32a9a8df2aa6e43b8aed76eb93a932");
    
                // create a new private key for the certificate
                CX509PrivateKey privateKey = new CX509PrivateKey();
                // http://blogs.technet.com/b/pki/archive/2009/08/05/how-to-create-a-web-server-ssl-certificate-manually.aspx
                privateKey.ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
                privateKey.MachineContext = false;
                privateKey.Length = 2048;
                privateKey.KeySpec = X509KeySpec.XCN_AT_KEYEXCHANGE;
                privateKey.ExportPolicy = X509PrivateKeyExportFlags.XCN_NCRYPT_ALLOW_EXPORT_NONE;
                privateKey.Create();
    
                // PKCS 10 Request
                // we use v1 to avoid compat issues on w2k8
                IX509CertificateRequestPkcs10 req = (IX509CertificateRequestPkcs10)new CX509CertificateRequestPkcs10();
                req.InitializeFromPrivateKey(X509CertificateEnrollmentContext.ContextUser, privateKey, template);
    
                // PKCS 7 Wrapper
                var signer = new CSignerCertificate();
                signer.Initialize(false, X509PrivateKeyVerify.VerifyAllowUI, EncodingType.XCN_CRYPT_STRING_BASE64_ANY, 
                    Convert.ToBase64String(signerCertificate.GetRawCertData()));
    
                var wrapper = new CX509CertificateRequestPkcs7();
                wrapper.InitializeFromInnerRequest(req);
                wrapper.RequesterName = requesterName;
                wrapper.SignerCertificate = signer;
    
                // get CSR
                var enroll = new CX509Enrollment();
                enroll.InitializeFromRequest(wrapper);
                var csr = enroll.CreateRequest();
                //File.WriteAllText("csr.p7b", csr);
    
                // submit
                const int CR_IN_BASE64 = 1, CR_OUT_BASE64 = 1;
                const int CR_IN_PKCS7 = 0x300;
                ICertRequest2 liveCsr = new CCertRequest();
                var disposition = (RequestDisposition)liveCsr.Submit(CR_IN_BASE64 | CR_IN_PKCS7, csr, null, caName);
    
                if (disposition == RequestDisposition.CR_DISP_ISSUED)
                {
                    string resp = liveCsr.GetCertificate(CR_OUT_BASE64);
                    //File.WriteAllText("resp.cer", resp);
    
                    // install the response
                    var install = new CX509Enrollment();
                    install.Initialize(X509CertificateEnrollmentContext.ContextUser);
    
                    install.InstallResponse(InstallResponseRestrictionFlags.AllowUntrustedRoot,
                        resp, EncodingType.XCN_CRYPT_STRING_BASE64_ANY, null);
                }
                else
                {
                    Console.WriteLine("disp: " + disposition.ToString());
                }
                Console.WriteLine("done");
                Console.ReadLine();
            }
    
            private enum RequestDisposition
            {
                CR_DISP_INCOMPLETE = 0,
                CR_DISP_ERROR = 0x1,
                CR_DISP_DENIED = 0x2,
                CR_DISP_ISSUED = 0x3,
                CR_DISP_ISSUED_OUT_OF_BAND = 0x4,
                CR_DISP_UNDER_SUBMISSION = 0x5,
                CR_DISP_REVOKED = 0x6,
                CCP_DISP_INVALID_SERIALNBR = 0x7,
                CCP_DISP_CONFIG = 0x8,
                CCP_DISP_DB_FAILED = 0x9
            }
    
            private static X509Certificate2 FindCertificateByThumbprint(string sslCertThumbprint)
            {
                X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
                try
                {
                    store.Open(OpenFlags.ReadOnly);
    
                    var certs = store.Certificates.Find(X509FindType.FindByThumbprint, sslCertThumbprint, true);
                    if (certs.Count > 0)
                    {
                        return certs[0];
                    }
                    else
                    {
                        throw new KeyNotFoundException();
                    }
                }
                finally
                {
                    store.Close();
                }
            }
    
            // we re-declare this to account for backcompat to 2k8
            [ComImport, Guid("884E2042-217D-11DA-B2A4-000E7BBB2B09")]
            class CX509CertificateRequestPkcs10
            {
            }
        }
    }
    

    【讨论】:

    • 如果您不使用证书请求代理 cert,您仍然可以通过以下 2 个修改来使用此解决方案:首先,您不必创建“包装器”对象。其次,在调用 liveCsr.Submit() 时,在第一个参数中,省略 CR_IN_PKCS7 标志。很棒的示例项目!
    猜你喜欢
    • 2015-04-11
    • 1970-01-01
    • 2021-10-13
    • 2010-10-13
    • 1970-01-01
    • 2015-02-18
    • 2014-07-13
    • 2017-09-21
    • 2014-12-26
    相关资源
    最近更新 更多