Hello folks, sorry for delayed post, one of my SSD disk suddenly dead and I was busy with data recovery.
In the previous post we discovered main interfaces and methods to retrieve Online Responder array settings and revocation configurations. Today we will learn how to use them to delete existing revocation configuration and add a new one.
In the previous post you noticed that my OCSP server has configured one revocation configuration named “test”. Consider when we don’t need this particular configuration (say, associated CA was decommissioned). We can delete it by calling IOCSPCAConfigurationCollection::DeleteCAConfiguration method and applying changes by calling IOCSPAdmin::SetConfiguration method.
PS C:\> $ocsp = New-Object -ComObject CertAdm.OCSPAdmin PS C:\> $ocsp.GetConfiguration("dc2",$true) PS C:\> $ocsp.OCSPCAConfigurationCollection.DeleteCAConfiguration("test") PS C:\> $ocsp.SetConfiguration("dc2",$true) PS C:\> $ocsp.OCSPCAConfigurationCollection PS C:\>
There is nothing complex: we pass configuration name (which, obviously must be unique within particular OCSP array) and then call SetConfiguration by passing OCSP server name and boolean value to update information even if OcspSvc service is not running. Trust me, nothing can be simpler in PKI world!
All OCSP server and revocation configuration changes MUST BE performed on an ARRAY CONTROLLER! This is because only array controller is authorized to update configuration between array members.
Here we will start with the most simple and common scenario — add new revocation configuration against an Enterprise CA. So, how to start? First, we have to identify CA server (by retrieving CA config string), then retrieve the most recent CA certificate and fetch CRL URLs to bind them to revocation provider.
There are various ways to achieve this goal. For example, ocsp.msc UI does it via ICertConfig2 and ICertAdmin2 COM interfaces:
PS C:\> # instantiate ICertConfig interface PS C:\> $CertConfig = New-Object -ComObject CertificateAuthority.Config PS C:\> # display Enterprise CA pick UI and save returned config string to a variable PS C:\> $ConfigString = $CertConfig.GetConfig(0x1) PS C:\> $ConfigString ca01.contoso.com\Contoso SHA2 CA PS C:\>
We got a configuration string of the CA. Now we need to get current CA certificate. In this case we will use ICertAdmin2::GetCAProperty method. ICertAdmin interface specific is outside of this article scope, so I briefly outline just required steps:
PS C:\> # connect to a CA and retrieve the count of CA certificates: PS C:\> $CertAdmin = New-Object -ComObject CertificateAuthority.Admin PS C:\> $CertAdmin.GetCAProperty($ConfigString,0xb,0,1,0) 1 PS C:\> # retrieve CA certificate at CA cert count minus 1: PS C:\> $base64cert = $CertAdmin.GetCAProperty($ConfigString,0xc,0,3,1) PS C:\> $base64cert MIICRjCCAeugAwIBAgIQBrUmlNV5l5VCByyP7eBjnzAKBggqhkjOPQQDAjBIMRMw EQYKCZImiZPyLGQBGRYDY29tMRcwFQYKCZImiZPyLGQBGRYHY29udG9zbzEYMBYG A1UEAxMPQ29udG9zbyBTSEEyIENBMB4XDTEzMTEwMzEzMTMxMVoXDTMzMTEwMzEz MjMwOVowSDETMBEGCgmSJomT8ixkARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2Nv bnRvc28xGDAWBgNVBAMTD0NvbnRvc28gU0hBMiBDQTBZMBMGByqGSM49AgEGCCqG SM49AwEHA0IABAWQFfIwhXcmkm1xodBb3w2+QvSLEwYJtVI9KngNeIrWzbKguCNb abHFD5PNLk84Mev9hZJ5jy3EhDKdYZJobF2jgbYwgbMwEwYJKwYBBAGCNxQCBAYe BABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIN5 aYEormhEoiCJ1bjk+DJO03NGMBAGCSsGAQQBgjcVAQQDAgEAME0GA1UdIARGMEQw QgYEVR0gADA6MDgGCCsGAQUFBwIBFixodHRwOi8vcGtpLmJveHRvbmUuY29tL0Nv bnRlbnRzL2Nwc21haW4uaHRtbDAKBggqhkjOPQQDAgNJADBGAiEAo51zFchZXrf3 PoRtQXYHlW5+oE0tWlI/vzKZEVriPasCIQCdzsh3PI+5YOHG9DknFHiifLLfVVkf ySP8xLBEwWm7aw== PS C:\> # convert base64 string to a byte array: PS C:\> $RawData = [convert]::FromBase64String($base64cert) PS C:\>
$RawData will contain a byte array that represents CA certificate for which revocation configuration is created. Additionally, we retrieve CRL URLs which will be used for revocation provider:
PS C:\> $CRLs = $CertAdmin.GetCAProperty($ConfigString,0x29,0,4,0) PS C:\> $crls ldap:///CN=Contoso%20SHA2%20CA,CN=ca01,CN=CDP,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=contoso,DC=com ?certificateRevocationList?base?objectClass=cRLDistributionPoint PS C:\> # remove extra trailing new line character PS C:\> $crls = $crls.trim()
Ok, so far we retrieved almost all required information and move on, create new revocation configuration. This is achieved by calling IOCSPCAConfigurationCollection::CreateCAConfiguration method where we pass configuration name (whatever you want, I usually use CA name with CA certificate’s key index) and CA certificate (as a byte array):
PS C:\> $revconfig = $ocsp.OCSPCAConfigurationCollection.CreateCAConfiguration("Contoso SHA2 CA (0)",$RawData) PS C:\> $revconfig Identifier : Contoso SHA2 CA (0) CACertificate : {48, 130, 2, 70...} HashAlgorithm : SigningFlags : SigningCertificate : ReminderDuration : ErrorCode : 2147483658 CSPName : KeySpec : ProviderCLSID : ProviderProperties : Modified : True LocalRevocationInformation : SigningCertificateTemplate : CAConfig : PS C:\>
The method returned a revocation configuration object reference. We do not store a copy of the object, but a reference to it, therefore when we modify this reference, a source object (which is stored in the $ocsp.OCSPCAConfigurationCollection property) is updated too. Current object status is 2147483658 (0x8000000a) which stands for “The data necessary to complete this operation is not yet available.” Let’s fill general properties:
PS C:\> # set hash and signing algorithm to SHA1 PS C:\> $revconfig.HashAlgorithm = "sha1" PS C:\> # set CA which will issue OCSP Response Signing certificate: PS C:\> $revconfig.CAConfig = $ConfigString PS C:\> $revconfig.SigningCertificateTemplate = "OCSPResponseSigning" PS C:\> # set provider ID. It must be "{4956d17f-88fd-4198-b287-1e6e65883b19}" PS C:\> $revconfig.ProviderCLSID = "{4956d17f-88fd-4198-b287-1e6e65883b19}" PS C:\> # set default signing flags: PS C:\> $revconfig.SigningFlags = 605 PS C:\> $revconfig Identifier : Contoso SHA2 CA (0) CACertificate : {48, 130, 2, 70...} HashAlgorithm : sha1 SigningFlags : 605 SigningCertificate : ReminderDuration : ErrorCode : 2147483658 CSPName : KeySpec : ProviderCLSID : {4956d17f-88fd-4198-b287-1e6e65883b19} ProviderProperties : Modified : True LocalRevocationInformation : SigningCertificateTemplate : OCSPResponseSigning CAConfig : ca01.contoso.com\Contoso SHA2 CA PS C:\>
Here is little note for SigningFlags property. For Enterprise CAs we should use the following flag combination:
Combined, these flags will result a numeric value of 605.
As it is known (or should be known), Windows OCSP relies on CRLs and we have to provide CRL location URLs to allow OCSP server to automatically download and use these CRLs. Revocation provider is implemented in a generic IOCSPPropertyCollection interface:
# instantiate and initialize IOCSPPropertyCollection interface: $OCSPPropCollection = New-Object -ComObject CertAdm.OCSPPropertyCollection [void]$OCSPPropCollection.InitializeFromProperties($null) # create property that will store Base CRL URLs. URLs must be explicitly casted # to a string array (rather than default object array) [void]$OCSPPropCollection.CreateProperty("BaseCrlUrls",[String[]]$CRLs) # assuming that our Enterprise CA uses Delta CRLs, generate a Delta CRL URL $DeltaCRLURLs = $CRLs | %{ if ($_ -match "^http") { $_ -replace "\.crl$", "+.crl" } else { $_ -replace "\?certificateRevocationList\?","?deltaRevocationList?" } } [void]$OCSPPropCollection.CreateProperty("DeltaCrlUrls",[String[]]$DeltaCRLURLs) # write property collection to ProviderProperties property $revconfig.ProviderProperties = $OCSPPropCollection.GetAllProperties()
if we run the code:
PS C:\> # instantiate and initialize IOCSPPropertyCollection interface: PS C:\> $OCSPPropCollection = New-Object -ComObject CertAdm.OCSPPropertyCollection PS C:\> [void]$OCSPPropCollection.InitializeFromProperties($null) PS C:\> # create property that will store Base CRL URLs. URLs must be explicitly casted PS C:\> # to a string array (rather than default object array) PS C:\> [void]$OCSPPropCollection.CreateProperty("BaseCrlUrls",[String[]]$CRLs) PS C:\> # assuming that our Enterprise CA uses Delta CRLs, generate a Delta CRL URL PS C:\> $DeltaCRLURLs = $CRLs | %{ >> if ($_ -match "^http") { >> $_ -replace "\.crl$", "+.crl" >> } else { >> $_ -replace "\?certificateRevocationList\?","?deltaRevocationList?" >> } >> } >> [void]$OCSPPropCollection.CreateProperty("DeltaCrlUrls",[String[]]$DeltaCRLURLs) >> # write property collection to ProviderProperties property >> $revconfig.ProviderProperties = $OCSPPropCollection.GetAllProperties() >> PS C:\> $revconfig Identifier : Contoso SHA2 CA (0) CACertificate : {48, 130, 2, 70...} HashAlgorithm : sha1 SigningFlags : 605 SigningCertificate : ReminderDuration : ErrorCode : 2147483658 CSPName : KeySpec : ProviderCLSID : {4956d17f-88fd-4198-b287-1e6e65883b19} ProviderProperties : {BaseCrlUrls, ldap:///CN=Contoso%20SHA2%20CA,CN=ca01,CN=CDP,CN=Public%20Key%20Services,CN= Services,CN=Configuration,DC=contoso,DC=com?certificateRevocationList?base?objectClass=cRL DistributionPoint, DeltaCrlUrls, ldap:///CN=Contoso%20SHA2%20CA,CN=ca01,CN=CDP,CN=Public%2 0Key%20Services,CN=Services,CN=Configuration,DC=contoso,DC=com?deltaRevocationList?base?ob jectClass=cRLDistributionPoint} Modified : True LocalRevocationInformation : SigningCertificateTemplate : OCSPResponseSigning CAConfig : ca01.contoso.com\Contoso SHA2 CA PS C:\>
we will get the complete revocation configuration with configured revocation provider.
Current list of provider propertied is listed in the ProviderProperties MSDN article. Also, there is a typo. Plural values misses “s” character at the end: BaseCrlUrls, DeltaCrlUrls.
Now we need to commit changes to the server and check, whether it is created as expected by calling SetConfiguration method:
$OCSPAdmin.SetConfiguration("dc2",$true)
If the method succeeds, then we can open ocsp.msc to check, whether it is really ok:
It is up and already working!
Today we learned how simple things can be so difficult. As I always say, Windows PKI will never create easy ways to accomplish some PKI-related stuff. But if you learned this way — you are on top and rock in colleague’s eyes. In order to better understand how it works, follow this post and MSDN documentation provided in links. Spend few more minutes to arrange this mess in your heads. Eventually, you will be able to automate the whole OCSP provisioning process. For example, I wrote (for internal use) an universal script that will automatically install and configure OCSP server with parameters. Spend some time today and save more time tomorrow.
Is it possible to use powershell to:
1. Set a server as the OCSP Array Controller
2. Add members to an OCSP array
3. Synchronize the OCSP array
yes, it is possible to set server as the OCSP array controller and manage array membership. But there is no way to synchronize (and refresh revocation data) OCSP array from PowerShell. This functionality is implemented directly in MMC.
Thank you. These 2 OCSP articles were very helpful.
Regarding array membership management, you can try to read my blog post in Russian: http://www.sysadmins.lv/blog-ru/upravlenie-online-responder-iz-powershell-chast-1.aspx
unfortunately, I haven't translated it to English. Try to use online translators.
I'm trying to set "RefreshTimeOut" property of $OCSPPropCollection, but it keeps throwing an error when I call $ocsp.SetConfiguration("dc",$true). Can you tell me what I'm doing wrong?
I know that it needs a DWORD value, but I'm not sure how to properly pass that. Here's what I've tried...
$RefreshTimeOut = "5"
[void]$OCSPPropCollection.CreateProperty("RefreshTimeOut",[String[]]$RefreshTimeOut)
I've also tried:
$RefreshTimeOut = "0x5"
[void]$OCSPPropCollection.CreateProperty("RefreshTimeOut",[String[]]$RefreshTimeOut)
And even:
$RefreshTimeOut = 5
[void]$OCSPPropCollection.CreateProperty("RefreshTimeOut",[Int[]]$RefreshTimeOut)
Any help would be greatly appreciated.
The problem is that RefreshTimeOut is DWORD (simple integer), not an array of strings or array of integers. Look at this page for more details on property types: https://msdn.microsoft.com/en-us/library/aa386372(v=vs.85).aspx
The code should be:
$RefreshTimeOut = 5
[void]$OCSPPropCollection.CreateProperty("RefreshTimeOut",[int]$RefreshTimeOut)
Thanks! I guess I didn't realize that I as trying to pass an array...
The DeltaCRL doesn't seem to work for multiple delta entries (we have http and LDAP). I used following instead.
$DeltaCRLURLs = $CRLs | %{
($_ -replace "\.crl", "+.crl") -replace "\?certificateRevocationList\?","?deltaRevocationList?"
}
Sorry just realised when viewiing new OCSP object that this way didnt work either, ended up with all items in one entry rather than multiple entires.
As per comment above from James, I too have multiple entries for Base and Delta CRLs and they are ending up as a single string in the OCSP object which then fails the config when viewing in the OCSP vai the GUI. If yuo edit the configuration by hand in the GUI and make it 2 line as it shoudl be it all works.
Has anybody found away round this?
The comment and code in the article mentions explicityly casting to a string array (rather than the default object array). could it be linked this casting?
# create property that will store Base CRL URLs. URLs must be explicitly casted
# to a string array (rather than default object array)
[void]$OCSPPropCollection.CreateProperty("BaseCrlUrls",[String[]]$CRLs)
Any help appreciated?
Hi. I had installed OCSP resronder on Enterprise sub-ca
All work correct, but when i trying to check certs from F5 - i have error "no responder"
From windows os check by cert util work correct.
> when i trying to check certs from F5 - i have error "no responder"
You need to consult with F5 documentation or contact F5 support.
p.s. it is not recommended to instal OCSP on CA server.
Post your comment:
Comments: