Hello S-1-1-0!
In previous post we gave an introduction into techniques to work with certificate revocation lists in PowerShell. We explored common steps to read CRL’s basic information, CRL extensions and revoked certificate collection. Today I will discuss about CRL handy shortcuts and signature validation.
In some environments, it is impossible to automatically copy CRLs from CA server to CRL distribution points or there is a scenario when PKI administrators run custom scripts to monitor CRL health status at CRL distribution points and update them if they are about to expire. For such purposes I maintain two shortcut methods to quickly identify required values.
CRL validity is determined by a NextUpdate field. If the current time passes that timestamp, the CRL is considered expired. To provide better validity handling, Microsoft use their own Next CRL Publish CRL extension. This extension contains a date/time value at which CA will issue new CRL. This value (when present) is always set prior to value in NextUpdate field to provide a time window to replicate newly published CRL across all distribution points prior existing CRLs expire. I have a good article on this subject: How ThisUpdate, NextUpdate and NextCRLPublish are calculated (v2). However, Next CRL Publish extension is presented in CRLs issued by Microsoft CAs and is absent in 3rd party CAs, as the result, next CRL publication date is determined solely by Next Update field. Moreover, there might be a case when CA is in the decommission process and issues its last CRL which is supposed to be valid infinitely.
To simplify all these validations, I developed a GetNextPublish method. The logic of this method is as follows:
PS C:\> $crl.GetNextPublish() otrdiena, 2016. gada 25. oktobri 20:00:00 PS C:\>
For monitoring purposes you may want to compare CRL numbers (they are numbered sequentially) across all CRL distribution points with a base value (for example, retrieved from CA database). This will ensure that there are no stale CRLs especially when CRL was published manually. For such purposes, I maintain a GetCRLNumber method:
PS C:\> $crl.GetCRLNumber() 349
If the CRL Number extension is absent, then zero value is returned, because such CRLs doesn’t have CRL numbering capabilities. This is the case for Version 1 CRLs, or non-conformant CAs.
Let’s take a look into our CRL (from DigiCert):
PS C:\> $crl Version : 2 Type : Base CRL IssuerName : System.Security.Cryptography.X509Certificates.X500DistinguishedName Issuer : CN=DigiCert SHA2 Secure Server CA, O=DigiCert Inc, C=US ThisUpdate : 2016.10.18. 20:14:33 NextUpdate : 2016.10.25. 20:00:00 SignatureAlgorithm : 1.2.840.113549.1.1.11 (sha256RSA) Extensions : {2.5.29.35 (Authority Key Identifier), 2.5.29.20 (CRL Number), 2.5.29.28 (Issuing Distribution Po int)} RevokedCertificates : {Serial number: 0c587cfa9bf443daeab70526d4bc009f revoked at: 2015.11.06. 21:57:32, Serial number: 0b3ba5097ac6f59b551a1338357a0981 revoked at: 2015.11.09. 11:22:51, Serial number: 0e213e45ff44bd 975d6d22cbb8a40f2d revoked at: 2015.11.09. 19:21:01, Serial number: 08d64d9f888feee694b32d06bba9f b83 revoked at: 2015.11.09. 19:22:03...} RawData : {48, 131, 4, 111...} Handle : 0 PS C:\>
Here we see a SignatureAlgorithm property that stores the information about signature algorithm (captain obvious is here too). This information is used to validate the signature against issuer. Let’s take proper and invalid issuer certificates:
PS C:\> $issuer = New-Object Security.Cryptography.X509Certificates.X509Certificate2 C:\Certs\DigiCertSHA2SecureServerCA .cer PS C:\> $nonissuer = New-Object Security.Cryptography.X509Certificates.X509Certificate2 C:\Certs\verisign.cer PS C:\> $issuer Thumbprint Subject ---------- ------- 1FB86B1168EC743154062E8C9CC5B171A4B7CCB4 CN=DigiCert SHA2 Secure Server CA, O=DigiCert Inc, C=US PS C:\> $nonissuer Thumbprint Subject ---------- ------- A5EC73D48C34FCBEF1005AEB85843524BBFAB727 OU=Class 2 Public Primary Certification Authority, O="VeriSign, Inc.", C=US PS C:\>
And try to use both certificates to validate signature:
PS C:\> $crl.VerifySignature($issuer,$true) True PS C:\> $crl.VerifySignature($nonissuer,$true) False PS C:\>
We can observe that DigiCert is the issuer of this CRL, while VeriSign is not. Plain and simple. VerifySignature method accepts two arguments: an instance of X509Certificate2 class and boolean value that indicates whether to perform CRL issuer name validation along with raw signature validation. In this case, SubjectName field of the issuer (or candidate at that point) is compared with IssuerName property of the CRL. Moreover, binary comparison is performed. This was made to be compatible with RFC3280 (although, obsolete, but still in use) which requires binary match. RFC5280 allows case-insensitive string match.
When using CRLs in your code to validate revocation status, do not forget to validate CRL signature as this will make your code more reliable and trustworthy.
Currently, VerifySignature supports RSA, DSA and ECDSA signatures. Alternate signature algorithms (RSASSA-PSS) are not yet supported, but I do have plans to add support of alternate signature formats.
In the past, I used CryptoAPI native functions (through p/invoke) to decode CRL objects. Since I have a reliable and very robust ASN.1 parser, I moved CRL decoder to a fully managed .NET code without using a piece of unmanaged code. As the result, normally you don’t need to dispose CRL object in order to release unmanaged resources and prevent memory leaks. However, there might be a need to get an unmanaged reference to CRL object. For such purposes I maintain a Handle property that contains a reference to a CRL object in unmanaged memory. Normally, it is zero:
PS C:\> $crl.Handle 0
If you need an unmanaged reference, call GetSafeContext method. This method will copy CRL object into unmanaged memory and retrieve a pointer to that memory block:
PS C:\> $crl.GetSafeContext() IsInvalid IsClosed --------- -------- False False PS C:\> $crl.Handle 489363296
Now, you can use this handle to pass into unmanaged functions. For example, into CertAddCRLContextToStore function to add CRL into Windows Certificate Store. When CRL handle is populated, it must be freed after you finish working with CRL object by calling ReleaseContext method:
PS C:\> $crl.ReleaseContext() PS C:\> $crl.Handle 0 PS C:\>
The difference between ReleaseContext and Reset methods is simple: ReleaseContext releases only unmanaged resources, while keeping managed object alive. If there are no unmanaged resources associated with the current object, the method does nothing (no errors are thrown). Reset method releases unmanaged resources (if necessary) and clears managed object by clearing all fields and setting them to default null/empty values.
That’s all for today. In next post, I’ll talk about CRL generation in PowerShell, so stay tuned!
Post your comment:
Comments: