Windows Server 2012 R2自签名证书生成与PEM导出报错解决
兼容Windows Server 2012及以上版本的自签名证书生成与PEM导出脚本
问题场景
在Windows Server 2016及以上系统中,可通过以下PowerShell脚本生成自签名证书并导出为PEM格式:
$cert = New-SelfSignedCertificate ` -Subject "CN=$env:COMPUTERNAME,OU=xx,O=xx,C=xx" ` -KeyAlgorithm RSA ` -KeyLength 2048 ` -KeyExportPolicy Exportable ` -NotAfter (Get-Date).AddYears(3) # 导出证书到文件 $CertBase64 = [System.Convert]::ToBase64String($cert.RawData, [System.Base64FormattingOptions]::InsertLineBreaks) $Crt = @" -----BEGIN CERTIFICATE----- $CertBase64 -----END CERTIFICATE----- "@ $Crt | Out-File -FilePath C:\cert.crt -Encoding Ascii # 导出私钥到文件 $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) $Key = @" -----BEGIN PRIVATE KEY----- $KeyBase64 -----END PRIVATE KEY----- "@ $Key | Out-File -FilePath C:\cert.key -Encoding Ascii # 清理证书存储 $cert | Remove-Item
但在Windows Server 2012 R2环境中,需将New-SelfSignedCertificate命令修改为:
$cert = New-SelfSignedCertificate ` -DnsName "$env:COMPUTERNAME" ` -CertStoreLocation cert:\LocalMachine\My
执行导出私钥的命令时会触发如下错误:
PS C:\> $KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob) Exception calling "Export" with "1" argument(s): "The requested operation is not supported. " At line:1 char:1 + $KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]:: ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : CryptographicException
由于无法使用OpenSSL等第三方工具,通过分析$cert.GetType()和$RSACng.GetType()输出,编写了兼容Windows Server 2012及以上版本的解决脚本(已修正原脚本语法错误):
if ([System.Environment]::OSVersion.Version -lt [Version]"10.0.14393.0") { # 针对Windows Server 2012及以下版本生成自签名证书 $policies = [System.Security.Cryptography.CngExportPolicies]::AllowPlaintextExport,[System.Security.Cryptography.CngExportPolicies]::AllowExport $name = new-object -com "X509Enrollment.CX500DistinguishedName.1" $name.Encode("CN=$env:COMPUTERNAME,OU=xxxx,O=yyyy S.p.A.,C=IT", 0) $key = new-object -com "X509Enrollment.CX509PrivateKey.1" $key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider" $key.KeySpec = 1 $key.Length = 2048 $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)" $key.MachineContext = 1 $key.ExportPolicy = [System.Security.Cryptography.CngExportPolicies]::AllowPlaintextExport $key.Create() $serverauthoid = new-object -com "X509Enrollment.CObjectId.1" $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") $ekuoids = new-object -com "X509Enrollment.CObjectIds.1" $ekuoids.add($serverauthoid) $ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1" $ekuext.InitializeEncode($ekuoids) $cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1" $cert.InitializeFromPrivateKey(2, $key, "") $cert.Subject = $name $cert.Issuer = $cert.Subject $cert.NotBefore = get-date $cert.NotAfter = $cert.NotBefore.AddYears(10) $cert.X509Extensions.Add($ekuext) $cert.Encode() $enrollment = new-object -com "X509Enrollment.CX509Enrollment.1" $enrollment.InitializeFromRequest($cert) $certdata = $enrollment.CreateRequest(0) $enrollment.InstallResponse(2, $certdata, 0, "") $cert = Get-ChildItem Cert:\LocalMachine\My | where{$_.Subject -like "*xxxx*yyyy*"} } else { # 针对Windows Server 2016及以上版本生成自签名证书 $cert = New-SelfSignedCertificate -Subject "CN=$env:COMPUTERNAME,OU=xxxx,O=yyyy S.p.A.,C=IT" -KeyAlgorithm RSA -KeyLength 2048 -KeyExportPolicy Exportable -NotAfter (Get-Date).AddYears(10) } # 导出证书到文件 $CertBase64 = [System.Convert]::ToBase64String($cert.RawData, [System.Base64FormattingOptions]::InsertLineBreaks) $Crt = @" -----BEGIN CERTIFICATE----- $CertBase64 -----END CERTIFICATE----- "@ $Crt | Out-File -FilePath C:\abc.crt -Encoding Ascii # 导出私钥到文件 $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) $Key = @" -----BEGIN PRIVATE KEY----- $KeyBase64 -----END PRIVATE KEY----- "@ $Key | Out-File -FilePath C:\abc.key -Encoding Ascii # 清理证书存储 $cert | Remove-Item
内容的提问来源于stack exchange,提问作者vb8448
相关产品推荐
相关产品推荐

