Intel vPro – Configuration – Part 3 – PKI Configuration

vPro Series of Posts


Now that your PKI is installed, we need to configure it for use with vPro.

Overview

  1. Create Provisioning Certificate Template
  2. Create AMT Device TLS Template

Creating the Provisioning Certificate Template

  1. RDP to your Enterprise Subordinate CA Server, then choose Start -> Run -> certtmpl.msc.
  2. Right-click the Web Server certificate template and choose ‘Duplicate’.
  3. Name the new template “AMT Provisioning Certificate”
  4. Navigate to the ‘Request Handling’ tab, and check the box labeled “Allow private key to be exported”.
  5. Navigate to the ‘Subject Name’ tab, and choose ‘Build from this Active Directory information’.
  6. Click the ‘Subject Name Format’ combo box and choose ‘Common Name’ from the list. Leave the other checkboxes on this page to their defaults.
  7. Navigate to the ‘Security’ tab, and grant the server which is going to run the Intel SCS service the Read and Enroll permissions. If you don’t have a server configured to run Intel SCS, you will have to come back and do this later.
  8. Navigate to the ‘Extensions’ tab, click ‘Application Policies’, then click ‘Edit’.
  9. On the ‘Edit Application Policies Extension’ screen, click ‘Add’.
  10. On the ‘Add Application Policy’ screen, click “New”.
  11. On the ‘New Application Policy’ screen, enter the following:
    • Name: ‘AMT Provisioning’
    • Object Identifier: 2.16.840.1.113741.1.2.3
  12. Click ‘OK’ until the template is saved.

Create the AMT Device TLS Certificate Template

This template will be used by the Intel SCS service. It will request certificates on behalf of your AMT devices. These certificates will be installed into the AMT device firmware and used for traffic authentication and for the WebUI.

  1. RDP to your Enterprise Subordinate CA Server, then choose Start -> Run -> certtmpl.msc.
  2. Right-click the certificate template named “Web Server” and choose ‘Duplicate’.
  3. Name the new template “AMT TLS Certificate”.
  4. Navigate to the ‘Request Handling’ tab, and check the box labeled “Allow private key to be exported”.
  5. Navigate to the ‘Subject Name’ tab, and ensure that the radio button ‘Supply in the request’ is selected.
  6. Navigate to the ‘Security’ tab, and grant the Intel SCS Server the Read and Enroll permissions. If you don’t have a server configured to run Intel SCS, you will have to come back and do this later.
  7. Click ‘OK’ to save the template.

Enabling the Templates

  1. On your Enterprise Subordinate CA server, run the ‘Certification Authority’ tool.
  2. Navigate to the ‘Certificate Templates’ folder on the left pane.
  3. Right-click the ‘Certificate Templates’ folder and choose ‘New’ -> ‘Certificate Template to Issue’.
  4. Choose the ‘AMT TLS Certificate’ template, and click ‘OK’.
  5. Again, right-click the ‘Certificate Templates’ folder and choose ‘New’ -> ‘Certificate Template to Issue’.
  6. Choose the ‘AMT TLS Certificate’ template, and click ‘OK’.

Great! Now you’re ready to install and configure the Intel SCS Service. This will be detailed in a future post.

Intel vPro – Configuration – Part 2 – PKI Installation

vPro Series of Posts


At this point in the series, our goal is to set up the simplest possible configuration to get vPro working as a proof-of-concept. Since the proof-of-concept will be using a self-signed certificate, we will need to install a Certificate Authority. Since it’s unsafe to use a single-tier PKI with vPro, we will install a two-tier PKI.

This post will cover the following:

  1. Installing the Offline Standalone Root CA
  2. Installing the Online Enterprise Subordinate (Issuing) CA

Installing the Offline Standalone Root CA

Requirements

You will need two VM’s:

  • Standalone root CA: Windows Server 2008 Standard or better.
  • Enterprise subordinate CA: Windows Server 2008 Enterprise or better.

Concepts

Please read the following blog post a couple times in order to learn the concepts behind PKI. Without this information, it will be difficult to continue.

In our case, we will configure IIS on the enterprise subordinate CA and use it as the AIA and CDP locations for both the offline standalone root and the online enterprise subordinate issuing CA.

Procedure

  1. Install Windows Server 2008 Standard or above on the VM.
  2. Download the following scripts from my blog post titled Server 2008 R2 Standalone Root CA Install Script and store them on the VM at the folder C:\Install_Files.
    1. capolicy.inf
    2. SetupCA-RootCA.ps1
    3. Install-StandAloneCA.cmd
  3. Modify capolicy.inf.
    1. Remove the following lines:
      [LegalPolicy]
      URL = "http://certs.chemistry.ohio-state.edu/CertData/cps.docx"
    2. Change the line ‘renewalkeylength’ from 4096 to 2048. vPro doesn’t support keys larger than 2048.
  4. Modify SetupCA-RootCA.ps1 line 351.
    1. Replace -CAName with a friendly-name for your CA (you get to choose this).
    2. Change -DNSuffix to match the distinguished name of your domain. You can find this by running the following command in powershell:
      ([adsi]'').distinguishedname
    3. Finally, change -HashAlgorith from SHA256 to SHA1. vPro doesn’t support SHA256 certificates.
  5. Modify Install-StandAloneCA.cmd
    1. Insert your domain’s distinguished name on line 9.
    2. On line 20, replace the entire line with the following code. Replace the URL with the FQDN of your future Enterprise Subordinate CA.
      certutil -setreg CA\CRLPublicationURLs "1:%windir%\system32\CertSrv\CertEnroll\%%3%%8%%9.crl\n2:http://cdp.yourdomain.com/Certdata/%%3%%8%%9.crl"
    3. On line 23, replace the entire line with the following code. Replace the URL with the FQDN of your future Enterprise Subordinate CA.
      certutil -setreg CA\CACertPublicationURLs  "1:%windir%\system32\CertSrv\CertEnroll\%%1_%%3%%4.crt\n2:http://aia.yourdomain.com/CertData/%%1_%%3%%4.crt"
  6. After placing all three files into C:\Install_Files, launch a command prompt as administrator and type the following commands:
    cd C:\Install_Files
    Install-StandAloneCA.cmd
    certutil -crl

Enterprise Subordinate Issuing CA

Now that your Offline Root CA is configured, it’s time to install the Enterprise Issuing CA.

Procedure

  1. Install Windows Server 2008 Enterprise or above on the VM.
  2. Create partitions on the server like the following:
    • C:\, 25GB, boot
    • D:\, 5GB, cert db
    • E:\, 5GB, logs
    • F:\, 5GB, inetpub
  3. Download the following scripts from my blog post titled Server 2008 Enterprise Subordinate CA Install Scripts and store them on the VM at the folder C:\Install_Files.
    1. capolicy.inf
    2. Setup-IssuingCA1.ps1
    3. Install-ADCS.cmd
  4. Modify capolicy.inf.
    1. Remove the following lines:
      [LegalPolicy]
      URL = "http://certs.chemistry.ohio-state.edu/CertData/cps.docx"
    2. Change the line ‘renewalkeylength’ from 4096 to 2048. vPro doesn’t support keys larger than 2048.
  5. Modify Setup-IssuingCA1.ps1 line 351.
    1. Replace -CAName with a friendly-name for your CA (you get to choose this).
    2. Change -DNSuffix to match the distinguished name of your domain. You can find this by running the following command in powershell:
      ([adsi]'').distinguishedname
    3. Finally, change -HashAlgorith from SHA256 to SHA1. vPro doesn’t support SHA256 certificates.
  6. Modify Install-ADCS.cmd
    1. Insert your domain’s distinguished name on line 9.
    2. On line 20, replace the entire line with the following code. Replace the URL with the FQDN of your future Enterprise Subordinate CA.
      certutil -setreg CA\CRLPublicationURLs "65:%windir%\system32\CertSrv\CertEnroll\%%3%%8%%9.crl\n65:F:\inetpub\wwwroot\certdata\%%3%%8%%9.crl\n6:http://cdp.yourdomain.com/Certdata/%%3%%8%%9.crl"
    3. On line 23, replace the entire line with the following code. Replace the URL with the FQDN of your future Enterprise Subordinate CA.
      certutil -setreg CA\CACertPublicationURLs  "1:%windir%\system32\CertSrv\CertEnroll\%%1_%%3%%4.crt\n1:F:\inetpub\wwwroot\certdata\%%1_%%3%%4.crt\n2:http://aia.yourdomain.com/CertData/%%1_%%3%%4.crt"
  7. After placing both files into C:\Install_Files, launch a command prompt as administrator and type the following commands:
    cd C:\Install_Files
    Install-ADCS.cmd

