【问题标题】:How to create a minimal dummy X509Certificate2?如何创建一个最小的虚拟 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.

标签: c# x509certificate x509certificate2


【解决方案1】:

我建议如下:

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

代码:

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】:

还有一种更简单的方法。

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

代码:

        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");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多