2013-11-25 9 views
4

Я знаю, есть много сообщений об этом, но все же я не могу найти решение, чтобы заставить его работать. Я произвел PFX -файл с OpenSSL на моей машине, как это:Прочтите закрытый ключ из PFX-файла

openssl x509 -req -days 365 -in "myReqest.csr" -signkey "myPrivateKey.pem" -out "myCertificate.crt" 
openssl pkcs12 -export -out "myCertificate.pfx" -inkey "myPrivateKey.pem" -in "myCertificate.crt" -certfile "myCertificate.crt" 

В моей C# приложение, получить доступ к закрытому ключу так:

var cert = new X509Certificate2("myCertificate.pfx", "myPassword"); 
cert.HasPrivateKey; // This is always true! 
cert.PrivateKey; // Works on my machine (only) 

Это работает прекрасно (на мой машина), но когда я запускаю тот же код на другой машина, она выбрасывает: «Набор ключей не найден», хотя HasPrivateKey возвращает true! Не следует ли включать закрытый ключ в файл * .pfx? Можете ли вы сказать мне:

  1. Был сертификат/закрытый ключ как-то автоматически устанавливается на моей машине OpenSSL когда я его создал?

  2. Как я могу прочитать закрытый ключ из * .PFX-файла (или, альтернативно, из файла * .PEM)?

StackTrace исключения:

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContaier) 
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContaier, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle) 
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair() 
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize) 
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(CspParameters parameter) 
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey() 

Update:

Я узнал, что следующая работа делает:

// on my machine 
// read certificate from file (exportable!) 
X509Certificate2 cert = new X509Certificate2("filename.pfx", "password", X509KeyStorageFlags.Exportable) 
// sign data etc. 
((RSACryptoServiceProvider)cert.PrivateKey).SignData(... 
// export private key to XML-file 
File.WriteAllText("filename.xml", cert.PrivateKey.ToXmlString(true)); 

// on the other machine 
// create new RSA object 
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
// import private key from xml 
rsa.FromXmlString(File.ReadAllText("filename.xml")); 
// verify data etc. 
rsa.VerifyData(... 

Однако, чтобы я, это только обходной путь, я хотел бы сделать это более обычным/стандартным способом!

+0

Wild догадка: это * частный * ключ, сгенерированный на * ваш * машина, поэтому * ваш * машина может использовать его (я злоупотреблял курсивом для выделения) – Alex

+0

Вы также управляете командами openssl на другой машине? (все, что вы упомянули, было «кодом»). –

+0

@Alex Это не очень полезно. Я думал, что закрытый ключ должен быть включен в файл сертификата, так как он находился в отдельном файле, который я создал заранее, и который я включил явно при создании сертификата с помощью openssl. – marsze

ответ

2

Кажется, в .NET нет прямого способа сделать это. Поэтому я решил теперь загрузить сертификат непосредственно из хранилища сертификатов:

X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); 
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly); 
X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, CERTIFICATE_THUMB_PRINT, false); 
if (certificates.Count == 0) 
{ 
    // "Certificate not installed." 
} 
else 
{ 
    certificate = certificates[0]; 
} 
store.Close(); 

Для этого, конечно же, если должен быть установлен на компьютере.

Я думаю, что это хорошее решение этой проблемы, поскольку оно добавляет к нему дополнительный уровень безопасности (приложение должно быть запущено на компьютере, на котором установлен сертификат, и как пользователь, который его установил, также сам файл можно сохранить в безопасном месте где-то в другом месте).

+0

Как вы можете извлечь секретный ключ? – NickG

+0

@NickG 'certificate.PrivateKey' должен работать, я думаю. Обратите внимание, что при таком подходе закрытый ключ обрабатывается хранилищем сертификатов Windows. – marsze

1

Набор ключей по умолчанию на другом компьютере не существует (набор пользовательских ключей обычно по умолчанию), вероятно, потому, что это приложение asp.net (то есть оно не имеет профиля пользователя). Если вы передадите X509KeyStorageFlags.MachineKeySet в качестве третьего аргумента в конструктор X509Certificate2, то он должен работать одинаково на обеих машинах.

Причина, по которой это происходит только при доступе к свойству PrivateKey, заключается в том, что это первое место, где создается фактический объект CSP для использования ключа.

+0

Это не помогло. Кроме того, это не приложение ASP.NET. – marsze

+0

Возможно, X509KeyStorageFlags.Exportable работает? Исключение явно указывает на проблему с набором ключей. Вы также можете комбинировать Exportable с MachineKeySet или UserKeySet. –

+0

Я не пробовал все это. Проблема, похоже, совершенно другая. – marsze

3

Возможно, вы можете рассказать нам немного больше о том, почему вы хотите это сделать. Разумеется, есть веские причины для этого, например, написать программу, которая будет размещаться на внутреннем сервере вашей компании для автоматизации сборки продукта.

Но если вы намерены распространять это приложение за пределами зоны высокого доверия (например, для клиентов), тогда ответ НЕ ДЕЛАЙТЕ ЭТО! Вы никогда не должны выдавать свой файл секретного ключа. Это открывает его для атаки грубой силы вашего пароля (что, безусловно, намного слабее самого частного ключа). И если вы распространяете свое приложение, то ваш пароль будет включен в простой текст в код MSIL. Там его можно легко просмотреть с помощью любого дизассемблера управляемого кода (например, Reflector), и его можно, вероятно, даже просмотреть с помощью текстового или шестнадцатеричного редактора.

Таким образом, раздача файла личного ключа вместе с вашим приложением для кого-то позволяет им легко подписать все, что они хотят, с помощью ВАШЕГО сертификата. Весь секретный ключ состоит в том, чтобы сохранить его безопасно запертым в том месте, где он никогда не будет доступен никому, кроме вас (или вашей организации и т. Д.).

+0

'такой как написание программы, которая будет сидеть на внутреннем сервере вашей компании для автоматизации сборки продукта' ... у вас это есть, не более того, чтобы сказать здесь. Другие вещи, о которых вы упомянули, я уже знаю. Однако, как вы можете видеть из моего ответа, я нашел лучшее решение. – marsze

1

Вы должны загрузить сертификат, как это:

X509Certificate2 cert = new X509Certificate2("a.pfx", "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet)

Это сообщение объясняет, почему http://paulstovell.com/blog/x509certificate2

Смежные вопросы