Tag Archives: Authenticode

ASP.NET 1.1 pages/assemblies take a long time on first load

The first time you load a page on an ASP.NET web site, or the first time you access a .NET web service, it may take significantly longer to load than subsequent accesses. There are several things that can cause this, including the framework compiling the aspx source pages, but there can be an even more significant delay if you are using Authenticode-signed assemblies and your server does not have access to the internet. In the case of web services, this delay may even be long enough to cause timeouts depending on the configuration of your client programs.

The problem is that as .NET loads Authenticode signed assemblies, it must check for updates on the certificate revocation list (CRL) to verify the signature on the assembly is valid. If Active Directory is not configured to have the authority for CRLs on the local network and the server in question does not have a connection to the internet, the request for the CRL will time out after approximately 15 seconds, and .NET will continue loading the assembly and consider it to be unsigned. This problem is discussed in several articles.

To verify this is what’s happening, you can use a packet sniffer on the server in question and look for the request for the CRL. Using Wireshark, I was able to observe the following behavior after I had stopped the World Wide Publishing service, started the trace, relaunched the World Wide Publishing service, and made a request:

Request for CRL

Request for CRL

The above screenshot shows that a request was made for http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl (IP address 96.17.76.91).

Note that the request will not always be made. The CRL is always cached for the lifetime of a process, so if the IIS worker processes continue to run you will not get a request for the CRL. It’s possible that the CRL is cached for longer, though I haven’t been able to verify that this Microsoft Technet article describes many things about the Windows PKI, including CRL caching. I can replicate the above results when I first stop the World Wide Publishing service, clear the cached data from Internet Explorer, start the trace, start the World Wide Publishing, then make a request to the ASP.NET page/web service. For computers that are not connected to the internet and have not been for a long time, I would guess any caching for the CRL would expire, and every time an Authenticode signed assembly is loaded Windows would try to refresh the CRL. On Vista, you can explicitly refresh the CRL cache per this article.

Resolving this issue on .NET 2.0 post SP1 is straightforward. Setting the generatePublisherEvidence configuration option to false will skip the CRL check. This issue is discussed in Microsoft KB936707.

On .NET 1.1, things are not as straightforward. There isn’t a configuration setting to disable the authentication behavior. The only solution is to disable CRL checking for the entire machine. This can be accomplished through the following steps, originally described on this website.

  1. Open Internet Explorer
  2. Go to Tools —> Internet Options…
  3. Go to the Advanced tab
  4. Locate the Security section and uncheck the Check for publisher’s certificate revocation option.
    Disable Check for publisher's certificate revocation option.

    Disable Check for publisher's certificate revocation option.

CRL checking can also be disabled throughout the entire organization per this Microsoft Technet article.

Another option to address the symptoms as opposed to the underlying issue is to change the behavior of the IIS worker processes. As mentioned previously, the CRL is cached throughout the lifetime of a process, so by managing the lifecyle of the worker process, you can force this timeout to come during non-work hours.

In IIS manager, view properties for the app pool under which your ASP.NET application is running. Go to the Performance tab and disable the idle timeout of the worker processes.

Disable worker process idle timeout

Disable worker process idle timeout

Next, go back to the Recycling tab and set the processes to only recycle at a certain time of day (e.g. 2:00 a.m.).

Change app pool recycling to non-business hours

Change app pool recycling to non-business hours

The last step is to create a custom script that will make a request to your application shortly after the worker processes have been recycled. This will force the CRL check at a time when it doesn’t matter how long the first request takes as normal user activity won’t be interrupted.