从PFX文件中读取私钥

时间:2013-11-25 16:30:07

标签: c# private-key x509certificate2 pfx

我知道,有关于此的很多帖子,但我仍然无法找到解决方案来实现此功能。我在我的机器上生成了 PFX -file openssl ,如下所示:

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文件中读取)?

  3. StackTrace of Exception:

    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()
    

    更新

    我发现以下情况确实有效:

    // 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(...
    

    然而,对我来说,这只是一种解决方法,我想以更传统/标准的方式做到这一点!

5 个答案:

答案 0 :(得分:3)

也许您可以告诉我们更多关于您为什么要这样做的信息。当然有充分的理由想要这样做,例如编写一个程序,该程序将位于公司的内部服务器上,以自动化产品构建。

但是,如果您打算在高信任区域之外(例如向客户)分发此应用程序,那么答案是不要做!您永远不应该泄露您的私钥文件。这会打开你的密码暴力攻击(这肯定比私钥本身弱得多)。如果您分发您的应用程序,那么您的密码将包含在MSIL代码中的纯文本中。在那里,可以使用任何托管代码反汇编程序(例如Reflector)轻松查看,甚至可以使用文本或十六进制编辑器查看它。

总之,将您的私钥文件与您的应用程序一起分发给某人允许他们使用您的证书轻松签署他们想要的任何内容。私钥的重点是将其安全地锁定在除了您(或您的组织等)之外的任何人都无法访问的位置。

答案 1 :(得分: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();

当然,如果必须在机器上安装。

我认为这是解决这个问题的一个很好的解决方案,因为它为它添加了额外的安全层(应用程序必须在安装证书的机器上运行,并且作为安装它的用户,也是文件本身可以存放在其他地方的安全地方。)

答案 2 :(得分:2)

你必须加载这样的证书:

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

这篇文章解释了为什么http://paulstovell.com/blog/x509certificate2

答案 3 :(得分:1)

另一台机器上不存在默认密钥集(用户密钥集通常是默认密钥集),可能是因为它是一个asp.net应用程序(即它没有用户配置文件)。如果将X509KeyStorageFlags.MachineKeySet作为第三个参数传递给X509Certificate2构造函数,那么它应该在两台机器上以相同的方式工作。

仅在访问PrivateKey属性时才会发生这种情况的原因是它是创建实际CSP对象以使用密钥的第一个位置。

答案 4 :(得分:0)

您也可以通过以下方法获取私人。

System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = LoadCertificate("Certificate.pfx", "PasswordofCertificate");

RSACryptoServiceProvider key = certificate.PrivateKey as RSACryptoServiceProvider;

从证书变量中,您还可以获取其他信息,例如公钥等。