One of my customers is using 3rd party Card Management System (CMS) to manage their smart cards. One of many common management tasks that such systems perform is revocation of the smart card and in particular the certificates issued to the given smart card. Well, of course CMS only originates the revocation request - the actual revocation is performed on CA that issued certificates. Certificates can be revoked for different reasons and when you revoke it is good idea to specify the reason code for revocation. Some implementations require that the reason code is specified, and some implementations require that this reason code must be set to "key compromise". If you do not specify the reason code during revocation then it will be set to the default reason code which is "unspecified".
So this particular CMS does not specify the reason code when it sends revocation requests to CA. At the same time customer Security Policy dictates that all subscriber certificates will be revoked with "key compromise" reason code.
As I mention before the default revocation reason code for Windows 2003 CA is "unspecified". It is not possible to change the default setting to any other reason code.
Since CMS doesn't specify the reason code for revocation all revoked certificates by this CMS are revoked with the reason code "unspecified". This is a problem for them and we had to find some quick and easy solution to change the reason code on already revoked certificates from "unspecified" to "key compromise".
Fortunately it is possible to do in couple different ways. One of them is to use certutil.exe command to re-revoke already issued certificates and specify new required reason code.
Here is the command you need to run to revoke a certificate with Serial Number 18e877ea00000000000a and reason code "key compromise":
certutil -revoke "18e877ea00000000000a" 1
So far so good, but how do we know what Serial Number to put into this command? We need to know what certificates already have been revoked. Well, the same utility comes to our rescue. If you run the following command it will provide you with Serial Numbers of all revoked certificates after the specified date:
certutil –view –restrict "RevokedWhen>=08/15/2007" –out SerialNumber
OK, so we run this command, get all serial numbers of revoked certificates, populate this numbers to the first command and re-revoke all of them with new reason code. Cool, but what kind of output does this command provide to us? Can we easily grab serial numbers out from it?
The output from this command looks similar to this:
1/1/2006 12:00 AM
Column Name Localized Name Type MaxLength
---------------------------- ---------------------------- ------ ---------
SerialNumber Serial Number String 128 -- Indexed
Serial Number: "61153ff1000000000006"
Serial Number: "18daada4000000000007"
Serial Number: "18e2c82a000000000008"
Serial Number: "18e3c5d4000000000009"
Serial Number: "18e877ea00000000000a"
Can we get actual numbers out of this output? To the rescue comes Visual Basic script that parse through this information and as it finds anything between "" it takes it, and then creates the revocation command and executes that command.
First we run this command and create the output file with serial numbers:
certutil –view –restrict "RevokedWhen>=08/15/2007" –out SerialNumber > sn-input.txt
Then we can run the following VBScript to re-revoke all certificates that have been revoked since 8/15/07. Here is the sample script to do it:
sInFile = "sn-input.txt"
sDelimiter = """"
const ForReading = 1, ForWriting = 2, ForAppending = 8
set oShell = wscript.createobject("wscript.shell")
set oFSO = wscript.createobject("scripting.filesystemobject")
if oFSO.FileExists(sInFile) then
set oInFile = oFSO.OpenTextFile(sInFile,ForReading)
wscript.echo "Input file " & sInFile & " does not exist."
do while not oInFile.AtEndOfStream
sLine = oInFile.ReadLine
aValues = split(sLine,sDelimiter)
if ubound(aValues)>0 then
if ucase(trim(aValues(0))) = ucase("Serial Number:") then
iRetVal = oShell.Run("certutil -revoke " & """"& aValues(1) &"""" & " 1",TRUE)
loop ' oFile
Now it should be easy to create a batch file that will first create an input file with serial numbers of all revoked certificates and then run vbscript that will parse through this file and re-revoke them with new reason code.
To truly really automate this solution we'll need to automatically inject the date into the command that creates the input file, otherwise it will re-revoke bunch more certificates that we really need. But I didn’t do any investigation yet on how easy it would be inject a certain date into that command. Maybe some other time.
By the way it would take me much longer to come up with this solution if not for some quick pointers from PG and help with writing vbscript from another MS Consultant. Mark you are da man!