SignalR Working on One Computer But Not Others - c#

We have a Windows service hosting SignalR. The same code is running on different machines, with different results.
If I go to this link on my laptop, it works:
https://localhost/signalr/negotiate
Response:
{
"Url":"/signalr",
"ConnectionToken":"AQAAANCMnd8BFdERjHoAwE/...==",
"ConnectionId":"0a09e290-c8af-48d6-b791-f05e3b8930b0",
"KeepAliveTimeout":20.0,
"DisconnectTimeout":30.0,
"ConnectionTimeout":110.0,
"TryWebSockets":false,
"ProtocolVersion":"1.2",
"TransportConnectTimeout":5.0,
"LongPollDelay":0.0
}
If I go to that same link on my desktop, I get this:
I checked the IE settings and the TLS settings are the same between my laptop and my desktop. I've also checked many other IE settings.
Edit: On good PC, get cert warning in browser. Doesn't happen on non-working PC.
Here is the code to get SignalR running:
protected override void OnStart()
{
LogUtility.LogInformation("SignalRHubHostController::OnStart()");
string url = this.Application.Configuration.SignalRHubHostController.HostUrl;
UriBuilder uri = new UriBuilder(url);
string schemeOverride = this.Application.Configuration.SignalRHubHostController.UriSchemeOverride;
if (!String.IsNullOrWhiteSpace(schemeOverride))
uri.Scheme = schemeOverride;
LogUtility.LogInformation(String.Format(CultureInfo.InvariantCulture, "Using [{0}] as the SignalR hub URL.", uri.Uri.ToString()));
this._disposableWebServer = WebApp.Start<Startup>(uri.Uri.ToString());
}
internal class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}

I got this to work. Apparently it was an issue with the existing certificate set to use port 443. I don't know why that was an issue, but the following steps caused things to start working for me.
Note: Rick Strahl's blog helped: Hosting SignalR under SSL/https
Created certificate in IIS specifically for this purpose:
Note: I did not have to use MMC to copy the cert from the personal folder to the trusted root folder. It was already in the trusted root folder.
Delete the existing cert dedicated to port 443:
netsh http delete sslcert 0.0.0.0:443
Note: I originally tried to add the cert and got an error because a cert was already specified for port 443. That's why this delete is here.
Add my new cert for port 443:
netsh http add sslcert ipport=0.0.0.0:443
appid={12345678-db90-4b66-8b01-88f7af2e36bf}
certhash=hashGoesHere
Note: Rick Strahl's blog said to always use that appid. I don't know what an appid means in the context of a cert. So, yeah, whatever...
Run my app and have it connect successfully:
Note: I'll need to use a real cert and trust it so I stop getting that warning. But that's not the point of this answer. I just wanted to show how I got this working with SignalR.
So while this got things working, I don't know why the original cert dedicated to port 443 wasn't working. Perhaps it wasn't in the root store. I couldn't figure out how to find that cert based on its hash on the PC.
Edit
For completeness, I wanted to share how you can get the cert hash. You can manually type it from looking at the certs in IIS, or you can copy it by finding it in MMC. It's the Thumbprint property of the cert. You just have to remove the spaces.

Related

IBM Webshpere MQ client connecting remote queue using SSL

