The LAB (Public Key Infrastructure)

This is taking a bit more time than anticipated, but rather spend the time now and learn along the way on some gotchas than doing it quick and dirty. If you’re interested in how to setup a lot of stuff automatically (which I recommend), please check out the blog of the true Chief Automation Officer Trond Eirik Haavarstein.

So up for the next part of my LAB. As you’re all aware, security is a hot topic these days so I need to take care of my certificates. As this is a LAB environment -reflecting work that you need to take care of in any production environment-, I will setup an internal Public Key Infrastructure (PKI) so I can issue certificates for my internal addresses.

I learned the hard way this setup needs to be done very carefully otherwise it will not work. So take your time and ensure you can stay focused when setting this up.

I will deploy a two-tier PKI hierarchy consisting of a (offline) root Certificate Authority (CA) and an enterprise Issuing CA based on Windows Active Directory Certificate Services (AD CS) as this is the most used model within Enterprises. So I will not bother you with setting up the VM’s itself, but I’ve created 2 new VM’s (based on the Windows Server template) where the first -NLSOMCA01- is not connected to any network or Active Directory and the second -NLSOMCA02- is just brought up as a member server in my AD.

NLSOMCA01 – Root Certificate Authority Server

Ok, I will start with installing the AD CS via Powershell.

Add-WindowsFeature ADCS-Cert-Authority -IncludeManagementTools

The error shown is because this machine doesn’t have any network connection, so it cannot update any component.

After the feature has been added, I can install the Root CA. For this I could use the default install command, but as this LAB is for to learn new “stuff”, I will use some of the available parameters to construct the installation. command.

-CACommonNameSpecifies the CA common name
LAB Damen Root CA
-CATypeSpecifies the type of CA to be installed
-CryptoProviderNameSpecifies the name of the cryptographic service provider that is used to store the private key
RSA#Microsoft Software Key Storage Provider
-HashAlgorithmNameSpecifies the signature hash algorithm
-KeyLengthSpecifies the bit length of the CA key
-ValidityPeriodSpecifies the validly period of the CA in hours, days, weeks, months or years
-ValidatyPeriodUnitsSpecifies the validity period of the CA certificate
-DatabaseDirectorySpecifies the folder location of the CA database log
(REQUIRED if you don’t have a network)
$(Join-Path $env:SystemRoot “System32\CertLog”)
Install-AdcsCertificationAuthority -CaCommonName "LAB Damen Root CA" -CAType StandaloneRootCA -CryptoProviderName "RSA#Microsoft Software Key Storage Provider" -HashAlgorithmName SHA256 -KeyLength 2048 -ValidityPeriod Years -ValidityPeriodUnits 10 -DatabaseDirectory $(Join-Path $env:SystemRoot "System32\CertLog")

So my Root CA has been installed, now the configuration. We need to configure a couple of things:

  • Authority Information Access (AIA)
  • Certificate Revocation List (CRL)
  • CRL Distribution Point (CDP)
  • Configuration Partition of Active Directory (DSConfigDN)

As the CA is not part of the domain I need to define the configuration partition of Active Directory via the DSConfigDN registry key, so this information can be used by the AIA and CDP containers. Because the CA will be powered off in normal circumstances I need to define the AIA & CDP location and publish the CA certificate and CDP.

certutil.exe -setreg CA\DSConfigDN "CN=Configuration,DC=lab,DC=damen-online,DC=nl"
certutil.exe -setreg CA\CRLPublicationURLs "1:%WINDIR%\System32\CertSrv\CertEnroll\%3%8%9.crl\n2:\n10:ldap:///CN=%7%8,CN=%2,CN=CDP,CN=Public Key Services,CN=Services,%6%10"
certutil.exe -setreg CA\CACertPublicationURLs "1:%WINDIR%\System32\CertSrv\CertEnroll\%1_%3%4.crt\n2:\n2:ldap://CN=%7,CN=AIA,CN=Public Key Services,CN=Services,%6%11"
certutil.exe -setreg CA\CRLPeriodUnits 6
certutil.exe -setreg CA\CRLperiod "Months"
certutil.exe -setreg CA\CRLDeltaPeriodUnits 0
certutil.exe -setreg CA\ValidityPeriodUnits 10
certutil.exe -setreg CA\ValidityPeriod "Years"
certutil.exe -setreg CA\AuditFilter 127
net stop certsvc
net start certsvc

Now this is done, I can generate a new CRL, which after being generated can be found in C:\Windows\System32\CertSrv\CertEnroll

