i use the following powershell script to generate self signed certificates on windows 2016 and above:
$cert = New-SelfSignedCertificate `
-Subject "CN=$env:COMPUTERNAME,OU=xx,O=xx,C=xx" `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-KeyExportPolicy Exportable `
-NotAfter (Get-Date).AddYears(3)
# export the certificate and dump to file
$CertBase64 = [System.Convert]::ToBase64String($cert.RawData, [System.Base64FormattingOptions]::InsertLineBreaks)
$Crt = @"
-----BEGIN CERTIFICATE-----
$CertBase64
-----END CERTIFICATE-----
"@
$Crt | Out-File -FilePath C:\cert.crt -Encoding Ascii
# export the private key and dump to file
$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
# clean keystore
$cert | Remove-Item
On windows 2012 R2 i have to change the New-SelfSignedCeriticate
command to:
$cert = New-SelfSignedCertificate `
-DnsName "$env:COMPUTERNAME" `
-CertStoreLocation cert:\LocalMachine\My
but when i run the $KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)
command i get this error:
PS C:\> $KeyBytes = $RSACng.Key.Export([System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateB
lob)
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
Any idea on why this command doens't work on windows 2012?
Thanks.
PS: I cannot use openssl or other third party tools.
EDIT 1
As requested in the comments, i'm attaching the output of the $cert.GetType()
and $RSACng.GetType()
commands:
PS C:\> $cert.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True X509Certificate2 System.Security.Cryptography.X509Certificates.X509Certifi...
PS C:\> $RSACng.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False RSACng System.Security.Cryptography.RSA
EDIT 2
I solved this the following script that should work on all windows versions above 2012.
if ([System.Environment]::OSVersion.Version -lt [Version]"10.0.14393.0") { # generate a self-signed certificate windows < 2016
$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 { # generate a self-signed certificate windows >= 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)
}
# export the certificate and dump to file
$CertBase64 = [System.Convert]::ToBase64String($cert.RawData, [System.Base64FormattingOptions]::InsertLineBreaks)
$Crt = @"
-----BEGIN CERTIFICATE-----
$CertBase64
-----END CERTIFICATE-----
"@
$Crt | Out-File -FilePath C:\abc.crt -Encoding Ascii
# export the private key and dump to file
$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
# clean keystore
$cert | Remove-Item