Fixing Certificate Validation

Before we continue, we need to configure the AIA and CDP points so that certificate validation will pass. Otherwise, the subordinate CA won’t trust the root when we try to link them.

  1. Download the following scripts from my blog post titled Server 2008 Enterprise Subordinate CA Install Scripts – Part 2 – IIS and store them on the VM at the folder C:\Install_Files.
    1. Install-SubCA-IIS.cmd
    2. MoveIISRoot.cmd
  2. Open a command prompt as administrator and type the following commands:
    cd C:\Install_Files
    Install-SubCA-IIS.cmd
  3. Login to the Standalone Root CA and copy the files located at C:\Windows\System32\certsrv\certdata to the Subordinate CA’s path F:\inetpub\wwwroot\CertData. These files are the CA Certificate and the initial blank CRL, needed for the CDP and AIA locations.

Linking the two CA’s

You might notice that after running Install-ADCS.cmd, the script gives you an error that the Enterprise Subordinate CA does not have a CA certificate and thus cannot start. Here’s how we fix that.

Step 1 – Establish Trust

In order for the servers to have a parent-child relationship, the child CA must trust the parent CA.

  1. Login to the Subordinate CA.
  2. Start -> Run (or Windows+R) -> “mmc”
  3. File -> Add Snap-in -> Certificates -> Local Computer -> Computer Account.
  4. Expand until you see ‘Trusted Root Certificate Authorities’.
  5. Right-click ‘Trusted Root Certificate Authorities’ and choose ‘Install Certificate’.
  6. Follow the wizard, selecting the file at F:\inetpub\wwwroot\CertData\ that was copied from the Standalone CA.

Step 2 – Generate a CA Certificate for the Subordinate CA

  1. Look on the C drive of the Enterprise Subordinate CA. You will see a certificate request file. Copy this file to your Standalone Root CA.
  2. Login to the standalone root CA and launch the Certificate Authority snap-in from ‘Administrative Tools’.
  3. Right-click the Standalone Root CA and choose ‘All Tasks’ -> ‘Submit New Request’.
  4. Open the request file saved from the C drive of the Enterprise Subordinate CA.
  5. Navigate to ‘Pending Requests’.
  6. Right-click the Pending Request for the Enterprise Subordinate CA’s certificate and choose ‘Approve’.
  7. Navigate to ‘Issued Certificates’.
  8. Double-click the Enterprise Subordinate CA’s certificate.
  9. Navigate to the ‘Details’ tab.
  10. Choose ‘Copy to File…’
  11. Follow the wizard, accepting the defaults. Save the file and copy the file to the Enterprise Standalone CA.

Step 3 – Install the Subordinate CA’s CA Certificate

  1. Login to the Enterprise Subordinate CA and launch the Certificate Authority snap-in from ‘Administrative Tools’.
  2. Right click the Enterprise Subordinate CA and choose ‘Install CA Certificate’.
  3. Select the certificate file copied from the Standalone Root CA.
  4. Right-click the Enterprise Subordinate CA and choose ‘All Tasks’ -> ‘Start Service’.

Verification

Both certificate servers should now be theoretically working and can issue and verify certificates. To test this, login to the Enterprise Subordinate CA and run the command ‘PKIView.msc’. It should enumerate your PKI and there should be no errors.

Congrats! Your PKI is now installed. Look to the next post for configuring your PKI for Intel AMT.

Single vs Two Tier PKI

Organizations typically decide to install a PKI because they want a piece of software which requires it. Usually, the end result is someone RDP’ing to a domain controller, starting server manager, installing the ADCS role, and clicking next a few times. This can lead to problems down the road. To understand this more, first we need to go over a bit of certificate basics.

Certificate Overview

Let’s pretend I have a CA named ‘MyCA.fakecompany.com’ and I issue a web server certificate from it to ‘MyWebServer.fakecompany.com’. When a client visits the website ‘mywebserver.fakecompany.com’ using https, the web server presents it’s certificate to our browser. This certificate must be ‘validated’ according to multiple criteria: expiration, revocation, and trusted root. Expiration is easy — certificates contain a date range for which they’re valid. The computer validating the certificate can check it’s current date and time against the certificate’s date range, and validate that criteria. Revocation and Trusted Root are a bit more tricky.

Certificate Validation

Certificates are considered ‘valid’ when they meet the following criteria:

  1. The certificate is not expired.
  2. The certificate has not been revoked.
  3. The computer validating the certificate trusts one of the CA’s in the chain.

As stated before, expiration is easy to validate. But what about revocation?

Revocation

Let’s say that the certificate I issued to MyWebServer is valid for 1 year, but a hacker broke in and stole the certificate’s private key about a month into that 1 year validity period. The hacker can use this certificate in combination with a DNS redirection exploit on a client PC to act as my web server, and no one would be the wiser.