certutil -crl

For an explanation of the publication options used in the certutil command the following table applies

Option Number Option 
0 No Options Defined 
1 Publish CRLs to this location 
2 Include in the CDP extensions of issued certificates 
4 Include in CRLS. Clients use this to find Delta CRL Locations 
8 Include in all CRLs. Specifies where to publish in the Active Directory when publishing manually. 
64 Publish Delta CRLs to this location 
128 Include in the IDP extension of issued CRLs

There were also some variables used and the table below explains these

Variable  Description 
%1 The DNS name of the certification authority server 
%2 The NetBIOS name of the certification authority server 
%3 The name of the Certificate Authority 
%4 The renewal extension of the certification authority 
%6 The location of the Configuration container in Active Directory 
%7 The “sanitized” name of the certification authority, truncated to 32 characters with a hash on the end 
%8 Inserts a name suffix at the end of the file name when publishing a CRL to a file or URL location 
%9 When a delta CRL is published, this replaces the CRLNameSuffix with a separate suffix to distinguish the delta CRL 
%10 The object class identifier for CRL distribution points, used when publishing to an LDAP URL 
%11 The object class identifier for a certification authority, used when publishing to an LDAP URL

NLSOMCA02 – Enterprise Issuing CA

OK, my Root CA has been configured and the CRL has been published. Now I need to copy the 2 files to a machine in my domain. I don’t have any backup tools in place (yet), so for now I will take the easy route, to add a NIC to the VM, take the files and remove the NIC afterwards. This a very bad practice (just read Het is Oorlog naar niemand die het ziet (Dutch only) by Huib Modderkolk and you will understand if you didn’t already), but for my lab environment which is not accessible from the outside world (yet), it’s a risk I’m willing to take. As you can see I copied the 2 files from NLSOMCA01 to NLSOMCA02.

