CRL's and PowerShell

Many systems administrators asks about dealing with CRLs (Certificate Revocation List) in Windows PowerShell. Some time ago the answer was — PowerShell can't natively work with CRLs because there are no any managed API (both in .NET and CryptoAPI COM), so you was unable to wrap these classes/interfaces to PowerShell. Hopefully there are 3rd party library in Mono (open-source .NET reference). However this just adds API and nothing else. For more complete PowerShell solution we need to get a cmdlet form. Fortunately Quest Software was first who developed cmdlets for PKI management. You can download them from the link:

Currently there are cmdlets for client certificate/CRL management only. You may ask: we have great certutil.exe, so why we need to search for native PowerShell solution? Yeah, certutil.exe is great cmd utility, but when we want to automate certain tasks, we will have to parse quite complex certutil output. By using PowerShell we can dramatically simplify this job by working with well-known objects.

At first you need to install Quest AD cmdlets, open PowerShell console and type:

Add-PSSnapin Quest.ActiveRoles.ADManagement

now you can use new cmdlets. In order to import CRL from a file or other data source (binary array) you need to use Import-QADCertificateRevocationList cmdlet:

PS C:\> $crl = Import-QADCertificateRevocationList -File C:\pica-1.crl
PS C:\> $crl | fl *

Version            : CRL_V2
SignatureAlgorithm : 1.2.840.113549.1.1.5 (sha1RSA)
Issuer             : CN=Sysadmins LV Internal Class 1 SubCA-1, OU=Information Systems, O=Sysadmins LV, C=LV
IssuedBy           : Sysadmins LV Internal Class 1 SubCA-1
Number             : 288
BaseNumber         :
CertificateIndex   : 0
KeyIndex           : 0
Type               : Base
EffectiveDate      : 2010.09.06. 8:20:24
NextUpdate         : 2010.09.10. 8:40:24
NextPublish        : 2010.09.09. 8:30:24
Entries            : {Quest.ActiveRoles.ArsPowerShellSnapIn.Interop.CRLEntry, Quest.ActiveRoles.ArsPowerShellSnapIn.Int
                     erop.CRLEntry, Quest.ActiveRoles.ArsPowerShellSnapIn.Interop.CRLEntry}
RawData            : {48, 130, 2, 179...}

PS C:\>

you see imported CRL object that is similar as you see in GUI. Let me explain several properties:

  • CertificateIndex — this property represents 'CA Version' extension major number. CA Version extension uses the following format: CACertNumber.CAKeyNumber. When you renew CA certificate by using existing key pair, the CACertNumber value is increased by 1 and the value will 1.0, 2.0, 3.0, etc. For more details please refer to the following article: Certification Authority Renewal.
  • KeyIndex — this property represents 'CA Version' extension minor value. When you renew CA certificate by using new key pair, CAKeyNumber increased to the CACertNumber value: 1.1, 2.2, 3.3, etc. For more details please refer to the following article: Certification Authority Renewal.
  • RawData — contains CRL object in native DER-encoded byte array format. You may use this property for any custom external means.

EffectiveDate, NextUpdate and NextPublish are stored as a native System.DateTime objects:

PS C:\> $crl.NextPublish

ceturtdiena, 2010. gada 9. septembrī 8:30:24

PS C:\> $crl.NextPublish | fl *

DateTime    : ceturtdiena, 2010. gada 9. septembrī 8:30:24
Date        : 2010.09.09. 0:00:00
Day         : 9
DayOfWeek   : Thursday
DayOfYear   : 252
Hour        : 8
Kind        : Local
Millisecond : 0
Minute      : 30
Month       : 9
Second      : 24
Ticks       : 634196178240000000
TimeOfDay   : 08:30:24
Year        : 2010

PS C:\>

so you see that PowerShell is extremely powerful for date and time parsing. You may select required CRLs based on various time filters. In order to review revoked certificate list you just need to explore Entries property:

PS C:\> $crl.Entries | ft -a

