Notice (2018-05-24): bugzilla.xamarin.com is now in
Please join us on
Visual Studio Developer Community and in the
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
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
Developer Community or GitHub 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.
System.Net.Security.SslStream and Mono.Security.Protocol.Tls.SslClientStream seems not to check server certificate against iOS root certificates. It constantly throws an exception:
[ERROR] FATAL UNHANDLED EXCEPTION: System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server.
at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x0027b] in /Developer/MonoTouch/Source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerCertificate.cs:327
at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00054] in /Developer/MonoTouch/Source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerCertificate.cs:105
at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00037] in /Developer/MonoTouch/Source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls.Handshake/HandshakeMessage.cs:105
at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00039] in /Developer/MonoTouch/Source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs:81
at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00127] in /Developer/MonoTouch/Source/mono/mcs/class/Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs:397
var tcpClient = new TcpClient("google.com", 443);
var ssl = new SslStream(tcpClient.getStream(), false);
If i provide custom validation callback, it always receives chain errors in 'errors' argument.
Accessing HTTPS with WebRequest API seems to work ok. But I need custom protocol over SSL. Is it possible with MonoTouch?
As of today you'll need to provide your own validation callback and, on error, use the MonoTouch.Security API  to check if iOS trust (or not) the provided certificate.
This will be very similar to what is presently done in ServicePointManager  for HttpWebRequest.
I've already solved this in my code in following way:
var syscerts = new System.Security.Cryptography.X509Certificates.X509Certificate[certificates.Count];
for (var i = 0; i < certificates.Count; i++)
syscerts[i] = new X509Certificate(certificates[i].RawData);
var trust = new SecTrust(new X509CertificateCollection(syscerts), SecPolicy.CreateSslPolicy(false, serverName));
var result = trust.Evaluate();
return result == SecTrustResult.Unspecified || result == SecTrustResult.Proceed;
Seems to work well. But this is iOS-specific solution.
Fixed in 96a8500795960ae1d9e81e28095c3e2dda303342
Created attachment 6609 [details]
Modified patch to allow validation without a RemoteCertificateValidationCallback
I could easily be mistaken about the correct way to fix this, but it looks like the original test scenario for this bug doesn't work at the moment. The attached patch makes two small revisions to the changes in `SslStream.BeginAuthenticateAsClient()`:
1. Switch `MONOTOUCH` to `INSIDE_SYSTEM`.
2. Re-order the lines a little so that `ServicePointManager.ChainValidationHelper.ValidateChain()` is _always_ added to the `SslClientStream.ServerCertValidation2` event handler, regardless of whether the user passes a `RemoteCertificateValidationCallback` into the `SslStream` constructor.
These two changes allow the original test scenario to run successfully.
Based on a comment from a slightly earlier commit (aaea1f82e4141d7f2193b0fe9258e84e9dc57a9f), I think these changes might be OK. To paraphrase: "Compiling only the `RemoteValidation()` method, and skipping the `LocalValidation()` method helps the linker to remove a lot of validation code that will never be used on OS X and iOS. On those platforms, the `INSIDE_SYSTEM` version of `SslClientStream` will always have a value assigned to the `ServerCertValidation2` event handler."
## Original test scenario
> var tcpClient = new TcpClient("google.com", 443);
> var ssl = new SslStream(tcpClient.GetStream(), false);
Whoops. Actually, I think the change from `MONOTOUCH` to `INSIDE_SYSTEM` doesn't make sense in this case because `System.Net.Security.SslStream` is always "inside system." That part of the patch can be ignored.
Moving milestone to C7.
@Martin, was this fixed as part of in your TLS refactoring ?
Yeah, all that code has been reworked and fixed.
For iOS / Mac, there'll also be a new API which lets you do that SecTrust thing without providing your own callback. This'll allow you to use a self-signed certificate and still use the system certificate validator.
Resolving for QA validation on C7.