通过PowerShell创建PEM文件



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

$ 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:UsersPubliccert.pem",$out)

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

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

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

对于证书,这很容易,只需使用$cert.RawData(转换为带有换行符的base64,就像您已经拥有的那样)。

对于私钥,根据文档,GetRSAPrivateKey($cert)(不是.Key)返回的RSA摘要,因此它的实现(如RSACng)具有方法ExportPkcs8PrivateKey()这些方法应该是放入类型为BEGIN/END PRIVATE KEY的PEM文件中的正确数据,并且ExportRSAPrivateKey()应该是对BEGIN/END RSA PRIVATE KEY类型的PEM文件正确的旧格式 - 但仅在Core 3.0+和Five中,我没有,因此无法测试。

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

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

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

如此简单的脚本用于创建.带电源外壳的 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:localmachinemy -KeyLength 2048  -KeyFriendlyName $certname -FriendlyName $friendlyName -HashAlgorithm sha256 -keyexportpolicy exportableencrypted -keyspec KeyExchange -NotAfter (Get-Date).AddYears(2) | Out-Null
$cert2=Get-ChildItem Cert:LocalMachinemy |
Where-Object { $_.FriendlyName -match $friendlyName }

$path = ‘cert:localMachinemy’ + $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:\temp\中)

你很接近,这就是它的工作方式:

$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

使用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:localmachinemy2F61C944634AA90A4AD7D1FE89BBEFAA3C0B6FDD"
# 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

我对前面的两个答案都遇到了麻烦。经过大量的搜索和测试,我找到了一种适用于普通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:currentusermy and store in variable $cert
$cert = New-SelfSignedCertificate -CertStoreLocation cert:currentusermy -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

最新更新