If we wanted to stop the hacker from using our web server’s certificate to spoof our service (say, http://www.myimportantbankinginfo.com), then we need a mechanism to tell the browser not to use the certificate. This mechanism is called certificate revocation.

To revoke a certificate in Server 2008, you run the ‘certification authority’ snap-in, right-click a certificate, and choose ‘revoke’. But what happens behind the scenes? How does the client web browser find out about the certificate’s revocation status?

Certificate Authorities maintain a list of revoked certificates that other systems can download and check. This list is called the CRL, or certificate revocation list. Anytime a browser accesses an https website, the browser finds and downloads the CRL corresponding to the CA which issued the web site’s https certificate. It then checks to see if the certificate presented by the web server is listed in the CRL. If so, the certificate will not be validated and you’ll see the browser’s certificate warning page.

But where does the browser find the CRL? Good question. Certificates can include an extension called a ‘CDP’, also known as a ‘CRL Distribution Point’. This is a list of HTTP or LDAP URL’s which point to the CRL for the certificate’s parent CA. You can even check the CRL of this web page right now! On your browser, click the ‘lock’ icon next to the URL at the top of the page and choose ‘certificate information’. After poking around, you should be able to find a line named ‘CRL Distribution Point’. If you copy the URL and paste it into the web browser, you will get a file ending in .crl containing a list of serial numbers of certificates that the CA has ‘revoked’.

An interesting note is that CRL’s expire. If the CDP presents your browser with an expired CRL, the certificate won’t validate unless a secondary CDP point contains a valid CRL.

Next, let’s talk about the chain of trust.

Trusted Roots and the AIA Extension

OK, so let’s pretend we have a certificate which hasn’t expired, and is not listed in the CRL’s. What we now know is that at some point in time someone decided to issue a certificate and hasn’t decided to revoke it. Now, we want to know if the issuer of the certificate is someone we trust. I can issue certificates for amazon all day, but unless your computer trusts me as an authoritative source, my certificates won’t validate.

So for this imaginary certificate we have, let’s also say that it’s issuing CA is named ‘Contoso Issuing CA’. If we look in the ‘trusted root certificate authorities’ store on our computer, we don’t see an entry for ‘Contoso Issuing CA’, so the certificate doesn’t immediately validate. This doesn’t mean we’re done though.

It’s not important that the direct parent of the certificate be trusted by your client, it’s just important that someone on the chain of trust is trusted by your client. For example, the grandparent, or the great-grandparent, or the great-great…ok, I think you get it.

So where do we find our certificate’s parent CA, let alone the grand-parent? From the AIA extension of course! AIA stands for ‘Authority Information Access’. It’s a HTTP or LDAP URL that points to the download location of the CA Certificate of the issuing parent of the current certificate you’re looking at. You can check this out in the current browser session by clicking the ‘lock’ on the address bar of any https website, choosing ‘certificate information’, and poking around for a line that reads ‘AIA Location’.

So, we follow the AIA of our certificate, and we get the ‘CA Certificate’ of the ‘Contoso Issuing CA’. This certificate has it’s own CRL to check, expiration date, etc. It checks out, but our computer doesn’t trust this CA, so we follow the AIA url and download the CA cert of the parent of ‘Contoso Issuing CA’. Let’s say that we get back a certificate from GoDaddy (or Equifax, or a bunch of other operators). Our computer trusts those, so the certificate validates.

Whew — simple right?

So what does this have to do with building a 1-Tier vs 2-Tier PKI?

PKI in Tears

With a single-tier PKI, in order for clients to trust your certificates, you need to install the CA Certificate of the CA into the trusted root certificate authorities store on all your clients. This is easy enough to do via group policy. Also, by default, the CDP and AIA locations on a Microsoft CA will point to LDAP locations in active directory, which the CA will manage automatically. Sounds awesome, right?

Problem 1 – Internet Clients

But what if your client isn’t connected to the LAN? Now you can’t get to LDAP, and so your certificates all fail to validate for laptop clients. If we’re just talking about enabling LDAPS on domain controllers than this isn’t a big deal, but for multi-platform web servies or SCCM Native\Internet mode, it’s a deal killer.

I can hear your guys now — “But John, what if we install a 1-Tier PKI with HTTP AIA and CDP locations? Hah! We got you now!”

Problem 2 – Recovering from a CA Hack

But what if your CA is compromised? The only way to recover and invalidate certificates with a single-tier PKI would be to visit every client and remove the old CA’s certificate from the trusted root certificate authorities share. Read that again — you need to visit _every client_ that you want to recover. If you miss a client, then that client is completely vulnerable to the attacker and will remain so until the CA certificate has expired.

How is this different from a multi-tier PKI? If an online issuing CA is compromised in a multi-tier PKI, all we need to do is revoke that specific compromised CA, publish a new CRL to the CDP locations, and re-issue the client certificates. This can all be done with a couple of clicks, and we’re good to go.

Even Better – Use an Offline Root

Having multiple tiers is helpful, but what if the root gets compromised? Then you’re in the same boat as a single-tier PKI — hitting every client to uninstall the compromised CA certificate.

The best-practice here is to create a ‘Standalone Offline Root CA’. This server would be kept powered off and disconnected from the network. It should only be powered on when it’s necessary to authorize other CA’s and publish CRL’s. Even then, these functions should be handled via sneaker-net. It should not be connected to the network. This will provide a greater level of protection for the root CA of your PKI.

Additionally, it’s possible to buy a hardware security module to store the root keys, so that an attacker would need to compromise both the offline root CA and the HSM.

Conclusion

And that’s it! 90% background information, 10% why a 1-tier PKI is not optimal. This stuff is hard and I glossed over a lot of the details (certificate hash checking, security policies, etc). For a more in-depth treatise on certificate validation, see the references below. Also, when dealing with Microsoft PKI, the gold-standard is still Brian Komar’s book. It’s awesome, but you might have trouble finding it. I got mine from eBay, but Safari Tech has it, and I think there are digital copies available for the kindle.

References:

Revoking and Superseding Duplicate Configuration Manager Client Certificates

I noticed that every time we reimaged a workstation, it would be issued a new certificate from our Certificate Authority. Since we only have 1 CA issuing SCCM Client certificates, one of  my coworkers and I threw together the following script. His name is Robert, and he did most of the work on this one. He’s awesome; you should hire him.

Download

It’s named ‘Revoke-DuplicateSCCMClientCerts.ps1’ and is available on my Github repo here: Jpuskar’s Github Page.

Usage

Run the powershell script with the /force argument. By default, it’s read-only and will run in ‘what-if’ mode.

Known Issues

It’s really only designed for a Single-CA environment. If you’ve got multiple CA’s, but only one issues SCCM certs, that’s fine. However, if you’re load-balancing your SCCM certificate issuing across multiple CA’s, the script will only look at a single CA’s certificate database for duplicates. It’s probably possible for it to be modified to work across multiple CA’s, but you’d need to key off of issue date instead of request ID like we’re doing now.

Enjoy!

Server 2008 Enterprise Subordinate CA Install Scripts – Part 3 – DFSR

It’s important that the inetpub directories of both Subordinate CA’s are synchronized. We can use DFSR to do this!

Overview

  • Part 1 – Installing ADCS
  • Part 2 – Installing IIS 7
  • Part 3 – Installing DFSR
  • Part 4 – Installing Certificate Web Enrollment Pages
  • Part 5 – Installing CES\CEP
  • Part 6 – Installing an OCSP Responder Array

Scripts!

File 1 – Install-DFSR.cmd

REM Install and Configure DFSR for IIS Content Repl
Powershell -executionpolicy bypass -command "Import-Module ServerManager; Add-WindowsFeature File-Services,FS-DFS,FS-DFS-Replication"
dfsradmin RG New /rgname:"CDP Replication Group"
dfsrAdmin RG Set Schedule full /RGName:"CDP Replication Group"
dfsradmin member new /rgname:"CDP Replication Group" /memname:%computername%
dfsradmin RF New /rgName:"CDP Replication Group" /RfName:CertData
dfsradmin Membership Set /RgName:"CDP Replication Group" /RfName:CertData /MemName:%computername% /LocalPath:F:\inetpub\wwwroot\CertData /MembershipEnabled:true /IsPrimary:true

REM Set staging directory
IF NOT EXIST "G:\DFSR" MKDIR "G:\DFSR"
IF NOT EXIST "G:\DFSR\Staging" MKDIR "G:\DFSR\Staging"
IF NOT EXIST "G:\DFSR\Staging\CertData" MKDIR "G:\DFSR\Staging\CertData"
Powershell -ExecutionPolicy bypass -file ".\Change-DFSRStaging.ps1"
IF EXIST "F:\inetpub\wwwroot\certdata\dfsrPrivate\staging" RMDIR /s /q "F:\inetpub\wwwroot\certdata\dfsrPrivate\staging"

File 2 – Change-DFSRStaging.ps1

Here’s a previous blog post of mine with very similar information: Changing the DSFR Staging Path with PowerShell.

#I want to change the stagingPath parameter of the respective instance of the DfsrReplicatedFolderConfig class
#The staging path is actually stored in AD
$computer = gc env:computername
$targetStagingPath = "G:\dfsr\staging\certdata"

#find the repl folder GUID
$ReplFolderConfigs = $null
$i = 0
While($ReplFolderConfigs -eq $null)
	{
		If($i -gt 0)
			{Sleep -seconds 2}
		ElseIf($i -gt 15)
			{
				$foundFolderConfigs = $false
				Break
			}
		$ReplFolderConfigs = gwmi -namespace "root\MicrosoftDFS" -class DfsrReplicatedFolderConfig
		$i++
	}

If(($ReplFolderConfigs.GetType().BaseType.Name) -eq "Array")
	{
		$ReplFolderConfigs | % {
			write-host -f cyan $_.RootPath
			If($_.RootPath -like "*inetPub*CertData*" -and $_.StagingPath -like "*inetPub*CertData*")
				{$replFolder = $_}
		}
	}
Else
	{$replFolder = $ReplFolderConfigs}
$folderGUID = $ReplFolder.ReplicatedFolderGuid

write-host -f cyan "folderGuid: $folderGUID"

#grab the objet from AD
$strFilter = "(&(objectClass=msDFSR-Subscription)(CN=" + $folderGUID + "))"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = $strFilter
$colResults = $objSearcher.FindAll()

If(($colResults.PSBase.GetType().Name) -eq "SearchResult")
	{$sDFSRConfigLDAPPath = $colResults.Path}
Else
	{
		$colResults | % {
			$result = $_
			$ldapResult = $result.Path
#			write-host -f green $ldapResult
			If($ldapResult -like ("*" + $computer + "*"))
				{$sDFSRConfigLDAPPath = $ldapResult}
		}
	}

#write-host -f yellow "sDFSRConfigLDAPPath: $sDFSRConfigLDAPPath"
$objDFSRConfig = [adsi]$sDFSRConfigLDAPPath

#modify the property
$stagepath = $objDFSRConfig.Get("msDFSR-StagingPath")
#write-host -f yellow "Current staging path: $stagepath"
$objDFSRConfig.Put("msDFSR-StagingPath",$targetStagingPath)
$objDFSRConfig.SetInfo()

#restart the dfsr service
Restart-Service DFSR
Sleep -seconds 10

Running the install-dfsr.cmd script on both Sub CA’s should start them sync’ing their inetpub folders! Stay tuned for Part 4.

Server 2008 Enterprise Subordinate CA Install Scripts – Part 2 – IIS

Overview

  • Part 1 – Installing ADCS
  • Part 2 – Installing IIS 7
  • Part 3 – Installing DFSR
  • Part 4 – Installing Certificate Web Enrollment Pages
  • Part 5 – Installing CES\CEP
  • Part 6 – Installing an OCSP Responder Array

Scripts!

File 1 – Install-SubCA-IIS.cmd

REM Install and Configure IIS for CertData content
Powershell -executionpolicy bypass -command "Import-Module ServerManager; Add-WindowsFeature net-framework-core"
PKGMGR.EXE /l:log.etw /iu:IIS-WebServerRole;IIS-WebServer;IIS-CommonHttpFeatures;IIS-StaticContent;IIS-DefaultDocument;IIS-HttpErrors;IIS-HttpRedirect;IIS-ApplicationDevelopment;IIS-ASP;IIS-ISAPIExtensions;IIS-HealthAndDiagnostics;IIS-HttpLogging;IIS-LoggingLibraries;IIS-RequestMonitor;IIS-HttpTracing;IIS-Security;IIS-WindowsAuthentication;IIS-RequestFiltering;IIS-IPSecurity;IIS-Performance;IIS-HttpCompressionStatic;IIS-WebServerManagementTools;IIS-IIS6ManagementCompatibility;IIS-Metabase

REM Move IIS Folders About
CALL moveIIS7Root.bat
REN C:\inetpub\wwwroot wwwroot.old
IF NOT EXIST F:\inetpub MKDIR F:\inetpub
IF NOT EXIST F:\inetpub\wwwroot MKDIR F:\inetpub\wwwroot
IF NOT EXIST F:\inetpub\wwwroot\CertData MKDIR F:\inetpub\wwwroot\CertData

REM Allow Double Escaping for Delta CRLs
%systemroot%\system32\inetsrv\appcmd set config /section:requestfiltering /allowdoubleescaping:true

REM Deny DFSRStaging from being accessed
%systemroot%\system32\inetsrv\appcmd set config /section:requestfiltering /+denyurlsequences.[sequence='DfsrPrivate']

File 2 – MoveIISRoot.cmd

This was and slightly modified from the Microsoft KB Article Guidance for relocation of IIS 7.0 and IIS 7.5 content directories.

REM PLEASE BE AWARE: SERVICING (I.E. HOTFIXES AND SERVICE PACKS) WILL STILL REPLACE FILES
REM IN THE ORIGINAL DIRECTORIES. THE LIKELIHOOD THAT FILES IN THE INETPUB DIRECTORIES HAVE
REM TO BE REPLACED BY SERVICING IS LOW BUT FOR THIS REASON DELETING THE ORIGINAL DIRECTORIES
REM IS NOT POSSIBLE.

@echo off
setlocal
set MOVETO=F:\
set MOVELOG=E:\

REM simple error handling if drive does not exist or argument is wrong
IF NOT EXIST %MOVETO% goto err

REM Backup IIS config before we start changing config to point to the new path
%windir%\system32\inetsrv\appcmd add backup beforeRootMove

REM Stop all IIS services
iisreset /stop

REM Copy all content
REM /O - copy ACLs
REM /E - copy sub directories including empty ones
REM /I - assume destination is a directory
REM /Q - quiet

REM echo on, because user will be prompted if content already exists.
echo on
xcopy %systemdrive%\inetpub %MOVETO%inetpub /O /E /I /Q
@echo off
REM Move AppPool isolation directory
reg add HKLM\System\CurrentControlSet\Services\WAS\Parameters /v ConfigIsolationPath /t REG_SZ /d %MOVETO%inetpub\temp\appPools /f

REM Move logfile directories
%windir%\system32\inetsrv\appcmd set config -section:system.applicationHost/sites -siteDefaults.traceFailedRequestsLogging.directory:"%MOVELOG%inetpub\logs\FailedReqLogFiles"
%windir%\system32\inetsrv\appcmd set config -section:system.applicationHost/sites -siteDefaults.logfile.directory:"%MOVELOG%inetpub\logs\logfiles"
%windir%\system32\inetsrv\appcmd set config -section:system.applicationHost/log -centralBinaryLogFile.directory:"%MOVELOG%inetpub\logs\logfiles"
%windir%\system32\inetsrv\appcmd set config -section:system.applicationHost/log -centralW3CLogFile.directory:"%MOVELOG%inetpub\logs\logfiles"

REM Move config history location, temporary files, the path for the Default Web Site and the custom error locations
%windir%\system32\inetsrv\appcmd set config -section:system.applicationhost/configHistory -path:%MOVETO%inetpub\history
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/asp -cache.disktemplateCacheDirectory:"%MOVETO%inetpub\temp\ASP Compiled Templates"
%windir%\system32\inetsrv\appcmd set config -section:system.webServer/httpCompression -directory:"%MOVETO%inetpub\temp\IIS Temporary Compressed Files"
%windir%\system32\inetsrv\appcmd set vdir "Default Web Site/" -physicalPath:%MOVETO%inetpub\wwwroot
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='401'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='403'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='404'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='405'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='406'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='412'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='500'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='501'].prefixLanguageFilePath:%MOVETO%inetpub\custerr
%windir%\system32\inetsrv\appcmd set config -section:httpErrors /[statusCode='502'].prefixLanguageFilePath:%MOVETO%inetpub\custerr

