Some time back I had cause to demonstrate the possibility of using Azure Automation in generating time limited certificates for use with Azure. It turned out to be more difficult than I thought as certificate creation on a local server or desktop uses the COM based CryptoAPI... which isnt available for use with Automation Runbooks.
This example script used the brilliant "Bouncy Castle" library for creating certificates.
The particular concept never progressed - but having some working code to reference (below) will be handy for anyone else also working with this idea. :)
<#
Module Name:
AzureCreateCert.psm1
Description:
Example
Version History
0.1 - 7 October 2017 Laurie Rhodes Demonstration Code
#>
<#
.Synopsis
Creates a Self Signed Certificate
.Description
Creates a Self Signed Certificate
.Example
New-RequestCertificate -RequestNumber 2435
.Inputs
[string]
.OutPuts
[string]
.Notes
NAME: New-RequestCertificate
AUTHOR: Laurie Rhodes
LASTEDIT: 24/06/2015
KEYWORDS:
.Link
Http://www.laurierhodes.info
#Requires -Version 2.0
#>
Function New-RequestCertificate
{
[CmdletBinding()]
param(
[string]$RequestNumber
) #end param
$datestart = [System.DateTime]::Parse("7/10/2017 11:00:00 PM",[System.Globalization.CultureInfo]::CurrentCulture, [System.Globalization.DateTimeStyles]::AssumeLocal)
$dateend = [System.DateTime]::Parse("7/10/2017 11:01:00 PM",[System.Globalization.CultureInfo]::CurrentCulture, [System.Globalization.DateTimeStyles]::AssumeLocal)
$ScriptDir = Split-Path $script:MyInvocation.MyCommand.Path
Add-Type -Path "$($ScriptDir)\BouncyCastle.Crypto.dll"
############## Generate Random Password for Cert
$Private:OFS = ""
$PasswordLength = 10
$InclChars = ‘abcdefghkmnprstuvwxyzABCDEFGHKLMNPRSTUVWXYZ123456789’
$RandomNums = 1..$PasswordLength | ForEach-Object { Get-Random -Maximum $InclChars.length }
$RandomPassowrd = [String]$InclChars[$RandomNums]
###############
$random = [Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator]::new()
$securerandom = [Org.BouncyCastle.Security.SecureRandom]::new($random)
$keygenparam = [Org.BouncyCastle.Crypto.KeyGenerationParameters]::new($securerandom,2048)
$keypairgen = new-object Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator
if ($random -ne $null) { write-debug " random created"} else {throw "random creation failed"; exit}
if ($securerandom -ne $null) { write-debug "securerandom created"} else {throw "securerandom creation failed"; exit}
if ($keygenparam -ne $null) { write-debug "keygenparam created"} else {throw "keygenparam creation failed"; exit}
$keypairgen = new-object Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator
$keypairgen.Init($keygenparam)
$certkeypair = $keypairgen.GenerateKeyPair()
$CertGenerator = [Org.BouncyCastle.X509.X509V3CertificateGenerator]::new()
$customrange = [Org.BouncyCastle.Utilities.BigIntegers]::CreateRandomInRange([Org.BouncyCastle.Math.BigInteger]::One , [Org.BouncyCastle.Math.BigInteger]::ValueOf([int64]::MaxValue), $securerandom )
$cn = new-object Org.BouncyCastle.Asn1.X509.X509Name("CN=TestCert" )
$issuer = new-object Org.BouncyCastle.Asn1.X509.X509Name("CN=TestFirm" )
$CertGenerator.SetSerialNumber($customrange)
$CertGenerator.SetIssuerDN($issuer)
$CertGenerator.SetNotBefore($datestart)
$CertGenerator.SetNotAfter($dateend)
$CertGenerator.SetSubjectDN($cn)
$CertGenerator.SetPublicKey($certkeypair.Public)
$CertGenerator.SetSignatureAlgorithm("SHA256withRSA")
$basconst = new-object Org.BouncyCastle.Asn1.X509.BasicConstraints($false)
$CertGenerator.AddExtension([Org.BouncyCastle.Asn1.X509.X509Extensions]::BasicConstraints, $true, $basconst )
$authident = new-object Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier( [Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory]::CreateSubjectPublicKeyInfo($certkeypair.Public) )
$CertGenerator.AddExtension([Org.BouncyCastle.Asn1.X509.X509Extensions]::AuthorityKeyIdentifier, $true, $authident )
[Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair]$issuerKeyPair = $certkeypair
[Org.BouncyCastle.Crypto.ISignatureFactory]$signatureFactory = [Org.BouncyCastle.Crypto.Operators.Asn1SignatureFactory]::new("SHA256withRSA", [Org.BouncyCastle.Crypto.AsymmetricKeyParameter]$issuerKeyPair.Private)
$cert = $CertGenerator.Generate($signatureFactory)
#########################
# RSA Private Key Import
# Cryptographic Service Provider properties
$cspParams = [System.Security.Cryptography.CspParameters]::new()
$cspParams.KeyContainerName = [guid]::NewGuid()
$cspParams.KeyNumber = 1
$cspParams.Flags = [System.Security.Cryptography.CspProviderFlags]::NoPrompt
$rsaProvider = [System.Security.Cryptography.RSACryptoServiceProvider]::new($cspParams)
$dotNetPrivateKey = [Org.BouncyCastle.Crypto.Parameters.RsaPrivateCrtKeyParameters]$issuerKeyPair.Private
$rsaParameters = new-object System.Security.Cryptography.RSAParameters
$rsaParameters.Modulus = ($issuerKeyPair.Private).Modulus.ToByteArrayUnsigned()
$rsaParameters.Exponent = ($issuerKeyPair.Private).PublicExponent.ToByteArrayUnsigned()
$rsaParameters.P = ($issuerKeyPair.Private).P.ToByteArrayUnsigned()
$rsaParameters.Q = ($issuerKeyPair.Private).Q.ToByteArrayUnsigned()
$rsaParameters.D = ($issuerKeyPair.Private).Exponent.ToByteArrayUnsigned()
$rsaParameters.DP = ($issuerKeyPair.Private).DP.ToByteArrayUnsigned()
$rsaParameters.DQ = ($issuerKeyPair.Private).DQ.ToByteArrayUnsigned()
$rsaParameters.InverseQ = ($issuerKeyPair.Private).QInv.ToByteArrayUnsigned()
$rsaProvider.ImportParameters($rsaParameters)
##################################
# Export X509 Cert
$x509cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new()
$x509cert.Import($cert.GetEncoded())
$x509cert.FriendlyName = "test certificate"
$x509cert.PrivateKey = [System.Security.Cryptography.AsymmetricAlgorithm]$rsaProvider
#create a pfx password
$Secure_String_Pwd = ConvertTo-SecureString $RandomPassowrd -AsPlainText -Force
#Export the certificate
$bytes = $x509cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx,$Secure_String_Pwd)
#Write the byte array to file
[system.convert]::ToBase64String($bytes) | Out-File "$($env:TEMP)\tempcert.pfx" -Force
write-output [system.convert]::ToBase64String($bytes)
}
- Log in to post comments