Как создать минимальный фиктивный X509Certificate2?
Я тестирую .NET-приложение; некоторые из модульных тестов включают программное генерирование объектов X509Certificate2.
Мне не важно, что я должен делать с подлинным ключом/приватным ключом/валидацией, я просто хотел бы иметь объект, который не бросает исключения, когда его поля проверяются. Я попытался использовать конструктор без параметров, но тогда целая куча полей генерирует исключения при доступе. Как видно в отладчике:
SubjectName = '(новый System.Collections.Generic.Mscorlib_CollectionDebugView (result.Certificates)). Items [0].SubjectName' выбрал исключение типа "System.Security.Cryptography.CryptographicException"
Я также пробовал передавать байтовый массив с некоторыми случайными числами в нем, но это даже не создавало (нужен ли массив конкретному размеру?)
Итак, вопрос: , что является самым простым (наименьшим количеством строк кода) способом программного генерации объекта X509Certificate2, который не будет генерировать исключения при доступе к полю/свойствам?
Ответы
Ответ 1
Я бы предложил следующее:
- Создайте сертификат, используя makecert.
- Добавьте сертификат в свой проект и измените его действие Build на встроенный ресурс.
- Загрузите сертификат из ресурса в настройке unit test, см. ниже.
код:
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");
На этом этапе вам должно быть хорошо дойти до взаимодействия с сертификатом. Вы можете создавать разные варианты, если ваши тестовые тесты имеют разные потребности.
Ответ 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
В запросе Langdon я использовал решение:
//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"?
"Moles - это облегченная структура тестовых заглушек и обходов в .NET, основанная на делегатах. Молы могут использоваться для обхода любого метода .NET, включая не виртуальные/статические методы в закрытых типах. Галерея Visual Studio или в комплекте с Pex."
http://research.microsoft.com/en-us/projects/moles/
Ответ 4
Есть еще один простой способ сделать это.
- Создайте сертификат с помощью MakeCert или экспортируйте любой существующий сертификат.
- Добавить сертификат в папку Project (папка 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");