私钥在Windows Server 2008 R2中意外删除

4
我在开发一个安装程序时遇到了一个奇怪的问题,在其中一个步骤中必须安装一个证书,但问题是在 Windows Server 2008 R2 上授予证书私钥访问权限给某个帐户(例如 IIS_IUSRS)时出现了问题。私钥存储在位置 C:\Users\All Users\Microsoft\Crypto\RSA\MachineKeys 中。
一个自定义的 C# 安装项目导入证书并在安装过程中为某个帐户提供证书的私钥访问权限。在一些时间(2-3秒)后,私钥文件会自动从 MachineKeys 文件夹中删除。因此,已安装的 Web 应用程序无法访问特定的证书,并显示以下错误消息:“System.Security.Cryptography.CryptographicException: Keyset does not exist”。这个错误只出现在 Windows Server 2008 R2 上,而在 Windows Server 2003 上一切正常。
我的问题是:为什么会删除私钥以及是哪个进程执行了这个操作?
更新于 2012 年 5 月 17 日:我还没有找到解决这个问题的方法,也没有在我询问的其他论坛(forums.asp.net、social.msdn.microsoft.com)上得到任何回应。所以,有人能建议其他资源或进一步排除故障的建议吗?
谢谢。
3个回答

6
这也发生在我身上 - 我的设置脚本添加证书和PK文件访问权限时没问题,应用程序也能正常工作。但是,在关闭PowerShell编辑器后重新启动应用程序后,出现了密钥集未找到的错误。
在导入证书时添加PersistKeySet标志可以解决这个问题。以下是使用持久性添加证书和私钥的PowerShell代码:
param(
    [string]$certStore = "LocalMachine\TrustedPeople",
    [string]$filename = "sp.pfx",
    [string]$password = "password",
    [string]$username = "$Env:COMPUTERNAME\WebSiteUser"
)

    function getKeyUniqueName($cert) {
         return $cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
    }
    
    function getKeyFilePath($cert) {             
         return "$ENV:ProgramData\Microsoft\Crypto\RSA\MachineKeys\$(getKeyUniqueName($cert))"
    }

$certFromFile = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($filename, $password)
$certFromStore = Get-ChildItem "Cert:\$certStore" | Where-Object {$_.Thumbprint -eq $certFromFile.Thumbprint}
$certExistsInStore = $certFromStore.Count -gt 0
$keyExists = $certExistsInStore -and ($certFromStore.PrivateKey -ne $null) -and (getKeyUniqueName($cert) -ne $null) -and (Test-Path(getKeyFilePath($certFromStore)))

if ((!$certExistsInStore) -or (!$keyExists)) {

    $keyFlags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeySet 
    $keyFlags = $keyFlags -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet
    $certFromFile.Import($filename, $password, $keyFlags)

    $store = Get-Item "Cert:\$certStore"
    $store.Open("ReadWrite")

    if ($certExistsInStore) {
        #Cert is in the store, but we have no persisted private key
        #Remove it so we can add the one we just imported with the key file
        $store.Remove($certFromStore)
    }

    $store.Add($certFromFile)
    $store.Close()

    $certFromStore = $certFromFile
    "Installed x509 certificate"
}

$pkFile = Get-Item(getKeyFilePath($certFromStore))
$pkAcl = $pkFile.GetAccessControl("Access")
$readPermission = $username,"Read","Allow"
$readAccessRule = new-object System.Security.AccessControl.FileSystemAccessRule $readPermission
$pkAcl.AddAccessRule($readAccessRule)
Set-Acl $pkFile.FullName $pkAcl
"Granted read permission on private key to web user"

我也不知道为什么,但我们遇到了同样的问题。 同样的修复方法有效-添加PersistKeySet和MachineKeySet似乎是解决方法。 我们的情况是来自Chef进程内的PowerShell脚本块。 守卫脚本起作用了,但是减少了额外的参数,会损坏私钥从而使证书无法使用。 希望这能帮助其他人。 - No Refunds No Returns
谢谢!我进行了小的编辑,修复了$keyExists测试,当$cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName为空时,$keyExists评估为true而不是false。 - axk

1

很明显这是一个安全问题“System.Security.”,您没有权限进行安装。您需要设置私钥的权限以允许该服务帐户访问它

稍后编辑:转到开始->运行->cmd->键入mmc->选择文件->添加/删除->选择证书->添加->计算机帐户->本地。我附上了一张屏幕截图,虽然是西班牙语,但我指出了字段:

enter image description here

打开->证书->个人->证书->右键点击证书->所有任务->管理私钥->添加网络服务。

另外,请查看此 entry 以了解 Windows Server 2008 中此功能的使用方法,然后在尝试后请回来并告诉我您是否可以通过我告诉您的方法解决了问题。


感谢您的回答。然而,我的问题不是那个应该读取私钥(即IIS_IUSRS组)的进程没有足够的访问权限来这样做。相反,问题在于私钥根本就不存在。让我再次描述一下事件的系列:一个进程(Web应用程序的安装程序)创建了一些私钥,然后在C:\Users\All Users\Microsoft\Crypto\RSA\MachineKeys机器文件夹中创建了适当的文件,在一些秒钟之后(在安装程序进程被终止之前),这些文件会意外地被删除。 - dimdamop
1
我已经阅读了您的更新评论。让我再次澄清问题,因为我认为它还没有被理解:私钥已成功创建,并具有正确的访问权限。问题在于,在成功创建几秒钟后,这些私钥会被删除。我无法理解是什么程序删除了这些私钥。 - dimdamop

1

http://referencesource.microsoft.com/#System/security/system/security/cryptography/x509/x509certificate2collection.cs,256 显示了 PersistKeySet 标志的测试位置。PersistKeySet 标志在 https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509keystorageflags%28v=vs.110%29.aspx 中有文档说明,其中提到“导入证书时与 PFX 文件关联的密钥将被持久化。”我的技术术语翻译告诉我这意味着“如果您调用 X509Certificate2 构造函数并且证书可能已经安装在计算机上,则必须包括 PersistKeySet 标志。”这可能也适用于 .Import 调用。很可能 PowerShell 的 Import-PfxCertificate cmdlet 已经这样做了。但是,如果您正在执行所接受的答案或 OP 请求的操作,则需要包含特殊密钥。我们在解决方案中使用了 ejegg 的脚本变体。我们有一个每 3 分钟运行一次的进程来检查所有配置的证书是否已安装,现在似乎运行良好。

我们在PowerShell中看到的症状是HasPrivateKey属性为true,但PrivateKey值本身为null。而证书的密钥文件位于C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys中已被删除。FindPrivateKey实用程序帮助我们观察文件被删除的情况。
祝这个问题4岁生日快乐,虽然回复已经很晚了。

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