通过PowerShell创建PEM文件

问题描述 投票:0回答:6

我正在尝试编写一个脚本来在 powershell 中创建 PEM 证书文件。我不确定我所做的是否完全错误,但是当我尝试在 socat OPENSSL 中使用 PEM 文件时,它返回了错误:

$ socat OPENSSL-LISTEN:1337,cert=cert.pem,verify=0 -

socat[1209] E SSL_CTX_use_certificate_file(): error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag
#create certificate
$cert = New-SelfSignedCertificate `
    -Subject "MYHOSTNAME" `
    -TextExtension @("2.5.29.17={text}DNS=MYHOSTNAME&IPAddress=192.168.1.100") `
    -KeySpec Signature `
    -HashAlgorithm SHA256 `
    -KeyExportPolicy Exportable

#publicKey
$PublicKey = $cert.GetPublicKey();
$PublicKeyB64 = [Convert]::ToBase64String($PublicKey,"InsertLineBreaks");

#privateKey
$RSACng  = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert);
$PrivateKey = $RSACng.Key;
$PrivateKeyByte = $PrivateKey.Export("PRIVATEBLOB");
$PrivateKeyB64 = [Convert]::ToBase64String($PrivateKeyByte,"InsertLineBreaks");

#createFile
$out = New-Object string[] -ArgumentList 6;
$out[0] = "-----BEGIN PRIVATE KEY-----";
$out[1] = $PrivateKeyB64;
$out[2] = "-----END PRIVATE KEY-----"

$out[3] = "-----BEGIN CERTIFICATE-----"
$out[4] = $publicKeyB64;
$out[5] = "-----END CERTIFICATE-----"

[IO.File]::WriteAllLines("C:\Users\Public\cert.pem",$out)

我不确定我所做的是否完全错误,但我找不到任何资源来帮助我继续。

一些执行在 powershell 中创建 PEM 文件的类似操作的脚本或一些有关如何继续操作的提示可能对帮助我修复此问题很有价值。

certificate rsa powershell
6个回答
3
投票

你已经很接近了,这就是它的工作原理:

$cert = ...

# Public key to Base64
$CertBase64 = [System.Convert]::ToBase64String($cert.RawData, [System.Base64FormattingOptions]::InsertLineBreaks)

# Private key to Base64
$RSACng = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
$KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)
$KeyBase64 = [System.Convert]::ToBase64String($KeyBytes, [System.Base64FormattingOptions]::InsertLineBreaks)

# Put it all together
$Pem = @"
-----BEGIN PRIVATE KEY-----
$KeyBase64
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
$CertBase64
-----END CERTIFICATE-----
"@

# Output to file
$Pem | Out-File -FilePath cert.pem -Encoding Ascii

如果您想要

openssl pkcs12 -in cert.pfx -out cert.pem -nodes
的等效项(例如,包括整个证书链),请执行以下操作:

$cert = ...

# Collect certificates
$CertChain = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Chain
$CertChain.Build($cert)
$certs = $CertChain.ChainElements | ForEach-Object {$_.Certificate}
[System.Array]::Reverse($certs)

# Private key to Base64
$RSACng = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
$KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)
$KeyBase64 = [System.Convert]::ToBase64String($KeyBytes, [System.Base64FormattingOptions]::InsertLineBreaks)

# Put it all together
$Pem = @"
-----BEGIN PRIVATE KEY-----
$KeyBase64
-----END PRIVATE KEY-----
"@
foreach ($cert in $certs) {
    $Pem += @"

-----BEGIN CERTIFICATE-----
$([System.Convert]::ToBase64String($cert.RawData, [System.Base64FormattingOptions]::InsertLineBreaks))
-----END CERTIFICATE-----
"@
}

# Output to file
$Pem | Out-File -FilePath cert.pem -Encoding Ascii

3
投票

使用 stackprotector 的方法,我遇到了一些其他人无疑也会遇到的障碍:

  1. 您的目标证书必须是可导出的。是的,这应该是 显而易见,但如果您使用 PowerShell 创建证书,则 可能会错过它。如果您运行此操作的密钥不是 可导出,你会得到一个错误:

    不支持请求的操作。

    如果创建证书,请将

    -KeyExportPolicy Exportable
    添加到命令末尾。

  2. 如何设置

    $cert
    变量很重要。它不仅仅是一个字符串值。 使用
    get-item
    命令,您可以设置您想要的对象 想要合作。然后其他一切都会很顺利。

# Create a self-signed exportable certificate
New-SelfSignedCertificate -DnsName hostname.domain.com -KeyExportPolicy Exportable  

# Identify the cert to export with the script
$cert = get-item "cert:\localmachine\my\2F61C944634AA90A4AD7D1FE89BBEFAA3C0B6FDD"

# Public key to Base64
$CertBase64 = [System.Convert]::ToBase64String($cert.RawData, [System.Base64FormattingOptions]::InsertLineBreaks)

# Private key to Base64
$RSACng = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
$KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)
$KeyBase64 = [System.Convert]::ToBase64String($KeyBytes, [System.Base64FormattingOptions]::InsertLineBreaks)

# Put it all together
$Pem = @"
-----BEGIN PRIVATE KEY-----
$KeyBase64
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
$CertBase64
-----END CERTIFICATE-----
"@

# Output to file
$Pem | Out-File -FilePath cert.pem -Encoding Ascii

2
投票

正如评论所述,您放入两个 PEM 文件正文中的数据是错误的。

对于证书,很简单,只需使用

$cert.RawData
(转换为带有换行符的base64,就像您已经拥有的那样)。

对于私钥,根据文档,

RSA
返回的
GetRSAPrivateKey($cert)
摘要(not
.Key
)因此其像
RSACng
这样的实现具有方法
ExportPkcs8PrivateKey()
,这应该是正确的数据在
BEGIN/END PRIVATE KEY
类型的 PEM 文件以及
ExportRSAPrivateKey()
中,这应该是对于
BEGIN/END RSA PRIVATE KEY
类型的 PEM 文件正确的旧格式 - 但仅限于我没有的 Core 3.0+ 和 5因此无法测试。

如果您有

openssl
命令行,解决方法是将
Export-PfxCertificate
转换为文件,然后
openssl pkcs12 [-nodes]
可以将其转换为 OpenSSL(以及
socat
)喜欢的 PEM 格式。但是,如果您有
openssl
命令行,您可以轻松地使用它直接生成私钥和(自签名/虚拟)证书,而无需使用 powershell。


1
投票

您还可以使用 CertUtil.exe。 经历一次

Certutil.exe 是一个命令行程序,作为证书服务的一部分安装。

使用 powershell 创建 .PEM 的简单脚本如下:

 $certpwd = '***'
$certpwd1 = ConvertTo-SecureString -String $certpwd -Force –AsPlainText
$certpwd2 = 'pass:' + $certpwd
$certname = $env:COMPUTERNAME
del c:\temp\$certname.*

$cert = New-SelfSignedCertificate -DnsName $certname -certStorelocation cert:\localmachine\my -KeyLength 2048  -KeyFriendlyName $certname -FriendlyName $friendlyName -HashAlgorithm sha256 -keyexportpolicy exportableencrypted -keyspec KeyExchange -NotAfter (Get-Date).AddYears(2) | Out-Null

$cert2=Get-ChildItem Cert:\LocalMachine\my |
Where-Object { $_.FriendlyName -match $friendlyName }


$path = ‘cert:\localMachine\my\’ + $cert2.thumbprint
Export-Certificate -cert $path -FilePath c:\temp\$certname.der -type CERT –noclobber | Out-Null
certutil -encode c:\temp\$certname.der c:\temp\$certname.pem | Out-Null

脚本的作用是

1)首先它创建自签名证书

2)然后以.der的形式导出到某个物理路径

3)使用Certutil进行编码,从而创建.pem文件(本例中.pem将保存在c:emp\中)


0
投票

还值得注意的是,PemEncoding 类

[System.Security.Cryptography.PemEncoding]::Write("CERTIFICATE", $x509Certificate.GetPublicKey())

是你的朋友:)


-1
投票

我对之前的两个答案都遇到了麻烦。经过大量搜索和测试,我找到了一种适用于普通 powershell 和很少(没有?)权限的方法。

此脚本还提供 pfx、der 和 pem 文件形式的自签名证书。

$dir = "c:\temp\"

$subj = "CN=YOUR_SUBJECT" #need either DnsName or Subject when calling New-SelfSignedCertificate

$friendlyName = "YOUR_FRIENDLY_NAME"

$pfxFilePath = $dir, $friendlyName, ".pfx" -join ""

$derFilePath = $dir, $friendlyName, ".der" -join ""

$pemFilePath = $dir, $friendlyName, ".pem" -join ""

#create new certificate in cert:\currentuser\my and store in variable $cert
$cert = New-SelfSignedCertificate -CertStoreLocation cert:\currentuser\my -Subject $subj -KeyAlgorithm RSA -KeyLength 2048 -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" -KeyExportPolicy Exportable -FriendlyName $friendlyName -NotAfter (Get-Date).AddYears(2)

#get password for pfx file
$pw = Read-Host "Enter Password:"

#export cert to pfx and write to file 
[io.file]::WriteAllBytes($pfxFilePath,$cert.Export(3, $pw))

#export cert to der and write to file
Export-Certificate -FilePath $derFilePath -Cert $cert

#encode der file as pem file and write to file
certutil -encode $derFilePath $pemFilePath | Out-Null
© www.soinside.com 2019 - 2024. All rights reserved.