Deploying Enterprise PKI on Windows Server 2012 R2

There are many reasons to deploy your own public key infrastructure (PKI). If you are looking to set up DirectAccess, in certain circumstances – like for instance, when you want Windows 7 clients to access corporate resources over DirectAccess – then you have to deploy an enterprise PKI. Microsoft’s implementation of PKI is called Active Directory Certificate Services, or AD CS, and it comes built into the Windows Server 2012 R2 operating system.

You need to carefully consider your company’s security policies and procedures before propping up an instance of AD CS. There is more to PKI than meets the eye. You need to establish certificate issuance and revocation procedures, private key archival policies, develop a plan for making certificate revocation lists (CRLs) available to internal and external clients, establish a cryptography standard, etc. PKI is likely one of the most paper-policy heavy areas of IT so it is really much easier to deal with the issues that come up when you plan ahead.

The rest of this article shows how to establish a PKI on your Active Directory based corporate network, using mostly PowerShell and command line.

Enterprise PKI Concepts

  • Stand-alone Certificate Authority (CA) – an instance of AD CS service that is running on a non-domain joined server and does not integrate with AD
  • Enterprise CA – an instance of AD CS service that is running on a domain-joined server and integrates with AD by virtue of publishing service location points to the Configuration naming context of the AD
  • Root CA – the root instance of the PKI trust chain. The first AD CS instance you install has to be the root CA, this establishes the trust hierarchy
  • Subordinate CA – the “child” node in the PKI trust chain. A subordinate CA sits “under” the root, or can be nested several levels deep under other higher level subordinate CAs
  • Issuing CA – subordinate CAs that issue end-user certificates are often called issuing CAs, for obvious reasons; however, not all subordinate CAs need to be issuing CAs. It is not uncommon to have a three-tier PKI structure with intermediate CAs, which are subordinate, but not used to issue certificates

Enterprise PKI Best Practices

Best practices is something that will vary depending on who you ask, but one PKI recommendation that has been given consistently over many years is that the root CA should be stand-alone, and offline. In some environments you will have to set up a root CA without ever connecting it to the network – the process of doing that vs. setting up a server on the network but off the domain isn’t much different, except you’d use a USB key to transfer a few files instead of a file share. Offline root CA will still be needed when the following events occur:

  • Issuing CA certificate is expiring and needs to be renewed
  • Issuing CA certificate needs to be re-issued in order to change crypto parameters, such as the hashing algorithm
  • Issuing CA is compromised and needs to be revoked
  • A new issuing CA needs to join the trust hierarchy at the same level (right under the root)
  • The root CA certificate is about to expire and needs to be renewed
  • The root CA CRL is about to expire and needs to be regenerated
From this list it kind of becomes obvious, why people want to keep root CAs offline. If anything happens to the root CA, the entire trust hierarchy is compromised; it is much easier to revoke an issuing CA certificate and setup a new issuing CA, than replace the entire PKI infrastructure.

Another point that will come up almost certainly is private key archival, if EFS certificates will be offered to the users. As an admin, you will want to make sure that private keys are archived (test it too…) so that you could still decrypt user data in the event of the original private key becoming damaged or going missing.

Enterprise PKI Design

Being diligent, we sketch out what we are about to do first.

Enterprise PKI Design Diagram

Enterprise PKI Design Diagram


Enterprise PKI Build Procedures

Unless stated otherwise, all procedures (especially command lines) have to be executed in elevated mode.

1. Installing Offline Root CA

In PowerShell,

Add-WindowsFeature ADCS-Cert-Authority -IncludeManagementTools

In PowerShell or command line,

notepad c:\windows\capolicy.inf

then paste the following CA parameters and save the file

 Signature=”$Windows NT$”

Note, that CRL expiration period value of 26 weeks equals 6 months, which is how often you will be bringing up the offline root CA in order to regenerate the CRL. Root CA CRL must be copied to an online issuing CA, otherwise clients and subordinate CAs will not be able to validate certificates.

Next, in PowerShell

Install-AdcsCertificationAuthority -CAType StandaloneRootCA -KeyLength 4096 -HashAlgorithmName SHA256 -ValidityPeriod Years -ValidityPeriodUnits 20 -CACommonName "Flexecom Root CA" -CryptoProviderName "RSA#Microsoft Software Key Storage Provider"

