Creating SSL Certificate with Custom CA
Tags: openssl, certificate, x509, selfsign
Published: 2021-07-04 05:15:51

---
title: Creating SSL Certificate with Custom CA
published: true
description: Creating custom root CA for internal use
tags: openssl, certificate, x509, selfsign
//cover_image: https://direct_url_to_image.jpg
---

## Creating Default OpenSSL Config File

{% gist https://gist.github.com/fakhrulhilal/70c80aa5331a92e0138f7c280b43fe11 %}

## Creating Custom Root CA

Creating the CA key:
`openssl genrsa -des3 -out root-CA.key 4096`
Note: remove `-des` option to create key without password

Creating self sign CA certificate

```powershell
openssl req -x509 -new -nodes -key root-CA.key -sha256 -days 3650 -out root-CA.crt `
	-subj "/C=ID/O=Dev lab/CN=Dev lab Root CA" `
	-addext 'keyUsage = cRLSign, keyCertSign, digitalSignature' `
	-addext 'extendedKeyUsage = critical, serverAuth, clientAuth, codeSigning, emailProtection, timeStamping' `
	-addext 'subjectKeyIdentifier=hash' `
	-addext 'authorityKeyIdentifier=keyid:always,issuer:always' `
	-addext "basicConstraints = critical, CA:TRUE"
```

Explanations:

- `subj`
  create unattended answer subject

- `basicConstraints`
  _CA:TRUE_ means it's issuer

- `keyUsage`
  determine what's this cert for: certificate signing (_keyCertSign_), CRL signing (_cRLSign_), digital signature

- `extendedKeyUsage`
  an extended version of `keyUsage`: server authentication (_serverAuth_), client authentication (_clientAuth_), file/code signing (_codeSigning_), S/MIME signing (_emailProtection_), time stamping

- `subjectKeyIdentifier`
  identifier of this cert

- `authoritykKeyIdentifier`

  the identifier which signs the cert, if it's root cert, then it should be itself

Shorter version

`openssl req -config openssl.cnf -x509 -new -nodes -key root-CA.key -out root-CA.crt -days 3650 -extensions ca_cert -subj "/C=ID/O=Dev Lab/CN=Dev Lab Root CA"`

Reference: [OpenSSL man page](https://www.openssl.org/docs/manmaster/man5/x509v3_config.html)

Inspect root CA certificate
`openssl x509 -noout -text -in root-CA.crt`

Convert into PKCS12 (.pfx) format
`openssl pkcs12 -export -name "Root CA" -out root-CA.pfx -inkey root-CA.key -in root-CA.crt`
Then import the pfx file into local machine placed under _Trusted Root Certification Authorities_

## Creating Intermediate CA

Creating the intermedia CA key
`openssl genrsa -out server-CA.key 4096`

Creating intermediate certificate request

`openssl req -new -key server-CA.key -out server-CA.csr -subj "/C=ID/O=Dev Lab/OU=Development/CN=Dev Lab Server CA"`

Sign the intermedia CA certificate's request with CA's key and cert:
`openssl x509 -extfile openssl.cnf -req -in server-CA.csr -CA root-CA.crt -CAkey root-CA.key -CAcreateserial -out server-CA.crt -extensions ica_cert -days 3650`

Inspect root CA certificate
`openssl x509 -noout -text -in server-CA.crt`

Convert into PKCS12 format
`openssl pkcs12 -export -name "Dev lab Server CA" -inkey server-CA.key -in server-CA.crt -out server-CA.pfx`
Then import the pfx file into local machine placed under _Intermediate Certification Authorities_

## Creating User Certificate

Creating the certificate key
`openssl genrsa -out dev.lab.key 2048`

Before moving on, the openssl config is configured to accept subject alternate name from environment variable named `SAN` (see line 176), so you need to configure first, otherwise, it will fail: `$Env:SAN = 'DNS:*.dev.lab, DNS:dev.lab'`. You can set it to the same as CN if you don't want to assign it to wilcard domain. We can also assign it to IP address as follows: `$Env:SAN = 'DNS:*.dev.lab,DNS:dev.lab,DNS:localhost,IP:127.0.0.1'`. After that, we can continue to create certificate request
```powershell
openssl req -new -key dev.lab.key -out dev.lab.csr -subj "/C=ID/ST=Jakarta/O=Dev Home/OU=Development/CN=*.dev.lab"
```

Sign the certificate request using server CA's key and certificate

```powershell
openssl x509 -extfile openssl.cnf -extensions web_cert -req -CA server-CA.crt `
	-CAkey server-CA.key -CAcreateserial -days 365 `
	-in dev.lab.csr -out dev.lab.crt
```

Convert into PKCS12 format
`openssl pkcs12 -export -name "dev.lab Certificate" -inkey dev.lab.key -in dev.lab.crt -out dev.lab.pfx`

Import the .pfx file into local machine using default location.

## Creating S/MIME Certificate

Creating the certificate key

`openssl genrsa -out iroel-email.key 2048`

Creating certificate request
`openssl req -new -key iroel-email.key -out iroel-email.csr -subj "/C=ID/ST=Jakarta/CN=Fakhrulhilal Maktum/emailAddress=iroel@dev.lab" -addext "subjectAltName = email:iroel@dev.lab, email:iroel@other.lab"`

Sign the certificate request using server CA's key and certificate

```powershell
$Env:SAN = 'email:iroel@dev.lab, email:iroel@dev.test'
openssl x509 -extfile openssl.cnf -extensions smime_cert -req -CA server-CA.crt `
	-CAkey server-CA.key -CAcreateserial -setalias "Dev email certificate" `
	-in iroel-email.csr -out iroel-email.crt -trustout -days 365
```

Convert into PKCS12 format
`openssl pkcs12 -export -name "wilcard.dev.lab Certificate" -inkey dev.lab.key -in dev.lab.crt -out dev.lab.pfx`

Import the .pfx file into local machine using default location.

## Installing Certificates

### Installing CAs' Certificate

1. Install root certificate (root-CA.crt) to *Trusted Root Certification Authorities* in machine level
2. Install intermediate certificate (server-CA.crt) to *Intermediate Certification Authorities*

### Install IIS Express Certificate

Install the certificate in Local Machine wide and in default location (Personal). Run this powershell with administrator privilege. Friendly name is `-name` parameter value when converting into PKCS12 format.

```powershell
$PfxPassword = 'pfx_password'
#$Certificate = Get-ChildItem Cert:\LocalMachine\My | ?{ $_.FriendlyName -eq 'localhost' }
$Certificate = Get-PfxCertificate -FilePath .\dev.lab.pfx -Password (ConvertTo-SecureString -String $PfxPassword -AsPlainText)
$IisExpress = Get-CimInstance Win32_Product -Filter 'Name like "IIS%Express%"'
for ($Port = 44300; $Port -lt 44400; $Port++) {
    netsh http delete sslcert ipport=0.0.0.0:$Port
    netsh http add sslcert ipport=0.0.0.0:$Port  certhash="$($Certificate.Thumbprint)"  appid="$($IisExpress.IdentifyingNumber)"
}
```

### Installing Kestrel Certificate

1. Using environment variable
   `ASPNETCORE_Kestrel__Certificates__Default__Path` = path to pfx file
   `ASPNETCORE_Kestrel__Certificates__Default__Password` = pfx's password

2. Using appsettings.json
```json
{
  "Kestrel": {
    "Certificates": {
      "Default": {
        "Path": "path/to/pfx/file",
        "Password": "pfx's password",
        /* or using .crt and key file */
        /*
        "Path": "path/to/crt/file",
        "KeyPath": "path/to/key/file"
        */
      }
    }
  }
}
```
Reference: [Configure endpoints for the ASP.NET Core Kestrel web server](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints)

3. Using dotnet tool: `dotnet dev-certs https --clean -i .\dev.lab.pfx -p the_password`

### Installing remote desktop certificate

```powershell
$PfxPassword = 'pfx_password'
#$Certificate = Get-ChildItem Cert:\LocalMachine\My | ?{ $_.FriendlyName -eq 'localhost' }
$Certificate = Get-PfxCertificate -FilePath .\dev.lab.pfx -Password (ConvertTo-SecureString -String $PfxPassword -AsPlainText)
wmic /namespace:\\root\cimv2\TerminalServices PATH Win32_TSGeneralSetting Set SSLCertificateSHA1Hash="$($Certificate.Thumbprint)"
````