Bug 17326 - ServerCertificateValidationCallback is not always called even though Keep-Alive=false was used
Summary: ServerCertificateValidationCallback is not always called even though Keep-Ali...
Status: RESOLVED FEATURE
Alias: None
Product: Class Libraries
Classification: Mono
Component: General ()
Version: 3.2.x
Hardware: All All
: High normal
Target Milestone: Untriaged
Assignee: Sebastien Pouliot
URL:
Depends on:
Blocks:
 
Reported: 2014-01-20 09:11 UTC by Mihai
Modified: 2014-05-29 08:28 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FEATURE

Description Mihai 2014-01-20 09:11:36 UTC
When sending two consecutive SSL WebRequest, the certificate callback is not called the second time.
Using Keep-Alive=false should solve the problem, but this flag seems to not be respected by System.Net.

The original Windows .Net Framework correctly calls the callback every time, but Mono doesn't call if validation was True the first time.

Please use the code below to reproduce the problem.
It reads a SSL page two times, while the validation is only the first time.

The output is:
  Validation called, returning true.
  OK
  Read 41478 length reply.
  OK
  Read 41456 length reply.


The CORRECT output should be:
  Validation called, returning true.
  OK
  Read 41334 length reply.
  Validation called, returning true.   <--- this is skipped by Mono
  OK
  Read 41430 length reply.

---------------------------------
class Program
{
	public static bool ValidateCertificate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
	{
		Console.WriteLine("Validation called, returning true.");
		return true;
	}

	static bool Submit(String url)
	{
		try
		{
			ServicePointManager.ServerCertificateValidationCallback = ValidateCertificate;

			var request = (HttpWebRequest)WebRequest.Create(url);
			request.KeepAlive = false;
			request.Method = "GET";

			var response = (HttpWebResponse)request.GetResponse();
			var statusCode = response.StatusCode;
			Console.WriteLine("{0}", statusCode);

			var replyStream = response.GetResponseStream();
			var reply = new StreamReader(replyStream, Encoding.UTF8).ReadToEnd();
			Console.WriteLine("Read {0} length reply.", reply.Length);

			return true;
		}
		catch(Exception e)
		{
			Console.WriteLine(e.Message);
			return false;
		}
	}

	static void Main(string[] args)
	{
		Submit("https://encrypted.google.com/");
		Submit("https://encrypted.google.com/");
	}
}
Comment 1 Sebastien Pouliot 2014-05-28 17:11:35 UTC
I'm fairly sure it's the cache of SSL/TLS connections [1] that cause this. That's lower level than HTTP (SSL/TLS transport) level so KeepAlive does not apply.

If I'm right then it is a "soft" bug (because we does not 100% match MS) and was done on purpose since the validation is a quite costly part of the initiating an SSL/TLS connection with a server. It also means it should be safe since the cache is short-lived and the server must accept to renegotiate with the same parameters. If not a full dance (handshake and certificate check) will be done.

It looks related to bug #19141. I've not tested the patch yet but seems to kill only half of the optimization (the crypto handshake is not duplicated, just the certificate check). That might be a solution.

Note that this is not the kind of "behaviour" that application should not rely on. Either us (or MS newer FX versions) could change this behaviour in the future.
Comment 2 Miguel de Icaza [MSFT] 2014-05-28 17:45:16 UTC
If this can change on the implementation, then it is probably a bad idea to make this change.
Comment 3 Sebastien Pouliot 2014-05-29 08:28:21 UTC
It is like I thought, the handshake cache removes the 2nd callback.

Theer's an easy trick* to validate this, e.g.

pollux:src sebastienpouliot$ mcs bug17326.cs

pollux:src sebastienpouliot$ mono bug17326.exe 
Validation called, returning true.
OK
Read 44594 length reply.
OK
Read 44594 length reply.

^ just like you had

pollux:src sebastienpouliot$ MONO_TLS_SESSION_CACHE_TIMEOUT=0 mono bug17326.exe 
Validation called, returning true.
OK
Read 44498 length reply.
Validation called, returning true.
OK
Read 44560 length reply.

^ two "Validation called"


You can add this into your own code, e.g.

Environment.SetEnvironmentVariable ("MONO_TLS_SESSION_CACHE_TIMEOUT", "0");

and the you'll have

pollux:src sebastienpouliot$ mono bug17326.exe 
Validation called, returning true.
OK
Read 44610 length reply.
Validation called, returning true.
OK
Read 44514 length reply.



* thanks Rolf for the reminder