REM Make sure Service Pack and Hotfix Installers know where the IIS root directories are
reg add HKLM\Software\Microsoft\inetstp /v PathWWWRoot /t REG_SZ /d %mOVETO%\inetpub\wwwroot /f
reg add HKLM\Software\Microsoft\inetstp /v PathFTPRoot /t REG_SZ /d %MOVETO%\inetpub\ftproot /f
REM Do the same for x64 directories
if not "%ProgramFiles(x86)%" == "" reg add HKLM\Software\Wow6432Node\Microsoft\inetstp /v PathWWWRoot /t REG_EXPAND_SZ /d %MOVETO%inetpub\wwwroot /f
if not "%ProgramFiles(x86)%" == "" reg add HKLM\Software\Wow6432Node\Microsoft\inetstp /v PathFTPRoot /t REG_EXPAND_SZ /d %MOVETO%inetpub\ftproot /f

REM Restart all IIS services
iisreset /start
echo.
echo.
echo ===============================================================================
echo Moved IIS7 root directory from %systemdrive%\ to %MOVETO%.
echo.
echo Please verify if the move worked. If so you can delete the %systemdrive%\inetpub directory.
echo If something went wrong you can restore the old settings via
echo     "APPCMD restore backup beforeRootMove"
echo and
echo     "REG delete HKLM\System\CurrentControlSet\Services\WAS\Parameters\ConfigIsolationPath"
echo You also have to reset the PathWWWRoot and PathFTPRoot registry values
echo in HKEY_LOCAL_MACHINE\Software\Microsoft\InetStp.
echo ===============================================================================
echo.
echo.
endlocal
goto success

REM error message if no argument or drive does not exist
:err
echo.
echo New root drive letter required.
echo Here an example how to move the IIS root to the F:\ drive:
echo.
echo MOVEIISROOT.BAT F
echo.
echo.

:success

And, that should do it for Part 2. You’ll want to run this on both Sub CA’s.

Server 2008 Enterprise Subordinate CA Install Scripts

This will cover setting up 2 Enterprise Subordinate CA’s.

