This is actually very common problem in many environments – Web Interface andor particular consoles (mostly MMC-based) are slow to start – there is actually KB article that describes a workaround for this issue. I consider this to be one of the tweaks that many people often implement, but don’t really understand the consequences and the reasons why it helps, so I’ve decided to write a small blog post about this topic.
What is certificate revocation list? So, you’ve got your certificate issued, right? But now you can ask yourself – what should I do in case that certificate was compromised and I quickly need to revoke it?
This is the primary purpose of Certificate Revocation List (CRL). It allows you to quickly check if the certificate is still valid and wasn’t revoked meanwhile. There are two different ways how this can be achieved – either you can download the whole list of revoked certificates (CRL) or you can ask only for specific certificate (OCSP – Online Certificate Status Protocol), which is much faster. Each certificate can actually be in two different statuses – Revoked (certificate is irreversibly revoked) or Hold (temporary invalidation of certificate).
As you can see, there is a clear difference between Revocation and Expiration – certificate itself doesn’t contain any information about the revocation date (how could it know) and therefore you need to check online if certificate is still valid or it was revoked.
As you can see, the rule that certificate should be always self-authenticating doesn’t apply here – properly implemented CRL policy would actually turn certificates into symmetric system (like Kerberos with KDC).
Why is it slow? Theoretically, certificate revocations shouldn’t have a great impact on performance – CRLs can be cached and consulted periodically and OCSP should require much less bandwidth (with CRL, you are getting list of all revoked certificates, with OCSP you are requesting revocation status of only specific certificate). The problem is when your serversdesktops are not connected to the internet – the system will still try to validate the certificate and connection needs to timeout.
This doesn’t affect only web sites, but also .NET applications – this is caused by the feature in .NET that is called Code Access Security (CAS) – I won’t go into too much detail, since this blog post is aimed at IT pros and not at developers. Whenever a module loads, it presents evidence to the CLR (Common Language Runtime, NOT CRL). One part of the “evidence” is information about publisher and this evidence is validated by looking at the signature (which involves certificate). During this process, CRL is consulted – and if you don’t have internet connection, you will see the timeout issues again.
How to fix it? Now since you understand what the issue is, it’s time to discuss how it could be fixed. Be aware that according to Microsoft, disabling CRL check is not recommended in a production environment, unless you are troubleshooting an issue. There are however also few other articles and blog posts where this is recommended solution (for example here and here).
There are actually few different solutions how to disable CRL checks… It is important to keep in mind that .NET is a framework and this got some advantages – for example fallback configuration. What this means is that you can specify default per-machine configuration and then overwrite this for specific applications only.
Per-Application fix If you want to disable CRL for specific application only, you can use the method specified in article CTX117273. Exactly same method can be used for any other application just by modifying (or creating) the application.exe.config file (most common example is modifying mmc.exe.config file). If you have a look at properly designed products like XenDesktop, you can see that this was actually preconfigured – for example BrokerService.exe.config already contains this configuration (<generatePublisherEvidence enabled=”false”/>).
Per-Computer fix Most of the times, the computer itself doesn’t have any internet access and to simplify the management, you want to change the behavior for all of the applications. In this case, you need to modify machine configuration that applies to all applications (unless application itself overwrites this behavior using application.exe.config). You can find this configuration file (called Machine.config) in the %Runtime%Config subfolder – runtime in this case refers to the .NET Framework runtime. For guidance, you can read this MSDN blog article.
Another way would be to simply use hosts to block access to the crl.microsoft.com (redirect to localhost).
What are the real consequences? I can imagine that some security guys are already sharpening the knives and trying to Google my home address, so it is important what the real impact of this change is.
As explained before, you are exposed to the revoked certificates when you disable CRL checks. Unfortunately, it turned out that CRL checks are not as useful as they should be. Since I’m responsible for Middle East region, I was watching closely the situation around “Flame” malware – this would be ideal situation when to use CRLs to revoke the certificate, but Microsoft issued new security hotfix instead. According to my knowledge, most of the browsers are actually ignoring the CRLs (otherwise you won’t be able to run MMC console without access to the internet) – this article sums it up nicely. Also Internet Explorer ignores it by default – the messages are quite common and would scare a lot of regular users (as explained here) – you can follow this blog post if you want to enable notifications about failed CRL checks.
If you still want to implement CRL and at the same time, you don’t want to wait for the timeouts, there is one way. CRL can be actually downloaded and applied manually (=through the script).
1.) Download the latest CRL updates
2.) Copy the CRL updates to the network share
3.) During startup, import them on each machine
You can the CRL updates (2 files) here and here – of course you can fully automate this process.
I’m not going to write the full script here, but to give you an idea of what needs to be done:
[array]$URLs = “http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl”, “http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl”
ForEach ($URL in $URLs) {
$(New-Object System.Net.WebClient).DownloadFile($URL, “$Env:TempTemp_CRL.crl”)
CertUtil –AddStore CA “$Env:TempTemp_CRL.crl”
}