Bug 5706 - Valid certificates are accepted regardless of end point
Summary: Valid certificates are accepted regardless of end point
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: System ()
Version: master
Hardware: PC Windows
: --- normal
Target Milestone: Untriaged
Assignee: Sebastien Pouliot
URL:
Depends on:
Blocks:
 
Reported: 2012-06-18 11:55 UTC by Brian
Modified: 2012-08-23 19:35 UTC (History)
5 users (show)

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


Attachments
Main.axml (1.05 KB, application/octet-stream)
2012-07-16 14:34 UTC, Allie Miller
Details
MainActivity.java (3.11 KB, application/octet-stream)
2012-07-16 14:34 UTC, Allie Miller
Details
Activity1.cs (1.64 KB, application/octet-stream)
2012-07-16 14:35 UTC, Allie Miller
Details


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 FIXED

Description Brian 2012-06-18 11:55:44 UTC
Good morning:

I've run into an issue on both platforms where by any valid certificate is accepted regardless of the end point.  For instance, if I connect to a server that's hosting https I can use any valid dns name for the service, be it www.*, .*, m.* (assuming that the dns points to the right area for the name).  As this is definitely not intended behavior for https (the client should reject the certificate if it doesn't match the end point) I thought it belonged here.

Thank you,
Brian Werth
Comment 2 Allie Miller 2012-07-16 14:34:06 UTC
Created attachment 2206 [details]
Main.axml

Submitted for follow-up
Comment 3 Allie Miller 2012-07-16 14:34:42 UTC
Created attachment 2207 [details]
MainActivity.java
Comment 4 Allie Miller 2012-07-16 14:35:07 UTC
Created attachment 2208 [details]
Activity1.cs
Comment 5 Jonathan Pryor 2012-07-17 17:02:09 UTC
This is a bug in Mono's BCL. Consider the following app:

  using System;
  using System.Net;

  class Test {
    public static void Main (string[] args)
    {
      foreach (string s in args) {
        Read (s);
      }
    }

    static void Read (string url)
    {
      Uri site = new Uri (url);
      HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(site);
      webReq.Method = "GET";
      webReq.ContentType = "message/http";
      try
      {
        WebResponse response = webReq.GetResponse();
        Console.WriteLine ("{0}: {1}", url, response.ToString ());
      }
      catch (Exception ex)
      {
        Console.WriteLine ("{0}: error: {1}", url, ex);
      }
    }
  }


Compile, run:

  $ dmcs wc.cs
  $ mono wc.exe https://74.125.224.134 
  https://74.125.224.134: System.Net.HttpWebResponse

No error.

Compare to .NET:

> E:\tmp>csc wc.cs
> Microsoft (R) Visual C# Compiler version 4.0.30319.17626
> for Microsoft (R) .NET Framework 4.5
> Copyright (C) Microsoft Corporation. All rights reserved.
> 
> E:\tmp>wc https://74.125.224.134
> https://74.125.224.134: error: System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
>    at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
>    at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
>    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
>    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
>    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
>    at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
>    at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
>    at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
>    at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
>    at System.Net.ConnectStream.WriteHeaders(Boolean async)
>    --- End of inner exception stack trace ---
>    at System.Net.HttpWebRequest.GetResponse()
>    at Test.Read(String url)

Error.

Mono should likewise throw an error.
Comment 6 Sebastien Pouliot 2012-08-23 15:59:53 UTC
Jonp, did you, by any chance, execute this (only) on a Mac ?
Comment 7 Jonathan Pryor 2012-08-23 16:18:35 UTC
@Sebastien: The invocation from Comment #5 was performed on a Mac. The ~equivalent code is also in Attachment 2208 [details] (Activity1.cs), and fails in the same manner on Android/Linux.
Comment 8 Sebastien Pouliot 2012-08-23 16:24:44 UTC
So the "general" managed code path works (tested on Ubuntu) but the refactoring done for MonoTouch (same code used for OSX) and Mono for Android introduced an identical error. 

When the certificate is trusted then `errors` and `status11` are reset to 0, meaning all previous validations (including checking the hostname) are disregarded and won't be reported as errors.

E.g. from mcs/class/System/System.Net/ServicePointManager.cs

#if MONODROID
				result = AndroidPlatform.TrustEvaluateSsl (certs, sender, leaf, chain, errors);
				if (result) {
					status11 = 0;
					errors = 0;
				}
#endif

I'll fix the iOS/OSX code path by skipping the validation and asking the native API to do the checks (no point in delegating half the job). This will ensure 100% identical results between iOS/OSX apps and MonoTouch/Mono, reduce the code (good) and remove the Regex (even better form the linker perspective).

M4A should (needs testing) be able to continue using the managed version and simply remove the offending "= 0;" lines.
Comment 9 Sebastien Pouliot 2012-08-23 16:57:18 UTC
Fixed (both iOS/OSX and M4A)

mono/master:
3a274aac77acaad20604506a92cafe458516a4e7
ad89f72f5b34899418dcdc12709abd66ae3c8e92

mono/mono-2-10
4b9e7cafc663a98126dfdfdc45d3399562a8ade0
b24e740510e37d7387bfa2c8a7645e8e29e39726

mono/mobile-master
b92321784cb9c2891f06a8715959a071ca64ce22
753daf79ad44283dc0df8ab7de23d031e76f5ce3

monotouch-5.4-series
e77507ccb80c24c95f0c6176c981675aa416cebf
Comment 10 Sebastien Pouliot 2012-08-23 19:35:26 UTC
QA: unit tests added in monotouch/master
d9314d4cab8c138050304329cb65488d94e491dc