SerialNumber         Reason RevocationDate
------------         ------ --------------
540000000000E0261741        2010.08.04. 21:26:00
2B0000000000202EEE1C        2010.05.01. 15:32:00
2100000000005AAFE02E        2010.04.24. 22:25:00

The output is self-explanatory so there is no need in comments.

We get CRL object and what we can do with it? We can do various actions. The following command will add this CRL object to local certificate store:

PS C:\> # at first we need to retrieve required container where we want to import our CRL object
PS C:\> $store = Get-QADLocalCertificateStore -StoreLocation CurrentUser -StoreName CA
PS C:\> # and add CRL to the container
PS C:\> Add-QADCertificateRevocationList -CRL $crl -Store $store

Type    Number   BaseNumber   KeyIndex     EffectiveDate   NextUpdate      Entries  Issuer
----    ------   ----------   --------     -------------   ----------      -------  ------
Base    288                   0            2010.09.06.     2010.09.10.     3        CN=Sysadmins LV Internal Class 1...

PS C:\> # check if the operation was completed successfully
PS C:\> Get-QADLocalCertificateStore CA CurrentUser | Get-QADCertificateRevocationList | ft -a

Type Number BaseNumber KeyIndex EffectiveDate NextUpdate  Entries Issuer
---- ------ ---------- -------- ------------- ----------  ------- ------
Base 288               0        2010.09.06.   2010.09.10. 3       CN=Sysadmins LV Internal Class 1 SubCA-1, OU=Infor...
Base 0                          2001.03.24.   2004.01.08. 3       OU=VeriSign Commercial Software Publishers CA, O="...

PS C:\>

Tip: to hide unnecessary cmdlet output you may add '| Out-Null' after any command. In order to remove this CRL from local store you need to use Remove-QADCertificateRevocationList cmdlet as follows:

$store = Get-QADLocalCertificateStore CA CurrentUser
Get-QADCertificateRevocationList -Store $store | ?{$_.IssuedBy -like "sysadmins*"} | Remove-QADCertificateRevocationList -Store $store

You can export this CRL back to a file by using Export-QADCertificateRevocationList cmdlet:

PS C:\> Export-QADCertificateRevocationList -CRL $crl -File c:\customcrl.crl
-----BEGIN X509 CRL-----
-----END X509 CRL-----

PS C:\>

By default this cmdlet exports CRL in Base64 encoding with X.509 CRL headers and footers. In order to export the CRL in a DER-encoded binary array format you may use –Encodig parameter:

Export-QADCertificateRevocationList -CRL $crl -File c:\customcrl.crl -Encoding Binary | Out-Null

In addition you may publish CRL to the Active Directory (similar as 'certutil –dspublish)' as follows:

Publish-QADCertificateRevocationList -CRL $crl -CAName CustomCAName

Note that –CAName parameter is mandatory and specifies CA server short (or NetBIOS name). This name is used to create subcontainer under CN=CDP,CN=Public Key Services, CN=Services, CN=Configuration, DC=ForestRootDomain. In order to unpublish the CRL from Active Directory the following syntax may be used:

Get-QADPKIObject CDP | Get-QADCertificateRevocationList | ?{$_.IssuedBy -like "sysadmins*"} | Unpublish-QADCertificateRevocationList -CAName "CustomCAName"

At first we retrieve CRLs from Active Directory by using Get-QADPKIObject cmdlet. As we are dealing with CRLs we need to specify 'CDP' container that contains AD published CRLs. After that we filter output CRL's by using custom filters (in our case we retreive any CRLs are issued by CA where name starts with 'sysadmins' keyword) and then we use Unpublish-QADCertificateRevocationList to delete selected CRLs from AD. If selected CRLs are the last in the subcontainer (under CDP container) you may decide to remove empty subcontainer you need to use –Force switch. If subcontainer still contains published CRLs the –Force switch will not affect.

I wrote Guide for Using Quest AD-PKI cmdlets (Note: registration required), so you may refer to the guide for additional information about Quest AD cmdlet usage and certificate fundamentals.