代码之家  ›  专栏  ›  技术社区  ›  albertjan jakaria manik

在根目录中插入证书(带有私钥),LocalMachine证书存储在.NET4中失败

  •  17
  • albertjan jakaria manik  · 技术社区  · 14 年前

    在localmachine的根证书存储区中插入具有privatekey的新CA证书时遇到问题。

    事情就是这样:

    //This doesn't help either.
    new StorePermission (PermissionState.Unrestricted) { Flags = StorePermissionFlags.AddToStore }.Assert();
    var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
    privkey.PersistKeyInCsp = true;
    //This shouldn't be necessary doesn't make a difference what so ever.
    RSACryptoServiceProvider.UseMachineKeyStore = true;
    cert.PrivateKey = privkey;
    store.Open (OpenFlags.MaxAllowed);
    store.Add (cert);
    store.Close ();
    

    证书被插入,它看起来很漂亮:(看!) note it says it has a private key

    所以你会说一个人可以用 FindPrivateKey

    C:\Users\Administrator\Desktop>FindPrivateKey.exe Root LocalMachine -t "54 11 b1 f4 31 99 19 d3 5a f0 5f 01 95 fc aa 6f 71 12 13 eb"
    FindPrivateKey failed for the following reason:
    Unable to obtain private key file name
    
    Use /? option for help 
    

    证书导出对话框给了我一个非常好的信息: alt text

    click here

    我很想知道为什么?

    (在Windows Server 2008 R2和Windows 7上测试)

    我会被诅咒的!

    怎么办?

    6 回复  |  直到 7 年前
        1
  •  11
  •   albertjan jakaria manik    10 年前

    我遇到了完全相同的问题,解决方法非常简单。 我要做的就是通过考试

    X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
    

    X509Certificate2的ctor。 ).

    var cspParams = new CspParameters
    {
          KeyContainerName = Guid.NewGuid().ToString(),
          KeyNumber = (int)KeyNumber.Exchange,
          Flags = CspProviderFlags.UseMachineKeyStore
    };
    
    var rsaProvider = new RSACryptoServiceProvider(cspParams);
    

    我希望这有帮助。

        2
  •  10
  •   Oleg    14 年前

    http://support.microsoft.com/kb/950090

    此外,我发现保存私钥不好 UseMachineKeyStore

    如果您确实需要在机器密钥存储上保存私钥,那么您至少应该保护该密钥,以便只对某些选定的用户进行读取,而不是对所有人进行读取。密钥容器只是文件系统中的一个文件(请参阅目录“%ALLUSERSPROFILE%\Microsoft\Crypto\Keys”中的文件),它与NTFS中的其他文件一样具有安全描述符。更改可以使用的文件的安全描述符 CspKeyContainerInfo.CryptoKeySecurity 财产和 AddAccessRule , RemoveAccessRule 等等。

    更新 :首先很抱歉回答得太长。

    your program code 根证书.pfx 文件。在第二部分中,您导入证书,但使用 RSACryptoServiceProvider .

    根证书.pfx 就像书中描述的那样 . 效果很好。

    MakeCert.exe 来自Windows SDK的实用程序。你可以像下面这样做

    MakeCert.exe -pe -ss MY -a sha1 -cy authority -len 2048 -m 120 -r -# 1
                 -n "CN=Some Root CA, C=NL, OU=BleedingEdge, ST=Somewhere, L=Somelane"
    

    然后,您可以导出证书管理单元(例如)的带或不带私钥的证书mmc.exe文件). 在上面的例子中,我没有对一些特殊的EKU限制CA,所以您可以不受任何限制地使用它,但是如果您确实需要限制,您可以向它添加额外的参数 生成证书.exe

    在我看来,证书的创建实际上是代码的一个独立部分。你的主要问题在第二部分。

    • Root AuthRoot 在里面 localMachine 在组织的每台(或多台)计算机上,但您应该导入证书 . 你可以在以下方面做到这一点

    CertMgr.exe-添加-c约-s-r本地计算机AuthRoot

    • 您应该导入CA证书 在计算机上 仅适用于将颁发其他证书的用户 的证书存储 . 所以电脑上的代码看起来像

    以下内容:

    // import PFX
    X509Certificate2 cert = new X509Certificate2 (@"c:\Oleg\rootcert.pfx", "password",
        X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
    // save certificate and private key
    X509Store storeMy = new X509Store (StoreName.My, StoreLocation.CurrentUser);
    storeMy.Open (OpenFlags.ReadWrite);
    storeMy.Add (cert);
    
    // get certificate without private key
    // one can import certificate from rootcert.cer instead
    byte[] certBlobWithoutPrivateKey = cert.Export (X509ContentType.Cert);
    // save pure certificate in Root of the local machine
    X509Certificate2 certWithoutPrivateKey = new X509Certificate2 (certBlobWithoutPrivateKey);
    X509Store storeRoot = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
    storeRoot.Open (OpenFlags.ReadWrite);
    storeRoot.Add (certWithoutPrivateKey);
    

    StoreName.My StoreLocation.CurrentUser 但我不建议你这么做。

    一般来说,在.NET代码中导入证书看起来有点奇怪,并没有显示将在后台执行的操作。Windows只知道 Key Containers 其中私钥(确切地说是密钥对)将被保存在CSP和 Certificate Stores 保存证书的位置(请参阅 http://msdn.microsoft.com/en-us/library/bb204781.aspx 关于商店的位置)。为了能够在证书存储中保存有关密钥容器的信息,微软引入了这样的名称 Certificate Extended Properties . 如果在的.NET属性中使用 X509Certificate2 喜欢 Thumbprint FriendlyName , HasPrivateKey , Archived 授权根 设置 CERT_KEY_PROV_INFO_PROP_ID 再来一次 My 具有 证书密钥提供信息属性ID 不是永久的 . 所有这一切都对提高安全性很重要。

        4
  •  0
  •   Mumbles76    8 年前

        5
  •  0
  •   sravani    8 年前

    通常根目录中的证书没有私钥可管理。如果您在web请求中关联密钥,则应导入到“我的文件夹”。我有TLS/SSl异常,其中我有客户端证书链。如果您将所有证书链存储在我的存储中,那么我就消除了该异常。问题出在用户帐户上。用于存储证书的实用程序使用当前用户帐户,实际应用程序在系统帐户上运行。

        6
  •  0
  •   NitrusCS    7 年前

    使用机器存储 选项需要传递给 CSP提供程序标志 这反过来又会传递给 密码机密钥集 X509型keystrageFlags.PersistKeySet

    解决方案:在将证书导入个人计算机存储之前,将证书添加到受信任的根目录。 In reading the logs from CAPI2 <Flags value="20" CRYPT_MACHINE_KEYSET="true"/> 正在检查证书的有效性,并且返回一个被X509Certificate2吞噬的异常( I love how many empty catch blocks they have in that code )或者advapi32只是单方面决定不保留不受信任证书的密钥。(顺便说一句,我怀疑这是2008年到20012年间的行为变化,但我还没有证明这一点。)为了解决这个问题,我在代码中添加了一个If检查来添加证书,如果颁发者等于主题(它是一个自签名的证书),那么在将证书添加到我的证书之前,先将证书添加到根目录中。

        if (certificate.Issuer.Equals(certificate.Subject))
        {
            using (X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine)) { 
                store.Open(OpenFlags.ReadWrite);
                store.Add(certificate);
                store.Close();
            }
        }
    
        using (X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine)){ 
            store.Open(OpenFlags.ReadWrite);
            store.Add(certificate);
            store.Close();
        }
    

    注意:我发现如果使用的证书 已经有主题密钥标识符。不知何故,当您触发api以实际生成SKI而不是将其交给时,它会触发将magic CRYPT\u MACHINE\u KEYSET标志传递给advapi32的条件。