This command installs the root CA. Pay attention to hash algorithm; as of November 2013, Windows 7 and possibly other Microsoft operating system environments (OSEs) do not support SHA512 hashing, even though Windows Server 2012 R2 has that support. SHA1 is not recommended as it has been proven to be flawed. Current recommendation seems to converge around SHA256 in infrastructures that may actually last 20 years.

Run the following commands in PowerShell (most of them will work in command line, except Restart-Service)

certutil.exe –setreg CA\CRLPublicationURLs “1:C:\Windows\System32\CertSrv\CertEnroll\%3%8.crl\n2:”
certutil.exe –setreg CA\CACertPublicationURLs “2:”
certutil.exe –setreg CA\CRLPeriodUnits 26
certutil.exe –setreg CA\CRLPeriod “Weeks”
certutil.exe –setreg CA\CRLDeltaPeriodUnits 0
certutil.exe –setreg CA\CRLDeltaPeriod “Days”
certutil.exe –setreg CA\CRLOverlapPeriodUnits 12
certutil.exe –setreg CA\CRLOverlapPeriod “Hours”
certutil.exe –setreg CA\ValidityPeriodUnits 10
certutil.exe –setreg CA\ValidityPeriod “Years”
certutil.exe –setreg CA\DSConfigDN “CN=Configuration,DC=flexecom,DC=com”
Restart-Service certsvc
certutil -crl

These commands set up CRL validity and publication service points, as well as defines default CA certificate validity periods and switches off delta CRL generation.

One more note regarding the CRL expiration. If you set it too high (52 weeks), you will have less work do to on the offline root CA, you won’t need to bring it up as often. The downside is that, should you need to revoke a certificate, and update the CRL, not all clients will be checking it (the new CRL) immediately. Client that cache the CRL may keep it though expiration, which may effectively result in a partial loss of control over your own certificate authority (by not being able to effectively revoke issued certificates).

certutil.exe -crl command at the end is the one that generates the new CRL, and drops it as configured, into “C:\Windows\System32\CertSrv\CertEnroll” directory.

2. Publishing Offline Root CA to Active Directory

From the directory above, copy *.crl and *.crt files to a USB stick (if the root CA is offline) or to a C$ share on the subordinate CA.

Then on the subordinate CA, run the following commands in PowerShell or command line. The first command adds the offline root CA public certificate to the AD DS, Configuration naming context. The second and third commands add the root CA and the root CRL to the relevant certificate stores on the subordinate CA.

certutil.exe –dspublish –f “CAROOT01_Flexecom Root CA.crt” RootCA
certutil.exe –addstore –f root “CAROOT01_Flexecom Root CA.crt”
certutil.exe –addstore –f root “Flexecom Root CA.crl”

3. Creating Root CA Certificate and CRL Distribution Endpoints

You may have noticed that we added as a CRL distribution point. Every time a certificate is issued by the root CA, this URL will be published on the certificate to instruct the consumers of that certificate that the CRL can be downloaded from this URL. We need to create the website on the online CA that will be serving this CRL (it can be any web server, not just an online CA).

On the subordinate CA, using PowerShell

mkdir c:\pki
new-smbshare –name pki –FullAccess SYSTEM,”Flexecom\Domain Admins” –changeaccess “Flexecom\Cert Publishers” -path c:\pki

I don’t have the web components installed on this subordinate CA yet, so I will finish this step later.

4. Installing an Enterprise Issuing CA

In PowerShell on the subordinate, domain-joined CA

Add-WindowsFeature ADCS-Cert-Authority -IncludeManagementTools
Add-WindowsFeature ADCS-Web-Enrollment,ADCS-Enroll-Web-Pol,ADCS-Enroll-Web-Svc,ADCS-Online-Cert,Web-Mgmt-Console

This installs AD CS as well as some additional auxiliary services we will configure later.

