从pfx文件或证书存储中提取私钥,而无需在Windows上使用OpenSSL

8yparm6h  于 2023-05-08  发布在  Windows
关注(0)|答案(6)|浏览(255)

正如标题所示,我想在不使用OpenSSL或任何其他第三方工具的情况下导出我的私钥。如果我需要一个.cer文件或.pfx文件,我可以通过MMC或PowerShell pkiclient轻松导出这些文件,但我找不到获取私钥的方法。
https://learn.microsoft.com/en-us/powershell/module/pkiclient/export-certificate?view=win10-ps
使用像https://www.sslshopper.com/ssl-converter.html这样的在线工具是不行的。
PS版本:

PS C:\Users\oscar> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.17134.228
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17134.228
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

我可以像这样得到公钥:

(Get-PfxCertificate -FilePath C:\Users\oscar\Desktop\localhost.pfx).GetPublicKey()

并导出整个证书,如下所示:

(Get-PfxCertificate -FilePath C:\Users\oscar\Desktop\localhost.pfx).GetRawCertData()

结果来自

PS C:\Users\oscar> $mypwd = ConvertTo-SecureString -String "MyPassword" -Force -AsPlainText
PS C:\Users\oscar> $mypfx = Get-PfxData -FilePath C:\Users\oscar\Desktop\localhost.pfx -Password $mypwd
PS C:\Users\oscar> $mypfx

OtherCertificates EndEntityCertificates
----------------- ---------------------
{}                {[Subject]...

PS C:\Users\oscar> $mypfx.EndEntityCertificates

Thumbprint                                Subject
----------                                -------
8ED4971564E35099D6DB490C3756E2AD43AAAAAA  CN=localhost

测试了@Brad的命令,但我得到了下面的错误。
私钥不能纯文本导出

certutil -exportPFX -p "myPassword" -privatekey -user my <Certificate Serial Number> C:\localhost.pfx

与MMC证书中的证书导出向导类似,如果包含密钥,则仅可导出到.pfx

fquxozlt

fquxozlt1#

我也遇到了同样的问题,并在PS Gallery的PSPKI Powershell module的帮助下解决了它。虽然我理解你寻找一个解决方案,最好使用一些内置的功能在Windows中,安装一个模块从PS画廊可能是可以接受的。至少在我的情况下。
首先安装PSPKI模块(我假设已经设置了PSGallery存储库):

Install-Module -Name PSPKI

PSPKI模块提供了一个Cmdlet Convert-PfxToPem,它将pfx文件转换为pem文件,其中包含证书和pirvate密钥作为base64编码的文本:

Convert-PfxToPem -InputFile C:\path\to\pfx\file.pfx -Outputfile C:\path\to\pem\file.pem

现在,我们需要做的就是用一些正则表达式魔法分割pem文件。例如,像这样:

(Get-Content C:\path\to\pem\file.pem -Raw) -match "(?ms)(\s*((?<privatekey>-----BEGIN PRIVATE KEY-----.*?-
----END PRIVATE KEY-----)|(?<certificate>-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----))\s*){2}"

$Matches["privatekey"] | Set-Content "C:\path\to\key\file.pem"
$Matches["certificate"] | Set-Content "C:\path\to\certificate\file.pem"
aij0ehis

aij0ehis2#

我发现Panos.G's answer很有前途,但没有让它工作。所有三个描述的方法在我的证书对象上都不可用。经过进一步的挖掘,我得出了以下解决方案:

  • 注意:如果您从证书存储区读取证书,则可以正常工作。例如,如果您使用Get-PfxCertificate读入.pfx文件,则它不起作用。如果您只是将其作为文件,则可以将其安装在证书存储中,以便能够从那里读取它,如下所示。
# Read the certificate from the certificate store
# In this example, I use the certificate thumbprint to identify the certificate.
$cert = Get-ChildItem Cert:\ -Recurse | ? {$_.Thumbprint -eq '<THUMBPRINT_OF_CERTIFICATE>'}

# Read the private key into an RSA CNG object:
$RSACng = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)

# Get the bytes of the private key
$KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)

# Encode the bytes (Base64)
$KeyBase64 = [System.Convert]::ToBase64String($KeyBytes, [System.Base64FormattingOptions]::InsertLineBreaks)

# Put it all together
$KeyPem = @"
-----BEGIN PRIVATE KEY-----
$KeyBase64
-----END PRIVATE KEY-----
"@

文件:

qojgxg4l

qojgxg4l3#

根据PowerShellGuy提到的。
这样行吗?

# first get your cert, either via pure .NET, or through the PSDrive (Cert:\)

# this is just an example

# get cert from PSDrive
$cert = Get-ChildItem Cert:\LocalMachine\My | where Subject -eq 'CN=MySubject'

# get cert from .NET
$My     = [System.Security.Cryptography.X509Certificates.StoreName]::My
$Store  = [System.Security.Cryptography.X509Certificates.X509Store]::new($My,'localmachine')
$Store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::MaxAllowed)

$cert   = $Store.Certificates | where Subject -eq 'CN=MySubject'

# get private key
# PKCS8, way #1
$BytesPkcs8 = $cert.PrivateKey.ExportPkcs8PrivateKey()
[System.Convert]::ToBase64String($BytesPkcs8)

# PKCS8, way #2
$Pkcs = [System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob
$BytesPkcs8 = $cert.PrivateKey.Key.Export($Pkcs)
[System.Convert]::ToBase64String($BytesPkcs8)

# RSA
$BytesRsa = $cert.PrivateKey.ExportRSAPrivateKey()
[System.Convert]::ToBase64String($BytesRsa)

那么这个Base64字符串就是你要找的吗?

fzwojiic

fzwojiic4#

嗯。你试过打开证书存储库,并通过这种方式获得私钥吗?我很确定这只适用于RSA/DSA证书。

$store = New-Object System.Security.Cryptography.X509Certificates.X509Store([System.Security.Cryptography.X509Certificates.StoreName]::My,"localmachine")
$store.Open("MaxAllowed")
$cert = $store.Certificates | ?{$_.subject -match "^CN=asdasd"}
$cert.PrivateKey.ToXmlString($false)
$store.Close()
mqxuamgl

mqxuamgl5#

existing answer by stackprotector的基础上,我想添加一个片段,当直接从.pfx文件阅读时可以工作。
从文件阅读时,必须使用.net core中允许指定X509 StorageFlag Exportable的方法,而不是使用PowerShells Get-PfxCertificate

# Password is a plain string, not a securestring
$cert=New-Object System.Security.Cryptography.X509Certificates.X509Certificate2( 
      $filename, 
      $password, 
      [Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

# now continue as with the other solutions
# Read the private key into an RSA CNG object:
$RSACng = [Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)

# Get the bytes of the private key
$KeyBytes = $RSACng.Key.Export([Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)

# Encode the bytes (Base64)
$KeyBase64 = [Convert]::ToBase64String($KeyBytes, [Base64FormattingOptions]::InsertLineBreaks)

# Put it all together
$KeyPem = @"
-----BEGIN PRIVATE KEY-----
$KeyBase64
-----END PRIVATE KEY-----
"@
5gfr0r5j

5gfr0r5j6#

如果我理解正确的话,一定要为你做这件事。
certutil -exportPFX -p "ThePasswordToKeyonPFXFile" my [serialNumberOfCert] [fileNameOfPFx]

相关问题