Bug 21895 - Forced client certificate request
Summary: Forced client certificate request
Status: ASSIGNED
Alias: None
Product: Class Libraries
Classification: Mono
Component: General (show other bugs)
Version: 3.4.0
Hardware: All All
: --- normal
Target Milestone: Untriaged
Assignee: Martin Baulig
URL:
Depends on:
Blocks:
 
Reported: 2014-08-06 20:26 UTC by Gusman
Modified: 2017-03-23 12:37 UTC (History)
9 users (show)

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


Attachments
TestCase (899 bytes, application/force-download)
2017-03-23 12:34 UTC, weber
Details

Description Gusman 2014-08-06 20:26:15 UTC
HttpListener always asks to the client connection for client certificate and there is no way to disable it.

This change was added on the commit https://github.com/mono/mono/commit/05f25eaaaa9fedd217cc1006182cce0da9275f25

Client certificate request must be an optional functionality, not a forced one.
Comment 1 Rodrigo Kumpera 2014-08-12 20:20:22 UTC
How does .NET support disabling client certificates with HttpListener?
Comment 2 Gusman 2014-08-12 20:26:38 UTC
In .net it's configured when the SSL certificate is installed

When issuing the netsh command to associate a certificate to an endpoint if you specify clientcertnegotiation=enable then the client certificate negotiation will be used else it will be disabled.
Comment 3 Brandon White 2015-02-24 11:48:13 UTC
[Pasting in my comment from @Gusman PR]

This is aggravating my customers as well. I agree that ideally it needs to be configurable, but I think the default should be false. I'm serving a simple status and configuration page from my application.
With the hardcoded value for requestClientCertificate being true, it causes an annoying and confounding pop-up whenever users try to access the page. We've also discovered that on Android phones, it appears that users cannot even access the page if they do not have PIN-based or some other phone lock security enabled.

@kumpera As I understand it, in Windows when you configure the SSL port via netsh, it must be storing additional configuration data (ie clientcertnegotiation=enable) that is later consulted by the SSL code (http.sys?). Mono does not seem to have anything comparable since httpcfg only stores the SSL cert in /root/.config/.mono/httplistener with no opportunity for storing any additional configuration settings.

I would further argue that a hardcoded value of false would be more correct, since that is the .NET behavior under Windows. As I understand, unless you specifically set clientcertnegotiation=enable when performing netsh, then the default behavior is to not request the client's cert. In lieu of a configurable setting, Mono should do the same.

I can think of 2 approaches Mono could take:

Somehow expose this parameter up the layers to the calling code, which would of course be a Mono-specific interface. I'm thinking this idea sucks.

Add a configuration file to hold this and other settings Mono is lacking vs. netsh. This file would reside next to the .cer and .pvk files. So for instance you'd have 443.cer, 443.pvk, and 443.json. We could then add switches to HttpCfg for this and other missing settings (I'm assuming there's more -- could be wrong). Then in the mono code, it would consult the config file to determine these options.

@kumpera What do you think about the option 2? Is there a more appropriate file format for this (XML, etc) that would be more consistent with other parts of Mono?
Comment 4 Rodrigo Kumpera 2015-02-24 12:17:23 UTC
Assigning it to the SSL maintainer.
Comment 5 p.gloor 2015-03-31 05:44:25 UTC
After upgrading from Mono 2.10.8.1 to Mono 3.12.1 this issue has broken my application as well. As long it's documented I personally don't care much about how the solution will be implemented. From a users perspective I could think of an option in httpcfg but manually editing a config file would be fine too.
Comment 6 Robert van der Boon 2015-12-04 14:40:19 UTC
With the current Mono 4.3.0 (master/38aa91b) it still requires a client certificate, which is very unfortunate. It makes the https support of the httplistener unusable for our use case.
Comment 7 Gusman 2015-12-04 18:20:34 UTC
@Robert if you need a workaround you have at least two options:

1-Compile mono from source and change the forced cert to false

  The offending line is in mcs/class/System/System.Net/HttpConnection.cs

  Change 

            SslServerStream ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, true, false);

  to

            SslServerStream ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, false, false);

2-Use Http connections

  If you are in an environment like mine where you have a farm with some load balancers you can instruct these to decipher the SSL data and pass it as plain http data to your listeners, if your environment is closed its safe to do this.

In my case we used the second option after testing the first one during some time, no need to recompile mono framework with each new release and the listener works a lot faster, we have some HAProxy's as balancers and it handles a lot better the SSL cypher than mono.

Cheers.
Comment 8 Brandon White 2015-12-04 19:35:39 UTC
@Robert Similar to @Gusman, we switched over to Nginx using the Reverse Proxy technique.  So in our C#/HttpListener app we only accepted HTTP from localhost.  Nginx handled all of the TLS/SSL stuff.  In our app, it required *no* code changes (other than removing all the stuff we had in there for TLS/SSL).

I thought this was going to hinder performance. I was completely wrong. It sped it up dramatically!  Our product is an embedded ARM appliance.  HTTPS page loads were much snappier vs. trying to use TLS in HttpListener.

Still, I would love to see this issue resolved in Mono.
Comment 9 Jim Borden 2016-01-16 10:14:21 UTC
This is especially aggravating when you consider that HttpClient has no way to include client certificates (the ClientCertificates property on WebRequestHandler is MonoTODO), so this kills P2P over HTTPS.  One of those problems needs to be fixed.  I don't really care which one.
Comment 10 Tobias Kolb 2016-02-25 10:31:05 UTC
I just upgraded from 3.10 to Mono 4.2.2. Now my self-hosted WCF-WebService with TLS is completely broken because Server is always forcing the client to provide a client certificate. When requesting a client certificate during a TLS handshake there should be 2 options: request and require. Mono 3.10 implemented the handshake the first way: the server always asked ("requests") for a client certificate but it was only an optional step. If the client didn't sent a certificate the TLS handshake nevertheless was completed. Although this isn't the correct behavior because normally it shouldn't even ask for a certificate per default (MS .NET is also not doing that), but anyway I can live with that bug.

Now in Mono 4.2.2 things turned even more worse: the server always "requires" a client certificate as a mandatory step. Handshake fails if client cannot provide any. I guess 99% of TLS scenarios out in the world will only need a server side authentication, not a client one.

We really need some "switch" to programmatically turn on/off client cert request/require. I guess this isn't that simple because .NET is doing that by the netsh command which isn't available in Mono. So until then *PLEASE* change the default behaviour back to the way Mono 3.10 was handling client certificates: requesting them, but not requiring them.
Comment 11 Martin Baulig 2016-11-11 10:31:22 UTC
Bump, need to add test and documentation.

This can now be done with MonoTlsSettings.
Comment 12 weber 2017-03-23 12:34:34 UTC
Created attachment 20746 [details]
TestCase

I think the problem is that the OnAccept path of the System/System.Net/EndPointListener doesn't handle exceptions at all.

That way any Exception, that will occure while the handshake is in progress (even if the client is terminating the connection early), will result in a uncatched exception that terminates the entire runtime.

Attached you will find a minimized test case for that scenario.

When i run curl with the --insecure flag everything is fine.
But when i run it without that flag, curl detects that the connection is insecure (that's not the real problem here) and closes it, which results in a runtime termination.
Comment 13 weber 2017-03-23 12:37:08 UTC
Sorry... Wrong Bug :-\

Note You need to log in before you can comment on or make changes to this bug.