Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate Self-signed certificate with Root CA Signer

Scenario: I am using PowerShell on Windows Server 2012r2 to generate a Root certificate and want to use that to sign a newly created Intermediate and Web certificate in dynamic generated (and destroyed) dev/test environments. The scripts are deployed remotely, and the intent is to keep it pure PowerShell if possible. In Windows 10/2016 this is relatively easy, after generating the Root certificate:

$Cert = New-SelfSignedCertificate -Signer $Root -Subject "CN=$Subject"

I've generated the Root certificate using COM X509Enrollment.CX509CertificateRequestCertificate and Security.Cryptography.X509Certificates.X509Certificate2 in a bastardized PS that I've had for some time, mainly because I needed to ensure that the Subject and Usage were set very specifically. I am not quite certain how to use this to sign the standard certificate without the above (which I have used before).

There are some examples using Bouncy Castle (see below) in C# that I could tie into PowerShell, but then I would need to deploy this additionally on the dynamic dev/test environments and I want to be able to do this in Powershell (via COM if needed) with the least dependencies.

  • C# Generate Self Signed Certificates on the Fly
  • How do I use Bouncy Castle in Powershell
like image 610
LimpingNinja Avatar asked May 16 '17 14:05

LimpingNinja


People also ask

Is a root CA cert self-signed?

Root certificates are self-signed (and it is possible for a certificate to have multiple trust paths, say if the certificate was issued by a root that was cross-signed) and form the basis of an X.

How do I create my own root CA?

Create your own root CA: Be a self trusted third-part and sign all self hosted SSL certificates, this will need one time maintenance in the browser certificate management to add root CA. All SSL certificates signed using our own root CA will be trusted by the browser by default.

How do I create a CA certificate in OpenSSL?

Create your root CA certificate using OpenSSL. Create the root key. Sign in to your computer where OpenSSL is installed and run the following command. This creates a password protected key. openssl ecparam -out contoso.key -name prime256v1 -genkey At the prompt, type a strong password.

Is it possible to create a self-signed certificate?

However, if you have a dev/test environment and don't want to purchase a verified CA signed certificate, you can create your own custom CA and create a self-signed certificate with it. Self-signed certificates are not trusted by default and they can be difficult to maintain. Also, they may use outdated hash and cipher suites that may not be strong.

Do I need a custom root CA for SSL certificates?

All SSL certificates signed using our own root CA will be trusted by the browser by default. The following is the network map of my home lab, as you can see I have way too many self hosted web tools, so maintaining these all in every browser is painful. This is where custom root CA comes handy.


1 Answers

The ultimate solution in my case, avoiding makecert and openssl was to use Powershell and BouncyCastle. I forked the PSBouncyCastle repo from PSBouncyCastle by RLipscombe and pushed 1.8.1 Bouncy Castle in. My forked version is the one I've used for the script, the fork resides at Forked: PSBouncyCastle.New.

I then used StackOverflow: C# Generate Certificates on the Fly as inspiration to write the following powershell below, I will be adding this to my GitHub and commenting, and I will amend this as soon as I do:

Import-Module -Name PSBouncyCastle.New