Overview

  • Part 1 – Installing ADCS
  • Part 2 – Installing IIS 7
  • Part 3 – Installing DFSR
  • Part 4 – Installing Certificate Web Enrollment Pages
  • Part 5 – Installing CES\CEP
  • Part 6 – Installing an OCSP Responder Array

First Thing’s First

Partition your CA like so:

  • C:\, 25GB, boot
  • D:\, 5GB, cert db
  • E:\, 5GB, logs
  • F:\, 5GB, inetpub
  • G:\, 5GB, DFSR Staging

Start Compiling Scripts

File 1 – capolicy.inf

[Version]
Signature= "$Windows NT$"

[PolicyStatementExtension]
Policies = LegalPolicy
Critical = 0

[LegalPolicy]
URL = "http://certs.chemistry.ohio-state.edu/CertData/cps.docx"

[AuthorityInformationAccess]
Empty = true

[CRLDistributionPoint]
Empty = true

[certsrv_server]
renewalkeylength=4096
RenewalValidityPeriodUnits=5
RenewalValidityPeriod=years
CRLPeriodUnits = 8
CRLPeriod = days
CRLDeltaPeriodUnits = 12
CRLDeltaPeriod = hours
LoadDefaultTemplates=0

File 2 – Setup-IssuingCA1.ps1

This was borrowed from the PowerShell Crypto Guy and slightly modified. You’ll need to change line # 351.

#####################################################################
# SetupCA.ps1
# Version 1.0
#
# This script installs or uninstalls Certification Authority role from the local server
#
# Vadims Podans (c) 2011
# http://en-us.sysadmins.lv/
#####################################################################
#requires -Version 2.0

