如何创建一个最小的虚拟 X509Certificate2?

Posted

技术标签:

【中文标题】如何创建一个最小的虚拟 X509Certificate2?【英文标题】:How to create a minimal dummy X509Certificate2? 【发布时间】:2011-10-13 18:07:48 【问题描述】:

我正在对 .NET 应用程序进行单元测试;一些单元测试涉及以编程方式生成 X509Certificate2 对象。

我不关心实际的签名/私钥/验证内容,我只想拥有一个在检查其字段时不会引发异常的对象。我尝试使用无参数构造函数,但随后一大堆字段在访问时抛出异常。在调试器中可以看到:

SubjectName = '(new System.Collections.Generic.Mscorlib_CollectionDebugView(result.Certificates)).Items[0].SubjectName' 引发了“System.Security.Cryptography.CryptographicException”类型的异常

我也尝试传递一个包含一些随机数的字节数组,但它甚至没有构造(数组是否需要特定大小?)

那么,问题:以编程方式生成不会在字段/属性访问时引发异常的 X509Certificate2 对象的最简单(最少的代码行)方法是什么?

【问题讨论】:

什么是痣?您能否提供最终解决方案作为答案?我现在正在尝试做同样的事情。 我认为他的意思是一个用于创建测试存根的框架和 Microsoft 研究中的弯路。你可以看这里:research.microsoft.com/en-us/projects/moles. 【参考方案1】:

我建议如下:

    使用makecert 生成证书。 将证书添加到您的项目并将其构建操作更改为嵌入式资源。 从单元测试设置中的资源加载证书,见下文。

代码:

byte[] embeddedCert;
Assembly thisAssembly = Assembly.GetAssembly(typeof(MyType));
using (Stream certStream = thisAssembly.GetManifestResourceStream("YourProjectName.localhost.pfx"))

  embeddedCert = new byte[certStream.Length];
  certStream.Read(embeddedCert, 0, (int)certStream.Length);


_signingCert = new X509Certificate2(embeddedCert, "password");

此时,您应该可以与证书进行交互了。如果您的单元测试有不同的需求,您可以创建不同的变体。

【讨论】:

我想我实际上可以读取该字节数组一次,将其作为字符打印到文件中,然后将其作为硬拷贝粘贴到源代码中编码字节[]?那不会太糟糕... @JasonShantz 我不明白为什么问这个问题的人将您的答案标记为“已回答”而没有解释什么是“MyType”??? @anhtv13 我相信 MyType 是项目中包含自签名证书作为嵌入式资源的 C# 类/类型的占位符。这允许对程序集的引用,这反过来又允许将资源作为流读取到 embeddedCert 字节数组中。一旦你有了这个字节数组,你就可以为 X509Certificate2 msdn.microsoft.com/en-us/library/ms148413(v=vs.110).aspx 使用适当的构造函数 在这方面,MyType 是与资​​源在同一个项目中的任意对象,如果您将证书保存在同一个项目中,它可能是 UnitTest 类本身。 注意:“YourProjectName”应该是命名空间(以防项目名称和命名空间不同)。使用 thisAssembly.GetManifestResourceNames() 进行检查。【参考方案2】:

这可能看起来很老套,这取决于你想变得多么务实……我使用的一种方法是从机器上随机获取一个证书。

这在以下情况下很好: - 我知道每台运行这些测试的机器都有一个有效的证书。 - 我正在使用 GIT,不想签入证书的二进制文件 - 我不在乎证书内容 - 我使用的代码不是模拟友好的,并且明确需要一个不可模拟的 X509Certificate 对象。

绝对不是防弹的,而是解除了对我的阻止并解除了对我的测试场景的阻止。

    static X509Certificate2 GetRandomCertificate()
    
        X509Store st = new X509Store(StoreName.My, StoreLocation.LocalMachine);
        st.Open(OpenFlags.ReadOnly);
        try
        
            var certCollection = st.Certificates;

            if (certCollection.Count == 0)
            
                return null;
            
            return certCollection[0];
        
        finally
        
            st.Close();
        
    

【讨论】:

这非常适合测试。顺便说一句,我们必须提防密码吗?【参考方案3】:

应兰登的要求,我自己使用的解决方案:

        //Moling test Certificate
        var cert = new MX509Certificate2();
        var subject = new MX500DistinguishedName();
        // hookup
        cert.SubjectNameGet = () => subject;
        cert.ThumbprintGet = () => "foo";
        subject.NameGet = () => "foobar";

这很有效,因为我在证书中访问的唯一字段是 SubjectName 和 Thumbprint,而我访问的 SubjectName 的唯一字段是名称。我“模拟”了这些字段的 getter 方法以返回虚拟字符串。如果您要访问其他字段,您可能需要将它们调入。

那么,什么是“痣”?

“Moles 是 .NET 中基于委托的测试存根和绕行的轻量级框架。Moles 可用于绕行任何 .NET 方法,包括密封类型中的非虚拟/静态方法。Moles 可在Visual Studio 库或与 Pex 捆绑在一起。”

http://research.microsoft.com/en-us/projects/moles/

【讨论】:

接受 Jason 的回答胜过我的回答,因为他的回答更笼统。【参考方案4】:

还有一种更简单的方法。

    使用 MakeCert 创建证书或导出任何现有证书。 在项目(App_Data 文件夹)中添加证书。 按照以下步骤获取证书。

代码:

        string certificate = "cert.pfx";
        string certPath = string.Format("0/App_Data/1", HttpRuntime.AppDomainAppPath, certificate);
        byte[] bytes = Util.FileToArray(certPath);
        X509Certificate2 publicKey = new X509Certificate2(bytes, "somepassoword");

【讨论】:

以上是关于如何创建一个最小的虚拟 X509Certificate2?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建一个自签名的SSL证书(X509)

[转]如何创建一个自签名的SSL证书(X509)

如何以编程方式创建有效的自签名 X509Certificate2,而不是从 .NET Core 中的文件加载

通过签署 CSR 创建 x509 v3 用户证书

如何配置 WCF 以通过 Internet 使用 x509 证书?

使用 OpenSSL 以编程方式创建 X509 证书