I am trying to connect to the remote queues using secured SSL connection. I have all the details provided by third party regarding SSL connection and Queue Manager details. I have V8 version of MQ client installed on my windows machine.
SSL folder that thirdparty has shared contains jks,kdb,rdb and sth files.
I am using below code to initialize the properties in .net console application
const string SslKeyRepository = #"ssl folder location with key name included";
const string CipherSpec = "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
const string CipherSuite = "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
const string SslPeerName = "Peername";
const string ConnectionType = MQC.TRANSPORT_MQSERIES_CLIENT;
static Hashtable init(String connectionType)
{
Hashtable connectionProperties = new Hashtable
{
{MQC.TRANSPORT_PROPERTY, connectionType},
{MQC.PORT_PROPERTY, 1496},
{MQC.SSL_CERT_STORE_PROPERTY, SslKeyRepository},
{MQC.SSL_CIPHER_SPEC_PROPERTY, CipherSpec},
{MQC.SSL_PEER_NAME_PROPERTY, $"CN=\"{SslPeerName}\""}
};
// Add the connection type
// SSL
// Set up the rest of the connection properties, based on the
// connection type requested
switch (connectionType)
{
case MQC.TRANSPORT_MQSERIES_BINDINGS:
break;
case MQC.TRANSPORT_MQSERIES_CLIENT:
case MQC.TRANSPORT_MQSERIES_XACLIENT:
case MQC.TRANSPORT_MQSERIES_MANAGED:
connectionProperties.Add(MQC.HOST_NAME_PROPERTY, HostName);
connectionProperties.Add(MQC.CHANNEL_PROPERTY, Channel);
break;
}
return connectionProperties;
}
I have tried few things but I end up getting exception "MQRC_SSL_INITIALIZATION_ERROR"
I would appreciate if you can help me with this.
There are many reasons for MQRC_SSL_INITIALIZATION_ERROR. Some of them are mechanical issues such as whether the keystore files can be accessed. Some are procedural such as whether the handshake fails. The best way to diagnose is methodically checking the configuration and then performing differential testing.
For the first part of this, perform the following checks. If you have already done so, don't cut corners. Do it again.
Verify that the certificates are accessible by issuing runmqakm -cert -list against the KDB to verify that it is structurally intact and the stash file is present with the proper password.
Verify that the kdb file is not in a world-readable directory is that the files are not marked world-readable.
Verify that the service account that runs the app is the owner of the KDB files and containing folder and has write access. (Not sure why but GSKit insists that the KDB must be writeable at run time.)
Issue runmqakm -cert -details to verify that the certificate(s) corresponding to the queue manager is/are present and the details. If the QMgr uses a self-signed cert there will be only one. If the QMgr uses a CA-signed cert there should be an intermediate and a root signer.
Find out from the 3rd party whether they have specified SSLCAUTH(OPTIONAL) or SSLCAUTH(REQUIRED). If OPTIONAL then the KDB should have no personal certs, only signers. If REQUIRED then the KDB must have a personal cert and the label must be ibmwebspheremq[serviceaccount] in lower case.
For the differential testing, try some of the following tests:
Test the app by connecting to a local QMgr using TLS (Note: MQ hasn't used SSL for years. It's TLS now. The old field names still retain SSL labels, though.) until you know that it is correctly configured. Go grab a copy of MQ Advanced for Developers and you can do integration testing on the desktop with your own QMgr, fully licensed for free.
Test using one of the sample programs. Use amqsputc or amqsgetc, depending on whether the real app is supposed to have PUT or GET on the queue. These use the same KDB, samme certs, etc. the main difference being they are known-good code.
Ask your business partner to let you test without SSL to make sure the "mechanical" parts of the configuration are correct. This includes things like the firewall routing, host, port and channel name, QMgr name, etc. If you can't connect with plaintext channels, you definitely won't succeed with TLS channels.
Once that works, test with SSL enabled and SSLCAUTH(OPTIONAL) set at the QMgr. This demonstrates that the client can validate the QMgr's cert.
Once that works, and if the objective is to use mutual authentication, test with SSLCAUTH(REQUIRED) set at the QMgr and a personal cert in the local KDB. This demonstrates that the QMgr can validate the client's cert.
Then, and only then, turn on SSLPEER locally to filter on the QMgr cert's DN.
If these don't help, please update the question with detailed results of your testing. The most common issues include cert labels and KDB permissions. If the business partner gave you the JKS and KDB, these should generally not come with a personal cert, only trusted certs.

Identityserver fails to load selfsigned certificate

I'm trying to set a Certificate for identityserver and it keeps failing with a "no access to private key error".
Taking it out of identityserver, the following code throws an access denied error
static X509Certificate2 GetCertificateFromDisk()
{
using (var stream = File.Open(#"patht-to-pfx", FileMode.Open))
{
var cert = new X509Certificate2(ReadStream(stream), "password", X509KeyStorageFlags.MachineKeySet);
return cert;
}
}
When running the code as administrator it works fine, not when running it under my own account. Eventually I want to run it as localsystem.
I even added 'Everyone' under the certificates private key permissions in my local computer certificate store,
screenprint here
... still I get the exception.
What is wrong here? Going Crazy about it
Update
Great tips from CryptoGuy in the answer below. Important note: Opening the file is not correct only Identityserver3 still failed when getting the certificate from the store. What made it work was to regenerate the certificate using Keith Sparkjoy's tool SerfCert. My previous certificate was generated using powershell. So keep in mind that powershell certificates have issues with accessibility of private key. Thanks to Keith for the tool!
There are few things to consider.
1) you are performing write access to Local Machine store. X509KeyStorageFlags.MachineKeySet attempts to save private key to Local Machine store. Therefore, you need administrator permissions to write there. You should remove this flag to perform read-only access
2)
Documentation says that adding permissions in MMC (manage private key-option on a certificate) should allow this, but it doesn't seem to work
it works on an already saved private keys.
What you really should do is to import certificate and private key to Local Machine store and then configure your application to reference installed certificate.
3) if your application runs under unpriveleged account and the key don't need to be shared, then you should use Current User store.

