我正在测试.NET应用程序;一些单元测试涉及以编程方式生成X509Certificate2对象。
我不关心实际的签名/私钥/验证内容,我只想拥有一个在检查字段时不会抛出异常的对象。我尝试使用无参数构造函数,但是当访问时,一大堆字段会抛出异常。如调试器中所示:
SubjectName ='(new System.Collections.Generic.Mscorlib_CollectionDebugView(result.Certificates))。Items [0] .SubjectName'抛出类型为'System.Security.Cryptography.CryptographicException'的异常
我也试过传递一个包含一些随机数的字节数组,但是甚至没有构造(数组是否需要特定的大小?)
那么,问题:以编程方式生成X509Certificate2对象的最简单(最少代码行)的方法是什么?这个对象在字段/属性访问时不会抛出异常?
答案 0 :(得分:9)
我建议如下:
代码:
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");
此时,您应该善于与证书进行交互。如果您的单元测试有不同的需求,您可以创建不同的变体。
答案 1 :(得分:3)
这可能看起来非常hacky,这取决于你想要的实用程度......我使用的方法是从机器中获取随机证书。
这在以下情况下很好: - 我知道运行这些测试的每台机器都有一个有效的证书。 - 我正在使用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();
}
}
答案 2 :(得分:1)
在兰登的要求下,我使用的解决方案,我自己:
//Moling test Certificate
var cert = new MX509Certificate2();
var subject = new MX500DistinguishedName();
// hookup
cert.SubjectNameGet = () => subject;
cert.ThumbprintGet = () => "foo";
subject.NameGet = () => "foobar";
这是有效的,因为我在证书中访问的唯一字段是它的SubjectName和Thumbprint,我访问的SubjectName的唯一字段是名称。我“moled”这些字段的getter方法返回虚拟字符串。如果你要访问其他领域,你可能需要将它们分解为。
那么,什么是“摩尔人”?
“Moles是.NET中基于委托的测试存根和绕道的轻量级框架。可以使用Moles来绕过任何.NET方法,包括密封类型中的非虚拟/静态方法.Moles是免费提供的Visual Studio Gallery或与Pex捆绑在一起。“
答案 3 :(得分:0)
还有一种更简单的方法。
代码:
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");