At this point we can finish the task we started in #3, since the web components were installed as part of web enrollment service installation. This next set of steps we will perform in the IIS Management MMC, one of the rare deviations from the command-line only CA installation:

  1. Create a new virtual directory, alias “pki”, physical path “c:\pki”
  2. Access the properties of c:\pki folder
  3. Switch to the Security tab and add Flexecom\Cert Publishers group, as well as “IIS AppPool\DefaultAppPool” identity to the NTFS ACL. Grant Cert Publishers the right to Modify (leave DefaultAppPool with its default Read/Execute level)
  4. Access pki virtual directory in IIS Management
  5. Double-click Request Filtering. On the right, click on Edit Feature Settings. Enable “Allow double escaping” and save settings

Now copy the *.crl and *.crt files from the root CA to C:\pki on the subordinate CA.

Let’s resume our subordinate CA installation

notepad.exe c:\windows\capolicy.inf

Copy and paste the following parameters into the notepad document

Signature=”$Windows NT$”

In PowerShell

Install-AdcsCertificationAuthority –CAType EnterpriseSubordinateCA –CACommonName “Flexecom First Issuing CA” –CryptoProviderName “RSA#Microsoft Software Key Storage Provider” –KeyLength 4096 –HashAlgorithmName SHA256

You should get the error 398, stating that CA installation is incomplete. This is expected. The installation will generate a certificate request file and drop it in the root of C: on the subordinate CA. Copy this file to the offline root CA, and then get this certificate issued using the following commands:

certreq.exe –submit “c:\casub01.flexecom.com_Flexecom First Issuing CA.req”

You will be prompted to select a certificate authority, select the only one listed (should be your root CA). The command will print the request ID (if this is your first certificate request, this will be ID = 2). Launch Certification Authority MMC and issue this requested certificate. Then back at the command line

certreq.exe -retrieve 2 subca.crt

This command gets the issued Subordinate CA certificate, which now needs to be transferred to and installed on the CASUB01 server.

certutil.exe -installcert subca.crt
Start-Service CertSvc

5. Completing Enterprise Issuing CA Installation

Run the following commands in PowerShell

certutil.exe –setreg CA\CRLPeriodUnits 2
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”

$crllist = Get-CACrlDistributionPoint; foreach ($crl in $crllist) {Remove-CACrlDistributionPoint $crl.uri -Force};

Add-CACRLDistributionPoint -Uri C:\Windows\System32\CertSrv\CertEnroll\%3%8%9.crl -PublishToServer -PublishDeltaToServer -Force

Add-CACRLDistributionPoint -Uri -AddToCertificateCDP -Force

Add-CACRLDistributionPoint -Uri file://\\\pki\%3%8%9.crl -PublishToServer -PublishDeltaToServer -Force

$aialist = Get-CAAuthorityInformationAccess; foreach ($aia in $aialist) {Remove-CAAuthorityInformationAccess $aia.uri -Force};

Add-CAAuthorityInformationAccess -AddToCertificateAia –Force

Add-CAAuthorityInformationAccess –AddToCertificateAia “ldap:///CN=%7,CN=AIA,CN=Public Key Services,CN=Services,%6%11”

Restart-Service CertSvc
certutil.exe -crl

As you can see, we’ve configured CRL/CA parameters similarly to how it was done earlier at the root CA. Commands are pretty self explanatory. In the second half of the batch we removed all CA CRL distribution points and re-applied them, to publish CRL into AD (ldap), SMB share, as well as through the web site

The last line, certutil.exe -crl, generated the full Subordinate CA CRL, as well as the delta Subordinate CA CRL, and dropped them into the C:\pki directory, which coincidentally makes the files available through to both internal and external clients. This is the intended behavior, check C:\pki to ensure that the files are there.

Make sure that DNS records are created in both the internal and external DNS zones to point to the relevant IP address (internal in the internal DNS zone, NATted external in the external DNS zone; check your firewall and enable port 80/tcp communication to as applicable).

Last step here, copy *.crt files from C:\Windows\System32\CertSvc\CertEnroll directory to C:\pki. C:\pki should now have 5 files, two CRTs (one from each CA) and three CRLs (one full CRL from each CA, and one delta CRL from the sub CA).


At this point, CA infrastructure is set up. There are a few things still left to be done, namely:

  • Configure CA Web Services
  • Configure Online Responder Revocation Policy
  • Configure Key Archival Policy
  • Configure Relevant Certificate Templates
  • Enable Auto-enrollment

This post is getting pretty long so the bullets above will be dealt with at a later date, in another post.


Leave a Reply

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


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>