After this is done I switch to my management server (for the LAB) and create a DNS record for (pointing to as I used this address before as my CDP location.

Starting with the second server (NLSOMCA02). I will combine the web servers (for issuing certificate and the CA role on here). I’ll start with installing the Webserver rol:

Add-WindowsFeature Web-WebServer -IncludemanagmentTools
Add-WindowsFeature Web-Mgmt-Service

The second feature is to ensure I can manage the Internet Information Server remotely. I need to open the firewall, enable remote management and ensure the service is started automatically

netsh advfirewall firewall add rule name="Web Remote Management" dir=in action=allow service=wmsvc
reg add "HKLM\Software\Microsoft\WebManagement\Server" /v EnableRemoteManagement /t REG_DWORD /d 1 /f
sc config wmsvc start=auto
net start wmsvc

This ensures I can connect to the webserver from my management server. Now creating the folder (C:\CertEnroll) that will hold the certificates and that will be used as a virtual directory in my web servers.

mkdir C:\CertEnroll
New-smbShare -Name "CertEnroll" -Path "C:\CertEnroll" -FullAccess SYSTEM,"LAB\Domain Admins" -ChangeAccess "LAB\Cert Publishers"
New-WebVirtualDirectory -Site "Default Web Site" -Name "CertEnroll" -PhysicalPath "C:\CertEnroll"

Now I need to enable some settings on the Virtual Directory to ensure it can be used for hosting certificates:

  • Enable directory browsing on the virtual directory
  • Enable double escaping on the webserver
c:\windows\system32\inetsrv\appcmd set config "Default Web Site/CertEnroll" /section:DirectoryBrowse /enabled:true
c:\windows\system32\inetsrv\appcmd  set config "Default Web Site" /section:system.Webserver/Security/requestFiltering -allowDoubleEscaping:true

Ok now installing the CA bits and bytes…

  • Certificate Authority
  • Certificate Authority Web Enrollment
Add-WindowsFeature ADCS-Cert-Authority -IncludeManagementTools 
Add-WindowsFeature ADCS-Web-Enrollment

To ensure my clients in the domain can use the root certificate I need to publish the certificate and my CRL in my Active Directory:

Certutil -f -dspublish "NLSOMCA01_LAB Damen Root CA.crt" RootCA
Certutil -f -dspublish "LAB Damen Root CA.crl" NLSOMCA01

Publishing done, I ensured both files are stored in the C:\CertEnroll folder on NLSOMCA02 and I add them to the local store of this server.

certutil -addstore -f root "NLSOMCA01_LAB Damen Root CA.crt"
Certutil -addstore -f root "LAB Damen Root CA.crl"

Next step is to configure the web enrollment service using powershell

Install-AdcsCertificationAuthority -CACommonName “LAB IssuingCA” -CAType EnterpriseSubordinateCA -CryptoProviderName “RSA#Microsoft Software Key Storage Provider” -HashAlgorithmName SHA256 -KeyLength 2048

The warning message “The Active Directory Certificate Services installation is incomplete. To complete the installation, use the request fi…” is expected as we need to approve the newly created request on the RootCA. The request is generated during the installation and placed in the root of NLSOMCA02. To approve the request I need to copy this to NLSOMCA01 and run the following command from this server:

Certreq -submit "NLSOMCA02.lab.damen-online.nl_LAB IssuingCA.req"

I select the correct CA, and after clicking OK, I get the message “Certificate request is pending: Taken under submission (0)” and I see a requestID returned. Now I can approve that request and export the certificate so I can import it in my Enterprise Issuing CA:

certutil.exe -resubmit 2
centreq -retrieve 2 "C:\Users\Administrator\Documents\NLSOMCA02.lab.damen-online.nl_LAB_IssuingCA.crt"

I copied the file to NLSOMCA02 and I install the certificate on this server

certutil -installcert NLSOMCA02.lab.damen-online.nl_LAB_IssuingCA.crt
net start certsvc

Now I can configure the AIA & CDP locations as well as the time limits for the CA and CRLs. I will do this in the same way as done on the root CA. Starting with defining the locations for CDP & AIA:

certutil -setreg CA\CRLPublicationURLs "1:%WINDIR%\system32\CertSrv\CertEnroll\%3%8%9.crl\n2:\n3:ldap:///CN=%7%8,CN=%2,CN=CDP,CN=Public Key Services,CN=Services,%6%10"
certutil -setreg CA\CACertPublicationURLs "1:%WINDIR%\system32\CertSrv\CertEnroll\%1_%3%4.crt\n2:\n3:ldap:///CN=%7,CN=AIA,CN=Public Key Services,CN=Services,%6%11"

Now I can set the time limits and restart the Certification Services

certutil.exe -setreg CA\CRLPeriodUnits 1
certutil.exe -setreg CA\CRLperiod "Weeks"
certutil.exe -setreg CA\CRLDeltaPeriodUnits 1
certutil.exe -setreg CA\CRLDeltaPeriod "Days"
certutil.exe -setreg CA\CRLOverlapPeriodUnits 12
certutil.exe -setreg CA\CRLOverlapPeriod "Hours"
certutil.exe -setreg CA\ValidityPeriodUnits 5
certutil.exe -setreg CA\ValidityPeriod "Years"
net stop certsvc && net start certsvc
certutil -crl

To verify if all steps are executed correctly, I connect to my management server where I start C:\Windows\System32\pkiview.msc, and happy happy, joy joy, all looks good.

Now I don’t need my RootCA (NLSOMCA01) anymore so I will shutdown this server. I will keep it on my environment, but I only need to start it again when my PKI is compromised or my issuing CA certificates are expired.

So my PKI Infrastructure is in place. In one of my next posts I will use this for secure my environment.

Bookmark the permalink.


  1. Nice one again Patrick! Just a few notes.
    2048 key length isnt enough anymore these days, rather go for 4096 at least or a EC based key. For example buying a Publically signed SSL cert, 2k key length wont be issued for longer period of 2yr.
    At least i learned this when my deployment at work was reviewed.

    Also i find little benefit of publishing to AD. I’ve setup multiple IssuingCA’s. But prefer to have the client simply do the CRL check on a dedicated web service.

    Btw, something that popped into my mind, using a capilicyinf prior to install can have some benefits. Additionally i try to avoid having a hostname in the ca cert, no spaces in the file and using a G1/G2 for the ‘generation’ of CA in ur environment.

    When you move to replacing the certifixate of PE/PC, please make a blog about it. Havent had time to address that myself yet.

    I didnt intent this to be this long or seem like critic! I enjoy reading your blogs and hearing about your experiences! Keep it coming!

    • Hey Kelly,
      Criticism is always welcome…

      As this is for my LAB I used the 2048 key length as it’s still supported (although minimum: and I actually don’t care if someone gets to it, but you’re right.
      Publishing to AD is entirely for LAB purposes, but I want to validate this also for “Windows Hello for Business”

      Replaced the cert on PE/PC in production already and that is pretty straightforward.

      Thanks for your review and visits!

Leave a Reply

Your email address will not be published. Required fields are marked *