Could not create SSL/TLS secure channel - works as exe but not in asp.net mvc

I have a problem with connectiong to an api over https. I wrote a little console application:
var handler = new WebRequestHandler();
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 mCert in store.Certificates)
{
// add my locale certificate
if (mCert.FriendlyName == "some_identifier_name")
handler.ClientCertificates.Add(mCert);
}
var httpClient = new HttpClient(handler);
var response= httpClient.GetAsync("https://url-to-my.com/api/something").Result;
var result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
This little script works fine, I get a statuscode 200 and also the json data from the api. As you can see I have a certificate installed on my local machine, which I add in the code.
I tried the same script on my webserver and everything works fine there too!
But if I run the script in my mvc application I still get the message "The request was aborted: Could not create SSL/TLS secure channel".
Where is the difference with the same code if I run it as an exe or as a mvc website?
PS: This code is not the answer to my question, I already tried it:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Solution: IIS > Applications Pools > Chose your Apppool > Advanced Settings > Identity > Change to LocalSystem
Seems like you have to give your application pool enough rights to read the certificate from your local machine.
After spending 2 to 3 days for above issue, found following solution and you don't want to change "Identity" to "LocalSystem" (In Apppool Advance setting),
run up mmc.exe and choose File->Add/Remove Snap-in, select certificates on the left-hand list and when it asks you, choose Computer Account and Local Computer. Click OK to exit the selection page.
Open up the Personal->Certificates folder under the snap-in you just enabled. It is possible, that the Certificates folder doesn't exist (if it is empty).
Right-click in the contents pane of Personal or Certificates and choose All Tasks->Import
Go through the wizard to import your certificate and select the option to "mark it exportable" which is usually needed for SSL usage (I think it includes the private key only when this is ticked).
With the certificate imported, select it, choose All Tasks->Manage Private Keys
You will get a familiar security dialog where you can add users who can access the private key. Add the account for the user that is running the application pool for your web site.
If you are using "App Pool Identity", then the users are found with IIS Apppool\app.pool.name Note that if you are running some versions of Windows Server, you will need to change the "location" parameter to point to the local machine rather than the domain which is selected by default, otherwise the user won't be found.
Reference : http://lukieb.blogspot.com/2015/04/the-request-was-aborted-could-not.html

SSL Certificates doesn't work

My problem is that I have an application on .net is mvc
The application make "Facturas Electronicas" for the company that I work.
If I run the application on my computer from the visual studio, the application works fine.
But if I publish the app to another server the application doesn't make the "Factura Electronica", but before this erros the application works fine on other servers.
All started when I publish another app with the same code, and needs the same certificates but it is to other product and i need the two applications.
After checking all the code I realize that the problem was the certificate a pfx file,
when the app try to execute this
X509Certificate2 cert = new X509Certificate2(certificadoDemo, claveCertificadoDemo);
the navigator return this
This webpage is not available
the expiration of the pfx file is until july 2014
Do anyone knows what is going on?
adding this
X509KeyStorageFlags.MachineKeySet
to that line of code i resolved the problem
this is the new line of code
X509Certificate2 cert = new X509Certificate2(certificadoDemo, claveCertificadoDemo, X509KeyStorageFlags.MachineKeySet);
thanks
Your question cannot be answered without a detailed exception. Either turn off customErrors in the web.config file (in which case, the entire exception will be sent to the browser) or catch errors in Global.asax Application_Error event handler and log the errors to a file somehow (using System.Diagnostics preferably). Without more sample code, we can't even know which constructor you're calling because X509Certificate2 has 5 constructors which take two parameters. See http://sscce.org/ on how to ask questions.

Implement a C# Client that uses WebServices over SSL?

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");

Categories

Resources