function Install-CertificationAuthority {
[CmdletBinding(
	DefaultParameterSetName = 'NewKeySet',
	ConfirmImpact = 'None',
	SupportsShouldProcess = $true
)]
	param(
		[Parameter(ParameterSetName = 'NewKeySet')]
		[string]$CAName,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[string]$CADNSuffix,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[ValidateSet("Standalone Root","Standalone Subordinate","Enterprise Root","Enterprise Subordinate")]
		[string]$CAType,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[string]$ParentCA,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[string]$CSP,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[int]$KeyLength,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[string]$HashAlgorithm,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[int]$ValidForYears = 5,
		[Parameter(ParameterSetName = 'NewKeySet')]
		[string]$RequestFileName,
		[Parameter(Mandatory = $true, ParameterSetName = 'PFXKeySet')]
		[IO.FileInfo]$CACertFile,
		[Parameter(Mandatory = $true, ParameterSetName = 'PFXKeySet')]
		[Security.SecureString]$Password,
		[Parameter(Mandatory = $true, ParameterSetName = 'ExistingKeySet')]
		[string]$Thumbprint,
		[string]$DBDirectory,
		[string]$LogDirectory,
		[switch]$OverwriteExisting,
		[switch]$AllowCSPInteraction,
		[switch]$Force
	)

#region OS and existing CA checking
	# check if script running on Windows Server 2008 or Windows Server 2008 R2
	$OS = Get-WmiObject Win32_OperatingSystem -Property Version, ProductType
	if ([int][string]$OS.Version[0] -lt 6 -and $OS.ProductType -ne 1) {
		Write-Error -Category NotImplemented -ErrorId "NotSupportedException" `
		-ErrorAction Stop -Message "Windows XP, Windows Server 2003 and Windows Server 2003 R2 are not supported!"
	}
	$CertConfig = New-Object -ComObject CertificateAuthority.Config
	try {$ExistingDetected = $CertConfig.GetConfig(3)}
	catch {}
	if ($ExistingDetected) {
		Write-Error -Category ResourceExists -ErrorId "ResourceExistsException" `
		-ErrorAction Stop -Message @"
Certificate Services are already installed on this computer. Only one Certification Authority instance per computer is supported.
"@
	}

#endregion

#region Binaries checking and installation if necessary
	try {Import-Module ServerManager -ErrorAction Stop}
	catch {
		ocsetup 'ServerManager-PSH-Cmdlets' /quiet | Out-Null
		Start-Sleep 1
		Import-Module ServerManager -ErrorAction Stop
	}
	$status = (Get-WindowsFeature -Name AD-Certificate).Installed
	# if still no, install binaries, otherwise do nothing
	if (!$status) {$retn = Add-WindowsFeature -Name AD-Certificate -ErrorAction Stop
		if (!$retn.Success) {
			Write-Warning "Unable to install ADCS installation packages due of the following error:"
			Write-Warning $retn.breakCode
		}
	}
	try {$CASetup = New-Object -ComObject CertOCM.CertSrvSetup.1}
	catch {
		Write-Error -Category NotImplemented -ErrorId "NotImplementedException" `
		-ErrorAction Stop -Message "Unable to load necessary interfaces. Your Windows Server operating system is not supported!"
	}
	# initialize setup binaries
	try {$CASetup.InitializeDefaults($true, $false)}
	catch {
		Write-Error -Category InvalidArgument -ErrorId ParameterIncorrectException `
		-ErrorAction Stop -Message "Cannot initialize setup binaries!"
	}
#endregion

#region Property enums
	$CATypesByName = @{"Enterprise Root" = 0; "Enterprise Subordinate" = 1; "Standalone Root" = 3; "Standalone Subordinate" = 4}
	$CATypesByVal = @{}
	$CATypesByName.keys | ForEach-Object {$CATypesByVal.Add($CATypesByName[$_],$_)}
	$CAPRopertyByName = @{"CAType"=0;"CAKeyInfo"=1;"Interactive"=2;"ValidityPeriodUnits"=5;
		"ValidityPeriod"=6;"ExpirationDate"=7;"PreserveDataBase"=8;"DBDirectory"=9;"Logdirectory"=10;
		"ParentCAMachine"=12;"ParentCAName"=13;"RequestFile"=14;"WebCAMachine"=15;"WebCAName"=16
	}
	$CAPRopertyByVal = @{}
	$CAPRopertyByName.keys | ForEach-Object {$CAPRopertyByVal.Add($CAPRopertyByName[$_],$_)}
	$ValidityUnitsByName = @{"years" = 6}
	$ValidityUnitsByVal = @{6 = "years"}
#endregion
	$ofs = ", "
#region Key set processing functions

#region NewKeySet
function NewKeySet ($CAName, $CADNSuffix, $CAType, $ParentCA, $CSP, $KeyLength, $HashAlgorithm, $ValidForYears, $RequestFileName) {

#region CSP, key length and hashing algorithm verification
	$CAKey = $CASetup.GetCASetupProperty(1)
	if ($CSP -ne "" -or $KeyLength -ne 0 -or $HashAlgorithm -ne "") {
		if ($CSP -ne "") {
			if ($CASetup.GetProviderNameList() -notcontains $CSP) {
				# TODO add available CSP list
				Write-Error -Category InvalidArgument -ErrorId "InvalidCryptographicServiceProviderException" `
				-ErrorAction Stop -Message "Specified CSP '$CSP' is not valid!"
			}
			$CAKey.ProviderName = $CSP
		}
		if ($KeyLength -ne 0) {
			if ($CASetup.GetKeyLengthList($CSP).Length -eq 1) {
				$CAKey.Length = $CASetup.GetKeyLengthList($CSP)[0]
			} else {
				if (@($CASetup.GetKeyLengthList($CSP) -notcontains $KeyLength)) {
					Write-Error -Category InvalidArgument -ErrorId "InvalidKeyLengthException" `
					-ErrorAction Stop -Message @"
The specified key length '$KeyLength' is not supported by the selected CSP '$CSP' The following
key lengths are supported by this CSP: $($CASetup.GetKeyLengthList($CSP))
"@
				}
				$CAKey.Length = $KeyLength
			}
		}
		if ($HashAlgorithm -ne "") {
			if ($CASetup.GetHashAlgorithmList($CSP) -notcontains $HashAlgorithm) {
					Write-Error -Category InvalidArgument -ErrorId "InvalidHashAlgorithmException" `
					-ErrorAction Stop -Message @"
The specified hash algorithm is not supported by the selected CSP '$CSP' The following
hash algorithms are supported by this CSP: $($CASetup.GetHashAlgorithmList($CSP))
"@
			}
			$CAKey.HashAlgorithm = $HashAlgorithm
		}
	}

	#$SETUPPROP_Interactive = 2
	$CASetup.SetCASetupProperty(1,$CAKey)
	#$CASetup.SetCASetupProperty($SETUPPROP_Interactive,$false)
#endregion

#region Setting CA type
	if ($CAType) {
		$SupportedTypes = $CASetup.GetSupportedCATypes()
		$SelectedType = $CATypesByName[$CAType]
		if ($SupportedTypes -notcontains $CATypesByName[$CAType]) {
			Write-Error -Category InvalidArgument -ErrorId "InvalidCATypeException" `
			-ErrorAction Stop -Message @"
Selected CA type: '$CAType' is not supported by current Windows Server installation.
The following CA types are supported by this installation: $([int[]]$CASetup.GetSupportedCATypes() | %{$CATypesByVal[$_]})
"@
		} else {$CASetup.SetCASetupProperty($CAPRopertyByName.CAType,$SelectedType)}
	}
#endregion

#region setting CA certificate validity
	if ($SelectedType -eq 0 -or $SelectedType -eq 3 -and $ValidForYears -ne 0) {
		try{$CASetup.SetCASetupProperty(6,$ValidForYears)}
		catch {
			Write-Error -Category InvalidArgument -ErrorId "InvalidCAValidityException" `
			-ErrorAction Stop -Message "The specified CA certificate validity period '$ValidForYears' is invalid."
		}
	}
#endregion

#region setting CA name
	if ($CAName -ne "") {
		if ($CADNSuffix -ne "") {$Subject = "CN=$CAName" + ",$CADNSuffix"} else {$Subject = "CN=$CAName"}
		$DN = New-Object -ComObject X509Enrollment.CX500DistinguishedName
		# validate X500 name format
		try {$DN.Encode($Subject,0x0)}
		catch {
			Write-Error -Category InvalidArgument -ErrorId "InvalidX500NameException" `
			-ErrorAction Stop -Message "Specified CA name or CA name suffix is not correct X.500 Distinguished Name."
		}
		$CASetup.SetCADistinguishedName($Subject, $true, $true, $true)
	}
#endregion

#region set parent CA/request file properties
	if ($CASetup.GetCASetupProperty(0) -eq 1 -and $ParentCA) {
		[void]($ParentCA -match "^(.+)\\(.+)$")
		try {$CASetup.SetParentCAInformation($ParentCA)}
		catch {
			Write-Error -Category ObjectNotFound -ErrorId "ObjectNotFoundException" `
			-ErrorAction Stop -Message @"
The specified parent CA information '$ParentCA' is incorrect. Make sure if parent CA
information is correct (you must specify existing CA) and is supplied in a 'CAComputerName\CASanitizedName' form.
"@
		}
	} elseif ($CASetup.GetCASetupProperty(0) -eq 1 -or $CASetup.GetCASetupProperty(0) -eq 4 -and $RequestFileName -ne "") {
		$CASetup.SetCASetupProperty(14,$RequestFileName)
	}
#endregion
}

#endregion

#region PFXKeySet
function PFXKeySet ($CACertFile, $Password) {
	$FilePath = Resolve-Path $CACertFile -ErrorAction Stop
	try {[void]$CASetup.CAImportPFX(
		$FilePath.Path,
		[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)),
		$true)
	} catch {Write-Error $_ -ErrorAction Stop}
}
#endregion

#region ExistingKeySet
function ExistingKeySet ($Thumbprint) {
	$ExKeys = $CASetup.GetExistingCACertificates() | ?{
		([Security.Cryptography.X509Certificates.X509Certificate2]$_.ExistingCACertificate).Thumbprint -eq $Thumbprint
	}
	if (!$ExKeys) {
		Write-Error -Category ObjectNotFound -ErrorId "ElementNotFoundException" `
		-ErrorAction Stop -Message "The system cannot find a valid CA certificate with thumbprint: $Thumbprint"
	} else {$CASetup.SetCASetupProperty(1,@($ExKeys)[0])}
}
#endregion

#endregion

#region set database settings
	if ($DBDirectory -ne "" -and $LogDirectory -ne "") {
		try {$CASetup.SetDatabaseInformation($DBDirectory,$LogDirectory,$null,$OverwriteExisting)}
		catch {
			Write-Error -Category InvalidArgument -ErrorId "InvalidPathException" `
			-ErrorAction Stop -Message "Specified path to either database directory or log directory is invalid."
		}
	} elseif ($DBDirectory -ne "" -and $LogDirectory -eq "") {
		Write-Error -Category InvalidArgument -ErrorId "InvalidPathException" `
		-ErrorAction Stop -Message "CA Log file directory cannot be empty."
	} elseif ($DBDirectory -eq "" -and $LogDirectory -ne "") {
		Write-Error -Category InvalidArgument -ErrorId "InvalidPathException" `
		-ErrorAction Stop -Message "CA database directory cannot be empty."
	}

#endregion
	# process parametersets.
	switch ($PSCmdlet.ParameterSetName) {
		"ExistingKeySet" {ExistingKeySet $Thumbprint}
		"PFXKeySet" {PFXKeySet $CACertFile $Password}
		"NewKeySet" {NewKeySet $CAName $CADNSuffix $CAType $ParentCA $CSP $KeyLength $HashAlgorithm $ValidForYears $RequestFileName}
	}
	try {
		Write-Host "Installing Certification Authority role on $env:computername ..." -ForegroundColor Cyan
		if ($Force -or $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Install Certification Authority")) {
			$CASetup.Install()
			$PostRequiredMsg = @"
Certification Authority role was successfully installed, but not completed. To complete installation submit
request file '$($CASetup.GetCASetupProperty(14))' to parent Certification Authority
and install issued certificate by running the following command: certutil -installcert 'PathToACertFile'
"@
			if ($CASetup.GetCASetupProperty(0) -eq 1 -and $ParentCA -eq "") {
				Write-Host $PostRequiredMsg -ForegroundColor Yellow -BackgroundColor Black
			} elseif ($CASetup.GetCASetupProperty(0) -eq 1 -and $PSCmdlet.ParameterSetName -eq "NewKeySet" -and $ParentCA -ne "") {
				$SetupStatus = (Get-ItemProperty HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration\$($CASetup.GetCASetupProperty(3))).SetupStatus
				$RequestID = (Get-ItemProperty HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration\$($CASetup.GetCASetupProperty(3))).RequestID
				if ($SetupStatus -ne 1) {
					Write-Host @"
Certification Authority role was successfully installed, but not completed. CA certificate request
was submitted to '$ParentCA' and is waiting for approval. RequestID is '$RequestID'.
Once certificate request is issued, finish the installtion by running the following command:
certutil -installcert 'PathToACertFile'
"@ -ForegroundColor Yellow -BackgroundColor Black
				}
			} elseif ($CASetup.GetCASetupProperty(0) -eq 4) {
				Write-Host $PostRequiredMsg -ForegroundColor Yellow -BackgroundColor Black
			} else {Write-Host "Certification Authority role is successfully installed!" -ForegroundColor Green}
		} else {
			#[void](Remove-WindowsFeature ADCS-Cert-Authority)
		}
	} catch {Write-Error $_ -ErrorAction Stop}
	Remove-Module ServerManager
}

function Uninstall-CertificationAuthority {
[CmdletBinding(
	ConfirmImpact = 'None',
	SupportsShouldProcess = $true
)]
	param(
		[switch]$AutoRestart,
		[switch]$Force
	)

	#region OS and existing CA checking
	# check if script running on Windows Server 2008 or Windows Server 2008 R2
	$OS = Get-WmiObject Win32_OperatingSystem -Property Version, ProductType
	if ([int][string]$OS.Version[0] -lt 6 -and $OS.ProductType -ne 1) {
		Write-Error -Category NotImplemented -ErrorId "NotSupportedException" `
		-ErrorAction Stop -Message "Windows XP, Windows Server 2003 and Windows Server 2003 R2 are not supported!"
	}
	$CertConfig = New-Object -ComObject CertificateAuthority.Config
	try {$ExistingDetected = $CertConfig.GetConfig(3)}
	catch {
		Write-Error -Category ObjectNotFound -ErrorId "ElementNotFoundException" `
		-ErrorAction Stop -Message "Certificate Services are not installed on this computer."
	}
#endregion

#region Binaries checking and removal stuff
	try {$CASetup = New-Object -ComObject CertOCM.CertSrvSetup.1}
	catch {
		Write-Error -Category NotImplemented -ErrorId "NotImplementedException" `
		-ErrorAction Stop -Message "Unable to load necessary interfaces. Your Windows Server operating system is not supported!"
	}
	try {Import-Module ServerManager -ErrorAction Stop}
	catch {
		ocsetup 'ServerManager-PSH-Cmdlets' /quiet | Out-Null
		Start-Sleep 1
		Import-Module ServerManager
	}
	$status = (Get-WindowsFeature -Name ADCS-Cert-Authority).Installed
	if ($status) {
		$WarningPreference = "SilentlyContinue"
		if ($Force -or $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Uninstall Certification Authority")) {
			$CASetup.PreUninstall($false)
			$retn = Remove-WindowsFeature -Name ADCS-Cert-Authority -ErrorAction Stop
			if ($retn.RestartNeeded -and $AutoRestart) {
				Restart-Computer -Force
			} else {
				Write-Host @"
Certification Authority role was removed successfully. You must restart this server to complete role removal.
"@ -ForegroundColor Yellow -BackgroundColor Black
			}
		}
	}
	Remove-Module ServerManager
#endregion
}

Install-CertificationAuthority -CAName "<yourOrg> Issuing CA1" -CSP "RSA#Microsoft Software Key Storage Provider" -CADNSuffix "dc=<yourdomain>,dc=<yourTLD>" -CAType "Enterprise Subordinate" -HashAlgorith SHA256 -DBDirectory "D:\db-cert" -LogDirectory "E:\log-cert"

# SIG # Begin signature block
# MIIQWAYJKoZIhvcNAQcCoIIQSTCCEEUCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU6RpjkQVJAvylqYv5JlJjJ1f0
# 2IGgggwdMIIDejCCAmKgAwIBAgIQOCXX+vhhr570kOcmtdZa1TANBgkqhkiG9w0B
# AQUFADBTMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xKzAp
# BgNVBAMTIlZlcmlTaWduIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EwHhcNMDcw
# NjE1MDAwMDAwWhcNMTIwNjE0MjM1OTU5WjBcMQswCQYDVQQGEwJVUzEXMBUGA1UE
# ChMOVmVyaVNpZ24sIEluYy4xNDAyBgNVBAMTK1ZlcmlTaWduIFRpbWUgU3RhbXBp
# bmcgU2VydmljZXMgU2lnbmVyIC0gRzIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
# AoGBAMS18lIVvIiGYCkWSlsvS5Frh5HzNVRYNerRNl5iTVJRNHHCe2YdicjdKsRq
# CvY32Zh0kfaSrrC1dpbxqUpjRUcuawuSTksrjO5YSovUB+QaLPiCqljZzULzLcB1
# 3o2rx44dmmxMCJUe3tvvZ+FywknCnmA84eK+FqNjeGkUe60tAgMBAAGjgcQwgcEw
# NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC52ZXJpc2ln
# bi5jb20wDAYDVR0TAQH/BAIwADAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3Js
# LnZlcmlzaWduLmNvbS90c3MtY2EuY3JsMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMI
# MA4GA1UdDwEB/wQEAwIGwDAeBgNVHREEFzAVpBMwETEPMA0GA1UEAxMGVFNBMS0y
# MA0GCSqGSIb3DQEBBQUAA4IBAQBQxUvIJIDf5A0kwt4asaECoaaCLQyDFYE3CoIO
# LLBaF2G12AX+iNvxkZGzVhpApuuSvjg5sHU2dDqYT+Q3upmJypVCHbC5x6CNV+D6
# 1WQEQjVOAdEzohfITaonx/LhhkwCOE2DeMb8U+Dr4AaH3aSWnl4MmOKlvr+ChcNg
# 4d+tKNjHpUtk2scbW72sOQjVOCKhM4sviprrvAchP0RBCQe1ZRwkvEjTRIDroc/J
# ArQUz1THFqOAXPl5Pl1yfYgXnixDospTzn099io6uE+UAKVtCoNd+V5T9BizVw9w
# w/v1rZWgDhfexBaAYMkPK26GBPHr9Hgn0QXF7jRbXrlJMvIzMIIDxDCCAy2gAwIB
# AgIQR78Zld+NUkZD99ttSA0xpDANBgkqhkiG9w0BAQUFADCBizELMAkGA1UEBhMC
# WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUx
# DzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x
# HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNMDMxMjA0MDAwMDAw
# WhcNMTMxMjAzMjM1OTU5WjBTMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNp
# Z24sIEluYy4xKzApBgNVBAMTIlZlcmlTaWduIFRpbWUgU3RhbXBpbmcgU2Vydmlj
# ZXMgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpyrKkzM0grwp9
# iayHdfC0TvHfwQ+/Z2G9o2Qc2rv5yjOrhDCJWH6M22vdNp4Pv9HsePJ3pn5vPL+T
# rw26aPRslMq9Ui2rSD31ttVdXxsCn/ovax6k96OaphrIAuF/TFLjDmDsQBx+uQ3e
# P8e034e9X3pqMS4DmYETqEcgzjFzDVctzXg0M5USmRK53mgvqubjwoqMKsOLIYdm
# vYNYV291vzyqJoddyhAVPJ+E6lTBCm7E/sVK3bkHEZcifNs+J9EeeOyfMcnx5iIZ
# 28SzR0OaGl+gHpDkXvXufPF9q2IBj/VNC97QIlaolc2uiHau7roN8+RN2aD7aKCu
# FDuzh8G7AgMBAAGjgdswgdgwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhho
# dHRwOi8vb2NzcC52ZXJpc2lnbi5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADBBBgNV
# HR8EOjA4MDagNKAyhjBodHRwOi8vY3JsLnZlcmlzaWduLmNvbS9UaGF3dGVUaW1l
# c3RhbXBpbmdDQS5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgEGMCQGA1UdEQQdMBukGTAXMRUwEwYDVQQDEwxUU0EyMDQ4LTEtNTMwDQYJKoZI
# hvcNAQEFBQADgYEASmv56ljCRBwxiXmZK5a/gqwB1hxMzbCKWG7fCCmjXsjKkxPn
# BFIN70cnLwA4sOTJk06a1CJiFfc/NyFPcDGA8Ys4h7Po6JcA/s9Vlk4k0qknTnqu
# t2FB8yrO58nZXt27K4U+tZ212eFX/760xX71zwye8Jf+K9M7UhsbOCf3P0owggTT
# MIIDu6ADAgECAgphPJ1VAAAAAAATMA0GCSqGSIb3DQEBBQUAMHIxCzAJBgNVBAYT
# AkxWMRUwEwYDVQQKEwxTeXNhZG1pbnMgTFYxHDAaBgNVBAsTE0luZm9ybWF0aW9u
# IFN5c3RlbXMxLjAsBgNVBAMTJVN5c2FkbWlucyBMViBJbnRlcm5hbCBDbGFzcyAx
# IFN1YkNBLTEwHhcNMTAwNDE1MTc0MDU2WhcNMTUwNDE0MTc0MDU2WjBaMQswCQYD
# VQQHEwJMVjEVMBMGA1UEChMMU3lzYWRtaW5zIExWMRwwGgYDVQQLExNJbmZvcm1h
# dGlvbiBTeXN0ZW1zMRYwFAYDVQQDEw1WYWRpbXMgUG9kYW5zMIIBIjANBgkqhkiG
# 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhzDxXkGOfXVksAb8aGJD7LsISli39npqUVB2
# QE09Ie5YwL55s9RCASTLnsk56j0N5dS/z6s7E63W2Gm0QMQhnm0lAeFLEsR+jEtI
# dAKSfg6ZBeTqr9RlZ++S2/veTZGr7F22+YwVMfjGq+F11WZrox4oQFY+7lRGFPvC
# +cj5waHlN4TySYSur8TaFUg55nWvzkgLWdoGJXhXEkwxCR4+zAFNgIByNgJPVRTw
# aKER2Crx0KU2awTZr91g2hOS3EgZSTbAWc/+m1IS2uXOFzMprlYOUZ64zHraV9G5
# N/Or6A7OTgkOV653o0+qoiKOH+JgFL6on7gZ7Fg8vTBkJ1M9VQIDAQABo4IBgTCC
# AX0wOwYJKwYBBAGCNxUHBC4wLAYkKwYBBAGCNxUIlp1NhZKyeL2fPIXo7HSCzthE
# eoKq90KH58Q2AgFkAgEDMB8GA1UdJQQYMBYGCisGAQQBgjcKAwwGCCsGAQUFBwMD
# MA4GA1UdDwEB/wQEAwIHgDApBgkrBgEEAYI3FQoEHDAaMAwGCisGAQQBgjcKAwww
# CgYIKwYBBQUHAwMwHQYDVR0OBBYEFCx12lrTtrk1gAKUsuYvMaIr11eZMB8GA1Ud
# IwQYMBaAFBv6XnMtZxNcztMO5uh6qWCMC2P8MDcGA1UdHwQwMC4wLKAqoCiGJmh0
# dHA6Ly93d3cuc3lzYWRtaW5zLmx2L3BraS9waWNhLTEuY3JsMGkGCCsGAQUFBwEB
# BF0wWzAyBggrBgEFBQcwAoYmaHR0cDovL3d3dy5zeXNhZG1pbnMubHYvcGtpL3Bp
# Y2EtMS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnN5c2FkbWlucy5sdi8w
# DQYJKoZIhvcNAQEFBQADggEBAEnZsZtm77dP7Rklc5NKNB9d8BwHPOocz5HXpSnq
# peSNSdCCC4g1P/Uq2qvfLtJ08aTIdnK2rPQAHCv+GBnVt2XhZpX3GnLigmeLvBTg
# aroyHxDO+EbCtCZCJ9tHK6Yz8QozPJhlT4qQPtMAeg3UKIQaGITIr705VpA3EDHA
# 7eOZZY1yPZDzpitXuv5fOQBT83qBJ5VReKLl4YDfTBA2cJZB3ZxPMv20d00fy3io
# o30uGKO3QSjEYRlgYOeJE6YhiUjBlSPqdT9eyZ4fInm+ly8HG7XYBVAw0hRj4fMI
# tK0qcLJJ3WG2YkF6aVpqbQ495intBJQqDDObX6ArzXcZTMoxggOlMIIDoQIBATCB
# gDByMQswCQYDVQQGEwJMVjEVMBMGA1UEChMMU3lzYWRtaW5zIExWMRwwGgYDVQQL
# ExNJbmZvcm1hdGlvbiBTeXN0ZW1zMS4wLAYDVQQDEyVTeXNhZG1pbnMgTFYgSW50
# ZXJuYWwgQ2xhc3MgMSBTdWJDQS0xAgphPJ1VAAAAAAATMAkGBSsOAwIaBQCgeDAY
# BgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3
# AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEW
# BBSMurp7qXyd3UA8Ez004qsUpHM+njANBgkqhkiG9w0BAQEFAASCAQAdtRo8iDBm
# 7NZwJiPxCSn2iTOKUD/nqsiRyHLwsRhSlq82dOG8t2+zC96Q+LadIDrUPExAIv10
# jRRgg82pDyNEtE48Vmo8iF2hLRD6vq9F4mfRQQ6c3WH1wz52lfKZj81ygSS88noA
# DA36W3rxCI3AdGYT24GMcOPvu/flNw6ujpLRnCAZcBQ8zOf/VW0sB3jsHD4mcwBs
# Pm7G/113uUrvH/eQp0ScWrIpcIHxcIYJH8Xw7lmRAEyCQwcoyvmil7pID6qy85pY
# JiIt7JNci8zjl6CrXDFT77WgD8xQLUpMfiy3cWsKP0j0Fym3KklF9VdmnhG1dkmz
# hofF1ATpyTqwoYIBfzCCAXsGCSqGSIb3DQEJBjGCAWwwggFoAgEBMGcwUzELMAkG
# A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMSswKQYDVQQDEyJWZXJp
# U2lnbiBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIENBAhA4Jdf6+GGvnvSQ5ya11lrV
# MAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3
# DQEJBTEPFw0xMTExMjEyMjQzNTlaMCMGCSqGSIb3DQEJBDEWBBQFn3Csp8NhmDuH
# 0rMbIJiyovaXxTANBgkqhkiG9w0BAQEFAASBgDuq2Jjo3E46gSK8X3ozHHr0uwqy
# 14vsILPss3KkiIffmBX+gTf+mPf3vbKg5IpwKk+JTAFrpHzQ+mbt1UVhXrhuMgrM
# nZftNparWOJ1XMuwTJiQYc0buZmX6tDDN44tI9cddIVbe10+CTqYLMIn+GvGRdix
# uXo+j2kopK1nQHcw
# SIG # End signature block

File 3 – Install-ADCS.cmd

You’ll need to add your FQDN, AIA, and CDP\OCSP locations by modifying lines 9, 20, and 23. This was borrowed from Brian Komar’s excellent book “Windows Server 2008 PKI and Certificate Security“. Go buy it if you can! Ebay is really the only place, or Safari Tech.

if not exist D:\db-cert mkdir D:\db-cert
if not exist E:\log-cert mkdir E:\log-cert

copy /y capolicy.inf %windir%

PowerShell -ExecutionPolicy bypass -file .\SetupCA-IssuingCA1.ps1

rem Declare Configuration NC
certutil -setreg CA\DSConfigDN CN=Configuration,DC=<yourDomain>,DC=<yourTLD>

rem Define CRL Publication Intervals
certutil -setreg CA\CRLPeriodUnits 8
certutil -setreg CA\CRLPeriod "Days"
certutil -setreg CA\CRLOverlapUnits 1
certutil -setreg CA\CRLOverlapPeriod "Days"
certutil -setreg CA\CRLDeltaPeriodUnits 12
certutil -setreg CA\CRLDeltaPeriod "Hours"

REM Apply the required CDP Extension URLs
certutil -setreg CA\CRLPublicationURLs "65:%windir%\system32\CertSrv\CertEnroll\%%3%%8%%9.crl\n65:F:\inetpub\wwwroot\certdata\%%3%%8%%9.crl\n6:http://cdp.<yourdomain>.com/Certdata/%%3%%8%%9.crl\n6:http://ca1.<yourdomain>.com/Certdata/%%3%%8%%9.crl\n6:http://ca2.<yourdomain>.com/Certdata/%%3%%8%%9.crl"

REM Apply the required AIA Extension URLs
certutil -setreg CA\CACertPublicationURLs  "1:%windir%\system32\CertSrv\CertEnroll\%%1_%%3%%4.crt\n1:F:\inetpub\wwwroot\certdata\%%1_%%3%%4.crt\n2:http://aia.<yourdomain>.com/CertData/%%1_%%3%%4.crt\n2:http://ca1.<yourdomain>.com/CertData/%%1_%%3%%4.crt\n2:http://ca2.<yourdomain>.com/CertData/%%1_%%3%%4.crt\n32:http://%%1/ocsp"

rem Enable all auditing events for the Issuing CA
certutil -setreg CA\AuditFilter 127

rem  Enable discrete signatures in issued certificates
Certutil –setreg CA\csp\DiscreteSignatureAlgorithm 1

rem Set Maximum Validity Period for Issued Certificates
certutil -setreg CA\ValidityPeriodUnits 5
certutil -setreg CA\ValidityPeriod "Years"

rem Restart Certificate Services
net stop certsvc
net start certsvc

OK, if you run ‘Install-ADCS.cmd’ you should be in business. Then, modify the CA friendly name in line #351 of file 2, and run it on the 2nd CA. Check back for Part 2!