I have created a server using HttpListener. It works perfect without SSL, but with SSL something strange happens.
I have installed the certificate using httpcfg and even with my own program, it installs correctly, the listener starts and serves HTTPS requests, but always asks for a client certificate.
It does not happens on Windows/.net, only with Linux/mono (I'm using ver 3.4.0) and is very annoying, I don't want the user to be asked each time he tries to log in for a client certificate.
Is this a mono bug or is there any way to disable the client certificate negotiation?
Thanks.
I'm having the same problem. What I've discovered is that this is hardcoded in Mono. In mcs/class/System/System.Net/HttpConnection.cs, when the constructor of SslServerStream is called, you will notice that the requestClientCertificate is hardcoded to true.
I came across this PR that attempts to change this hardcoded value to false, however it's currently semi-rejected due to "I rather not change one hardcoded value for another hardcoded value."
[Update] And I just now realized you (OP) are the author of the PR :)
[Update 9/21/2016] It looks like this question is still getting hits. If it is helpful to anyone, we went with nginx as a reverse proxy a long time ago when we could not resolve this issue. I'm glad we did, and should have done it sooner. It is much faster than Mono for handling the SSL/TLS, and allows us to more carefully control the crypto suites and keep up to date with security patches.
I'm keeping an eye on Mono 4.6, which has yet to release. With their overhaul of TLS and the ability to plug in alternate implementations at runtime this might give us a path forward without using nginx reverse proxy.
The only options one (still..) has are:
Use Gusman's pull request #1 or #2 (depending on your Mono version) as workaround which should be OK for productive environments, if a recent Mono version's source code is used.
Example for Mono v4.2.3.4:
echo -e -n "83c83\n< \t\t\t\tSslServerStream ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, true, false);\n---\n> \t\t\t\tSslServerStream ssl_stream = new SslServerStream (new NetworkStream (sock, false), cert, false, false, false);\n" > nocerts.diff
tar xvjf mono-4.2.3.4.tar.bz2
cd mono-4.2.3.4
patch ./mcs/class/System/System.Net/HttpConnection.cs ../nocerts.diff
./configure --prefix=/usr
make
make install
Or use the last Mono version that works without client certificates (which is v3.10.0).
Related
In the past, there has been lots of productive discussion on how to mount drives programmatically.
This link is one productive example:
How do I map a network drive that requires a username and password in .NET?
However, what I seem to be missing is a way to perform this mount when TLS is required.
We see things like this:
net.exe use x: "\server.com#ssl:443\folder" /User:UserName Password
Where this can be used in code with:
System.Diagnostics.ProcessStartInfo process = new System.Diagnostics.ProcessStartInfo();
process.FileName = "net.exe";
process.Arguments = "use Z: \\\\JoeDoodle.TheDomain5.com#SSL\\MyFolder\\ PassW0rd /user:JoeUser";
process.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(process);
// Other stuff...
This sort of thing works great with SSL but not TLS. This is a .Net 4.0 application with our test base starting on Windows 7. Since we are running this as process as shown I am not sure not much that matters.
I cannot use WNetAddConnection2 and related imports because this is a remote drive. The other end is Linux exposing Webdav and it works fine for SSL but not TLS specifically. They are phasing out SSL so I must use TLS.
Any way to mount it programmatically will probably be fine with TLS but I just haven't found the successful combination.
Any help is appreciated.
The problem was ultimately not a Windows problem but an Apache problem.
Apache required not just turning SSLv3 off but a slight code change and recompile.
This only applied to Windows 7 connecting so I do not know about Windows 8.
I have a .NET 3.5 desktop application that had been showing periodic slow downs in functionality whenever the test machine it was on was out of the office.
I managed to replicate the error on a machine in the office without an internet connection, but it was only when i used ANTS performance profiler that i got a clearer picture of what was going on.
In ANTS I saw a "Waiting for synchronization" taking up to 16 seconds that corresponded to the delay I could see in the application when NHibernate tried to load the System.Data.SqlServerCE.dll assembly.
If I tried the action again immediately it would work with no delay but if I left it for 5 minutes then it would be slow to load again the next time I tried it.
From my research so far it appears to be because the SqlServerCE dll is signed and so the system is trying to connect to get the certificate revocation lists and timing out.
Disabling the "Automatically detect settings" setting in the Internet Options LAN settings makes the problem go away, as does disabling the "Check for publishers certificate revocation".
But the admins where this application will be deployed are not going to be happy with the idea of disabling certificate checking on a per machine or per user basis so I really need to get the application level disabling of the CRL check working.
There is the well documented bug in .net 2.0 which describes this behaviour, and offers a possible fix with a config file element.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<generatePublisherEvidence enabled="false"/>
</runtime>
</configuration>
This is NOT working for me however even though I am using .net 3.5.
The SQLServerCE dll is being loaded dynamically by NHibernate and I wonder if the fact that it's dynamic could somehow be why the setting isn't working, but I don't know how I could check that.
Can anyone offer suggestions as to why the config setting might not work?
Or is there another way I could disable the check at the application level, perhaps a CAS policy setting that I can use to set an exception for the application when it's installed?
Or is there something I can change in the application to up the trust level or something like that?
You can specify in code if you want to check the revocation list per application:
ServicePointManager.CheckCertificateRevocationList = false;
In this blog posting (which cites another source) you have two options: disable CRL checking system wide or per app:
Disable CRL Checking Machine-Wide Control Panel -> Internet Options ->
Advanced -> Under security, uncheck the Check for publisher's
certificate revocation option
Disable CRL Checking For a Specific .Net Application See this
Microsoft KB Article: http://support.microsoft.com/kb/936707
What solved the problem for me:
I (think I) had a problem with online revocation before, so I explicitly switched to offline. Due to to warning, I now had to change...
_ = builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(
options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.RevocationMode = X509RevocationMode.Offline;
}
);
... to ...
_ = builder.Services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(
options =>
{
options.AllowedCertificateTypes = CertificateTypes.All;
options.RevocationMode = X509RevocationMode.NoCheck;
}
);
I am developing a c# application, and using Pinvoke to call the method WinVerifyTrust.
the pinvoke declaration is as defined in Pinvoke.net.
The RevocationChecks is set to none.
When trying to check my program on iExplorer, at first it worked ok and returned status ok for the file, but suddenly it started failing with CERT_E_REVOCATION_FAILURE, and then after a while it was ok again.
What might cause this weird behavior? does it mean that I am doing something wrong?
By default WinVerifyTrust tries to download any associated Certificate Revocation List (CRL) to verify that the certificate has not been explicitly revoked. If your connection to the Internet is not stable and the download fails, the CERT_E_REVOCATION_FAILURE is returned.
If you have some version of the Windows SDK installed, you can temporarily turn of the CRL download with the setreg tool. Keep in mind though that this should only be used temporarily to verify that the issues you are seeing are indeed related to CRL connectivity.
setreg.exe 3 FALSE
Documentation for the tool is available at MSDN.
There are several questions like this, but my situation seems a bit different. I have extremely simple code:
WebClient client = new WebClient();
client.DownloadFile("http://www.xkcd.com", "xkcd.html");
However, I get the error "No connection could be made because target machine actively refused the connection." However, I also see this problem with connections to any website. It also only appears in .NET applications, all of a sudden, none of them can access the web.
Any ideas?
For the purpose of a sanity check, I like using PowerShell to call api's, so I'd suggest that if you can.
Also, make sure to try that url in IE on the system just to make sure there's nothing weird going on (forced proxy, site is really down, DNS or hosts file is resolving it to something else, etc).
C:\Users\james » $wc = new-object system.net.webclient
C:\Users\james » $wc.DownloadFile("http://www.xkcd.com", "xkcd.html")
C:\Users\james » dir .\xkcd.html
Directory: Microsoft.PowerShell.Core\FileSystem::C:\Users\james
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 8/26/2010 1:08 AM 7454 xkcd.html
The user that your code is running as is relevant. For example the code might work in a console/WinForms app but not in an ASP.NET app.
Try to go to the site using Internet Explorer browser. The problem is the WebClient uses proxy settings from IE. And there are any wrong proxy settings you'll get the message you've got.
So I've got a ServiceReference added to a C# Console Application which calls a Web Service that is exposed from Oracle.
I've got everything setup and it works like peaches when it's not using SSL (http). I'm trying to set it up using SSL now, and I'm running into issues with adding it to the Service References (or even Web References). For example, the URL (https) that the service is being exposed on, isn't returning the appropriate web methods when I try to add it into Visual Studio.
The underlying connection was closed: An unexpected error occurred on a send.
Received an unexpected EOF or 0 bytes from the transport stream.
Metadata contains a reference that cannot be resolved: 'https://srs204.mywebsite.ca:7776/SomeDirectory/MyWebService?WSDL'
Another quandary I've got is in regards to certificate management and deployment. I've got about 1000 external client sites that will need to use this little utility and they'll need the certificate installed in the appropriate cert store in order to connect to the Web Service. Not sure on the best approach to handling this. Do they need to be in the root store?
I've spent quite a few hours on the web looking over various options but can't get a good clean answer anywhere.
To summarize, I've got a couple of questions here:
1) Anybody have some good links on setting up Web Services in Visual Studio that use SSL?
2) How should I register the certificate? Which store should it exist in? Can I just use something like CertMgr to register it?
There's gotta be a good book/tutorial/whatever that will show me common good practices on setting something like this up. I just can't seem to find it!
Well, I've figured this out. It took me far longer than I care to talk about, but I wanted to share my solution since it's a HUGE pet peeve of mine to see the standard. "Oh I fixed it! Thanks!" posts that leave everyone hanging on what actually happened.
So.
The root problem was that by default Visual Studio 2008 uses TLS for the SSL handshake and the Oracle/Java based Webservice that I was trying to connect to was using SSL3.
When you use the "Add Service Reference..." in Visual Studio 2008, you have no way to specify that the security protocol for the service point manager should be SSL3.
Unless.
You take a static WSDL document and use wsdl.exe to generate a proxy class.
wsdl /l:CS /protocol:SOAP /namespace:MyNamespace MyWebService.wsdl
Then you can use the C Sharp Compiler to turn that proxy class into a library (.dll) and add it to your .Net projects "References".
csc /t:library /r:System.Web.Services.dll /r:System.Xml.dll MyWebService.cs
At this point you also need to make sure that you've included System.Web.Services in your "References" as well.
Now you should be able to call your web service without an issue in the code. To make it work you're going to need one magic line of code added before you instantiate the service.
// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
Okay, so I was feeling pretty impressed with myself as testing was great on my dev box. Then I deployed to another client box and it wouldn't connect again due to a permissions/authority issue. This smelled like certificates to me (whatever they smell like). To resolve this, I used certmgr.exe to register the certificate for the site to the Trusted Root on the Local Machine.
certmgr -add -c "c:\someDir\yourCert.cer" -s -r localMachine root
This allows me to distribute the certificate to our client sites and install it automatically for the users. I'm still not sure on how "security friendly" the different versions of windows will be in regards to automated certificate registrations like this one, but it's worked great so far.
Hope this answer helps some folks. Thanks to blowdart too for all of your help on this one and providing some insight.
It sounds like the web service is using a self signed certificate. Frankly this isn't the best approach.
Assuming you're a large organisation and it's internal you can setup your own trusted certificate authority, this is especially easy with Active Directory. From that CA the server hosting the Oracle service could request a certificate and you can use AD policy to trust your internal CA's root certificate by placing it in the trusted root of the machine store. This would remove the need to manually trust or accept the certificate on the web service.
If the client machines are external then you're going to have to get the folks exposing the service to either purchase a "real" certificate from one of the well known CAs like Verisign, Thawte, GeoTrust etc. or as part of your install bundle the public certificate and install it into Trusted Root certificate authorities at the machine level on every machine. This has problems, for example no way to revoke the certificate, but will remove the prompt.
Thanks for this great tip, took a quick look around at your stuff and you have a lot of good ideas going on. Here's my little bit to add -- I'm figuring out webMethods and (surprise!) it has the same problems as the Oracle app server you connected to (SSL3 instead of TLS). Your approach worked great, here's my addendum.
Given static class "Factory," provide these two handy-dandy items:
/// <summary>
/// Used when dispatching code from the Factory (for example, SSL3 calls)
/// </summary>
/// <param name="flag">Make this guy have values for debugging support</param>
public delegate void CodeDispatcher(ref string flag);
/// <summary>
/// Run code in SSL3 -- this is not thread safe. All connections executed while this
/// context is active are set with this flag. Need to research how to avoid this...
/// </summary>
/// <param name="flag">Debugging context on exception</param>
/// <param name="dispatcher">Dispatching code</param>
public static void DispatchInSsl3(ref string flag, CodeDispatcher dispatcher)
{
var resetServicePoint = false;
var origSecurityProtocol = System.Net.ServicePointManager.SecurityProtocol;
try
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;
resetServicePoint = true;
dispatcher(ref flag);
}
finally
{
if (resetServicePoint)
{
try { System.Net.ServicePointManager.SecurityProtocol = origSecurityProtocol; }
catch { }
}
}
}
And then to consume this stuff (as you have no doubt already guessed, but put a drum roll in here anyway):
var readings = new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading[] {
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 1, created = DateTime.Now.AddDays(-1), reading = 17.34, userID = 2
},
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 2, created = DateTime.Now.AddDays(-2), reading = 99.76, userID = 3
},
new ArchG2.Portal.wmArchG201_Svc_fireWmdReading.wmdReading() {
attrID = 3, created = DateTime.Now.AddDays(-5), reading = 82.17, userID = 4
}
};
ArchG2.Portal.Utils.wmArchG201.Factory.DispatchInSsl3(ref flag, (ref string flag_inner) =>
{
// creates the binding, endpoint, etc. programatically to avoid mucking with
// SharePoint web.config.
var wsFireWmdReading = ArchG2.Portal.Utils.wmArchG201.Factory.Get_fireWmdReading(ref flag_inner, LH, Context);
wsFireWmdReading.fireWmdReading(readings);
});
That does the trick -- when I get some more time I'll solve the threading issue (or not).
Since I have no reputation to comment, I'd like to mention that Mat Nadrofsky's answer and code sample for forcing SSL3 is also the solution for an error similar to
An error occurred while making the
HTTP request to https://xxxx/whatever.
This could be due to the fact that the
server certificate is not configured
properly with HTTP.SYS in the HTTPS
case. This could also be caused by a
mismatch of the security binding
between the client and the server.
Just use
// We're using SSL here and not TLS. Without this line, nothing workie.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
as mentioned by Mat. Tested with an SAP NetWeaver PI server in HTTPS. Thanks!
Mat,
I had such issues too and I have a way to avoid using certmgr.exe to add certificates to trusted root on a remote machine.
X509Store store;
store = new X509Store("ROOT", StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
The 'certificate object' can be created like this:
X509Certificate2 certificate = new X509Certificate2("Give certificate location path here");