function New-SelfSignedCertificate {
  [CmdletBinding()]
  param (
    [string]$SubjectName,
    [string]$FriendlyName = "New Certificate",
    [object]$Issuer,
    [bool]$IsCA = $false,
    [int]$KeyStrength = 2048,
    [int]$ValidYears = 2,
    [hashtable]$EKU = @{}
  )

  # Needed generators
  $random = New-SecureRandom
  $certificateGenerator = New-CertificateGenerator

  if($Issuer -ne $null -and $Issuer.HasPrivateKey -eq $true)
  {
    $IssuerName = $Issuer.IssuerName.Name
    $IssuerPrivateKey = $Issuer.PrivateKey
  }
  # Create and set a random certificate serial number
  $serial = New-SerialNumber -Random $random
  $certificateGenerator.SetSerialNumber($serial)

  # The signature algorithm
  $certificateGenerator.SetSignatureAlgorithm('SHA256WithRSA')

  # Basic Constraints - certificate is allowed to be used as intermediate.
  # Powershell requires either a $null or reassignment or it will return this from the function
  $certificateGenerator = Add-BasicConstraints -isCertificateAuthority $IsCA -certificateGenerator $certificateGenerator

  # Key Usage
  if($EKU.Count -gt 0) 
  {
    $certificateGenerator = $certificateGenerator | Add-ExtendedKeyUsage @EKU
  }
  # Create and set the Issuer and Subject name
  $subjectDN = New-X509Name -Name ($SubjectName)
  if($Issuer -ne $null) {
    $IssuerDN = New-X509Name -Name ($IssuerName)
  }
  else 
  {
    $IssuerDN = New-X509Name -Name ($SubjectName)
  }  
  $certificateGenerator.SetSubjectDN($subjectDN)
  $certificateGenerator.SetIssuerDN($IssuerDN)

  # Authority Key and Subject Identifier
  if($Issuer -ne $null)
  {
    $IssuerKeyPair = ConvertTo-BouncyCastleKeyPair -PrivateKey $IssuerPrivateKey
    $IssuerSerial = [Org.BouncyCastle.Math.BigInteger]$Issuer.GetSerialNumber()
    $authorityKeyIdentifier = New-AuthorityKeyIdentifier -name $Issuer.IssuerName.Name -publicKey $IssuerKeyPair.Public -serialNumber $IssuerSerial
    $certificateGenerator = Add-AuthorityKeyIdentifier -certificateGenerator $certificateGenerator -authorityKeyIdentifier $authorityKeyIdentifier
  }

  # Validity range of the certificate
  [DateTime]$notBefore = (Get-Date).AddDays(-1)
  if($ValidYears -gt 0) {
    [DateTime]$notAfter = $notBefore.AddYears($ValidYears)
  }
  $certificateGenerator.SetNotBefore($notBefore)
  $certificateGenerator.SetNotAfter($notAfter)


  # Subject public key ~and private
  $subjectKeyPair = New-KeyPair -Strength $keyStrength -Random $random
  if($IssuerPrivateKey -ne $null)
  {
    $IssuerKeyPair = [Org.BouncyCastle.Security.DotNetUtilities]::GetKeyPair($IssuerPrivateKey)
  }
  else 
  {
    $IssuerKeyPair = $subjectKeyPair
  }
  $certificateGenerator.SetPublicKey($subjectKeyPair.Public)

  # Create the Certificate
  $IssuerKeyPair = $subjectKeyPair
  $certificate = $certificateGenerator.Generate($IssuerKeyPair.Private, $random)
  # At this point you have the certificate and need to convert it and export, I return the private key for signing the next cert
  $pfxCertificate = ConvertFrom-BouncyCastleCertificate -certificate $certificate -subjectKeyPair $subjectKeyPair -friendlyName $FriendlyName
  return $pfxCertificate
}

A few examples of usage for this powershell would be:

Generate a Root CA

$TestRootCA = New-SelfSignedCertificate -subjectName "CN=TestRootCA" -IsCA $true
Export-Certificate -Certificate $test -OutputFile "TestRootCA.pfx" -X509ContentType Pfx

Generate a Standard Self Signed

$TestSS = New-SelfSignedCertificate -subjectName "CN=TestLocal"
Export-Certificate -Certificate $TestSS -OutputFile "TestLocal.pfx" -X509ContentType Pfx

Generate a certificate, signing with a root certificate

$TestRootCA = New-SelfSignedCertificate -subjectName "CN=TestRootCA" -IsCA $true
$TestSigned = New-SelfSignedCertificate -subjectName "CN=TestSignedByRoot" -issuer $TestRootCA

Export-Certificate -Certificate $test -OutputFile "TestRootCA.pfx" -X509ContentType Pfx
Export-Certificate -Certificate $test -OutputFile "TestRootCA.pfx" -X509ContentType Pfx

Generate a Self-Signed with Specific Usage

$TestServerCert = New-SelfSignedCertificate -subjectName "CN=TestServerCert" -EKU @{ "ServerAuthentication" = $true }

Note that the -EKU parameter accepts via splatting, it does this to ensure that anything added to Add-ExtendedKeyUsage is validly passed. It accepts the following certificate usages:

  • DigitalSignature
  • NonRepudiation
  • KeyEncipherment
  • DataEncipherment
  • KeyAgreement
  • KeyCertSign
  • CrlSign
  • EncipherOnly
  • DecipherOnly

This fits my need and seems to work across all Windows Platforms we are using for dynamic environments.

like image 130
LimpingNinja Avatar answered Oct 09 '22 18:10

LimpingNinja