The Problem

A Windows 8 machine has a certificate that is used by an application. Auto enrollment will renew the certificate when it is near its expiration period. However, applications that are bound to the old certificate do not "know" about the new certificate. These applications may fail if they continue to use the old certificate.

The Solution

A custom powershell script can be registered to execute at the time the renewal takes place. This custom script can re-configure the application to use the new certificate.

How Can I Do It? [Short Version]

To get you started with a very basic script to see how the feature works, do the following:

  1. Create the following powershell script in c:\notification_scripts called ReplaceCertificate.ps1 which will run when a certificate gets renewed:

    param([string]$OldCertHash, [string]$NewCertHash)

    $FileName = "Replace_" + $OldCertHash + "_" + $NewCertHash

    Set-Content -Path c:\notification_scripts\$FileName -Value "Replace $OldCertHash with $NewCertHash"

    This script will create a file in the c:\notification_scripts folder whose name is the hash of the old certificate followed by an "_" followed by the hash of the new certificate.

  2. Depending on the execution policy in your powershell environment this script may not run. For now, run the following from an elevated command prompt:

    Set-ExecutionPolicy Unrestricted

    Later, you will see how to avoid this [see Fine Tuning section]

  3. Run the following cmdlet to setup notifications for a user certificate:

    New-CertificateNotificationTask -type Replace -PSScript c:\notification_scripts\ReplaceCertificate.ps1 -Name "ReplaceNotification" -Channel User

    Using certmgr, enroll for a certificate for the user. And then renew it.

  4. In the c:\notification_scripts folder you should observe a file called Replace_<OldHash>_<NewHash>
    This indicates that the script from step 1 executed.

What Other Notifications Exist?

The New-CertificateNotificationTask cmdlet allows you to setup a notification for certificates that get renewed. You can also use this cmdlet to setup a notification for certificates that are expiring or are expired. Use the "-Type" parameter in the cmdlet to change between Replace [which covers renew] or Expire [which covers expiring or expired].

There are also other notifications such as:

  • "New" which indicates a newly enrolled certificate.
  • "Delete" which indicates a certificate has been removed.
  • "Archival" which indicates autoenrollment has archived a certificate.
  • "Export" which indicates a certificate has been exported together with its private key

How It Works?

Two new event logs were created:

  • "Applications and Service Logs\Microsoft\Windows\CertificateServicesClient-Lifecycle-User" for user events
  • "Applications and Service Logs\Microsoft\Windows\CertificateServicesClient-Lifecycle-System" for system events

The enrollment code was modified to write events into the Operation channel in these event logs. Some events are:

  • Event ID 1001 describes a certificate being replaced. The event details has relevant information like the old and new thumbprints.
  • Event ID 1004 describes a certificate being deleted. The event details has relevant information like the thumbprint.
  • Event ID 1005 describes a certificate being archived. The event details has relevant information like the thumbprint and context.
  • Event ID 1006 describes a new certificate being installed. The event details also has relevant information like thumbprint and context.
  • Event ID 1007 describes a certificate being exported with its private key. The event details has relevant information like the thumbprint.

The task scheduler [type: taskschd.msc from command line to see it] can monitor the event log for these events and execute powershell on a particular script. The New-CertificateNotificationTask cmdlet creates a task in task scheduler. You can fine tune the task by editing it using the task scheduler interface. Alternatively, if you have other monitoring software you can invoke it using task scheduler as well based off these events. See the diagram below for a visual summary:

 

Fine Tuning Tasks

In some environments powershell scripts cannot be executed. For instance, the default execution policy is set to Restricted which means powershell scripts cannot run.  You may want to run these notification scripts, but not change the environment execution policy. You can do this with a little fine tuning on the task scheduler. You will need to have a task already configured using the New-CertificateNotificationTask cmdlet :

  • Open Task Scheduler [run: taskschd.msc]
  • Expand "Task Scheduler Library"
  • Expand "Microsoft" and then "Windows" and "CertificateServicesClient" and "Notification"
  • Select the task that shows up on the right hand side window. Right click and choose Properties.
  • Choose the "Actions" tab
  • You should see the action is to start a program and the details is to start powershell. Click the "Edit..." button to modify this line
  • You can modify the program, and you can also add arguments. Add the following argument: -ExecutionPolicy Unrestricted
  • Click "Ok"

Now, you can have your machine powershell environment still be Restricted, but this task will run in Unrestricted.

You can also fine tune the task to run something other than powershell.

What Is A Real World Example?

IIS SSL Bindings

You can run your default website using an ssl server certificate. IIS will maintain the binding between the website and the ssl server certificate. You can see your bindings in powershell:

dir iis:\sslbindings | format-list *

If any certificate is renewed, IIS will not be notified to update its bindings. The SSL stack will do its best to find the latest renewed certificate based on what is configured in the IIS binding. Essentially, the SSL stack will "walk the renewal chain".

An alternative, is to configure a script that runs when a certificate is renewed. This script will see if there are any IIS bindings using the old certificate and update the bindings appropriately.  Here is the script:

param([string]$OldCertHash, [string]$NewCertHash)

import-module webadministration

$bindings = dir IIS:\SslBindings | where {$_.Thumbprint -eq $oldCertHash}
# String comparison is case-insensitive

$newCert = dir “cert:\LocalMachine\My\$newCertHash”

$bindings | ForEach-Object { del $_.PSPath; $newCert | new-item $_.PSPath;}

Save this to a file: c:\scripts\replace.ps1
Then run this cmdlet:

New-CertificateNotificationTask -Type Replace -PSScript c:\scripts\replace.ps1 -Name ReplaceCertificateInIIS -Channel System

 

Credit: Thanks to Alex Radutskiy and Haitao Li