通过代码访问时,私钥为空,为什么?

13

我在我的电脑上安装了一个证书,当我想查看它时,会看到消息“您有与此证书相对应的私钥”,但是当我在代码中尝试访问该私钥时,它是空的。我使用以下代码来获取我的证书:

var x509Certificate = GetCertificate(StoreName.My, StoreLocation.LocalMachine, "CN=SomeCert");

哪里:

public X509Certificate2 GetCertificate(string storeName, string storeLocation, string subjectName)
{
     var store = new X509Store(getStoreName(storeName), getStoreLocation(storeLocation));
     X509Certificate2Collection certificates = null;
     store.Open(OpenFlags.ReadOnly);

     try
     {
          X509Certificate2 result = null;
          certificates = store.Certificates;
          return getCertificateResult(certificates, subjectName, result);
     }
     finally
     {
          if (certificates != null)
          {
               foreach (var cert in certificates)
               {
                    cert.Reset();
               }
          }
          store.Close();
     }
}

并且:

private static X509Certificate2 getCertificateResult(IEnumerable certificates, string subjectName, X509Certificate2 result)
{
     foreach (var cert in certificates.Cast<X509Certificate2>().Where(cert => cert.SubjectName.Name != null && cert.SubjectName.Name.ToLower() == subjectName.ToLower()))
     {
          if (result != null)
          {
             throw new ApplicationException(string.Format("There is more than one certificate found for subject Name {0}", subjectName));
          }
          result = new X509Certificate2(cert);
     }

     if (result == null)
     {
          throw new ApplicationException(string.Format("No certificate was found for subject Name {0}", subjectName));
     }
     return result;
}

我成功地取回了我的证书,但是当我尝试访问私钥时,执行以下操作:

x509Certificate.PrivateKey

PrivateKey的值为null。我做错了什么?我需要这个值来签署SAML2请求。

注:我知道我的代码有些抽象,但我的意思是我已经检索到证书(它被找到了),但私钥却是null。如果还有任何阻止回答问题的抽象信息,请告诉我,我可以提供更多细节。


你的应用程序是否在你登录的用户下运行?可能是权限问题?虽然我认为这会抛出异常而不仅仅是返回空值。 - Richard Dalton
在“管理私钥”下,列出了应用程序池正在运行的用户,并具有完全控制权限。这是您所指的吗? - Brian David Berman
你确定你没有任何异常存在吗? - Stefan Rasmusson
没有任何异常被抛出,只是一个空的PrivateKey。 - Brian David Berman
3个回答

7

这里所述,.cer文件(我想它也适用于所有证书格式)不能包含私钥。从安全的角度来看,这是正确的,因为该文件是公开的。
但是,X509Certificate2不仅仅是一个证书,它还是证书本身和其他一些东西的容器。这就是为什么它有PrivateKey属性的原因。如果您需要在代码中使用此信息,并且如果您有一个私钥文件(.pvk)和密码,那么您可以使用.pfx文件代替.cer。可以使用pvk2pfx工具创建它:

> MakeCert -r -pe -ss SampleStoreName -n "CN=Sample" Sample.cer -sky exchange -sv Sample.pvk
> pvk2pfx -pvk Sample.pvk -pi SamplePassword -spc Sample.cer -pfx Sample.pfx -f

2
Reset文档指出它释放证书的资源。当然,由于该方法被称为Reset而不是Dispose,合理的假设是实例如果需要再次使用这些资源,则应能够重新获取这些资源。不幸的是,这并不是事实。

在GetCertificate的finally块中,您调用了集合中每个证书的Reset - 包括您返回的那个证书,这使其无用。


这显然不是事实。在getCertificateResult方法中,他明显创建了一个新的证书实例并返回它。因此,在返回时它将具有正确的详细信息。 - Imran Rashid

0

我知道这个问题已经很老了,但是对于未来的读者们,让我加上我的想法。

在我看来,你得到的证书似乎不包含私钥。所有存储中的证书都没有私钥。当然,你自己的证书会有私钥,但是其他实体的证书不会有私钥,这是有道理的。

在你的代码中,你没有显示从哪里获取证书的存储位置。难道你得到的证书不是你自己的证书之一吗?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接