SignalR with Self-Signed SSL and Self-Host - ssl

Tried my luck at research, but so far no joy.
I would like to connect a SignalR javascript client to a self-hosted SignalR Windows Service binding to a self-signed SSL certificate.
My application works quite well over http, but the client repetitively disconnects when the Owin WebApplication starts using https.
Here is what I've done to configure SignalR with SSL.
Created a Self-Signed certificate using IIS
Imported the certificate into the Trusted Root Certification Authorities in the mmc (not sure if that helped)
Ran NETSH command to bind SSL to port 8080
netsh http add sslcert ipport=0.0.0.0:8080 certhash=123456f6790a35f4b017b55d09e28f7ebe001bd appid={12345678-db90-4b66-8b01-88f7af2e36bf}
Added code in self-hosted HubConnection instances to add exported SSL like this (though this shouldn't matter because it's the client that cannot connect):
if (File.Exists("MyCert.cer")
&& Settings.GetSetting(Settings.Setting.SrProtocol).Equals("https", StringComparison.InvariantCultureIgnoreCase))
connection.AddClientCertificate(X509Certificate.CreateFromCertFile("MyCert.cer"));
Starting Owin WebApplication using https (this should create the binding in http.sys)
string registerUrl = string.Format("{0}://SOME.WHERE.COM:{1}", Service.Server.SrProtocol, Service.Server.SrPort);
WebApp.Start<StartUp>(registerUrl);
In the SignalR 2.0 documentation, it says:
To start the web server, call WebApplication.Start(endpoint). You should now be able to navigate to endpoint/signalr/hubs in your browser.
When I browse to the URL http://SOME.WHERE.COM:8080/signalr/hubs I am successful receiving the javascript that drives SignalR.
When I browse to the URL https://SOME.WHERE.COM:8080/signalr/hubs I am unsuccessful and I receive "The connection to the server was reset" using FF.
Some additional points I've considered:
NETSH SHOW indicates the url is registered
URL group ID: E300000240000022
State: Active
Request queue name: Request queue is unnamed.
Properties:
Max bandwidth: inherited
Max connections: inherited
Timeouts:
Timeout values inherited
Number of registered URLs: 1
Registered URLs: HTTPS://SOME.WHERE.COM:8080/
NETSH SHOW indicates the SSL certificate is bound to 8080:
IP:port : 0.0.0.0:8080
Certificate Hash : 123456f6790a35f4b017b55d09e28f7ebe001bd
Application ID : {12345678-db90-4b66-8b01-88f7af2e36bf}
Certificate Store Name : (null)
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
Any help is greatly appreciated!

I believe its all working for me now. Here is a run down of the steps I took to get things flowing:
SSL NOTES
SSL & SignalR (Owin WebApplication) requires binding a certificate to a port.
Use IIS to generate an self-signed cert, this should place the certificate into the LOCAL COMPUTER > Personal > Certificates folder in CERTMGR
In CERTMGR shift+drag certificate to LOCAL COMPUTER > Trusted Root Certification Authorities > Certificates folder, which should make a copy of it there
Run the following command to bind the SSL certificate to 0.0.0.0:8080
netsh http add sslcert ipport=0.0.0.0:8080 certhash=123456f6790a35f4b017b55d09e28f7ebe001bd appid={12345678-db90-4b66-8b01-88f7af2e36bf}
netsh http show urlacl > D:\urlacl.txt
Output:
Reserved URL : https://*:8080/
User: SOMEWHERE\Administrator
Listen: Yes
Delegate: No
SDDL: D:(A;;GX;;;S-1-5-21-138209071-46972887-2260295844-1106)
Run the following NETSH command to reserve all IP addresses for port 8080 to the My Service application ID and service account
netsh http add urlacl url=https://*:8080/ user=SOMEWHERE\Administrator listen=yes
netsh http show sslcert > D:\sslcert.txt
Output:
IP:port : 0.0.0.0:8080
Certificate Hash : 123456f6790a35f4b017b55d09e28f7ebe001bd
Application ID : {12345678-db90-4b66-8b01-88f7af2e36bf}
Certificate Store Name : (null)
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
Update the MyServices.exe.config file to use https protocol (These are appSetting keys used to dynamically set the protocol and port of SignalR when My Service starts)
<add key="SrProtocol" value="https" />
<add key="SrPort" value="8080" />
Start the My Service using the NETSTAT START command
Run the following NETSH command to show the service state is occupying the registered url
netsh http show servicestate > D:\servicestate.txt
Output:
Server session ID: C300000320000039
Version: 2.0
State: Active
Properties:
Max bandwidth: 4294967295
Timeouts:
Entity body timeout (secs): 120
Drain entity body timeout (secs): 120
Request queue timeout (secs): 120
Idle connection timeout (secs): 120
Header wait timeout (secs): 120
Minimum send rate (bytes/sec): 150
URL groups:
URL group ID: C600000340000138
State: Active
Request queue name: Request queue is unnamed.
Properties:
Max bandwidth: inherited
Max connections: inherited
Timeouts:
Timeout values inherited
Number of registered URLs: 1
Registered URLs:
HTTPS://*:8080/
My application does NOT depend on IIS, but once I used IIS to temporarily create a port binding to my SSL certificate, my application started to work, and I was able to inspect the NETSH servicestate to see how IIS does it. I have since dropped the IIS binding and ran through the setup notes, and still have success.
My Owing startup looks somethign like this:
private void configureMessaging()
{
string registerUrl = string.Format("{0}://*:{1}", Service.Server.SrProtocol, Service.Server.SrPort);
try
{
#if DEBUG
//System.Diagnostics.Debugger.Launch();
#endif
// Starts an owin web application to host SignalR, using the protocol and port defined.
WebApp.Start<StartUp>(registerUrl);
}
catch (Exception ex)
{
Logger.Logs.Log(string.Format("Failed to configure messaging. Exception: {0}", ex.RecurseInnerException()), LogType.Error);
if (ex is HttpListenerException || ex.InnerException is HttpListenerException)
{
try
{
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "netsh.exe";
p.StartInfo.Arguments = string.Format("netsh http delete urlacl url={0}"
, registerUrl
);
p.Start();
p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
catch (Exception exP)
{
Logger.Logs.Log(string.Format("Failed to delete urlacl {0}. Exception: {1}"
, registerUrl
, exP.RecurseInnerException()
)
, LogType.Error
)
;
retries = 5;
}
}
if (retries < 5)
{
retries++;
Logger.Logs.Log(string.Format("Attempting to configure messaging again. Attempt No. {0}", retries), LogType.Warn);
Thread.Sleep(1000);
configureMessaging();
}
else
Logger.Logs.Log(string.Format("Exceeded total number of retries to configure messaging.", retries), LogType.Error);
}
}
And self-hosted HubConnetion instances look like this:
public IHubProxy MyHubProxy
{
get
{
if (this._MyHubProxy == null)
{
var connection = new HubConnection(string.Format("{0}://{1}:{2}/"
, Settings.GetSetting(Settings.Setting.SrProtocol)
, MyHub.GetLocalhostFqdn(null)
, Settings.GetSetting(Settings.Setting.SrPort)
)
)
;
this._MyHubProxy = connection.CreateHubProxy("MyHub");
if (File.Exists("My.cer")
&& Settings.GetSetting(Settings.Setting.SrProtocol).Equals("https", StringComparison.InvariantCultureIgnoreCase))
connection.AddClientCertificate(X509Certificate.CreateFromCertFile("My.cer"));
connection.Start().Wait();
}
return this._MyHubProxy;
}
}
There is a little more code here than relevant, but hopefully it may be of help!

Related

How to connect to a gRPC Server hosted in Kestrel as HTTPS from a gRPC C++ Client using default certificates (Windows 10)?

I am using ASP.Net Core (Grpc.Net) for creating a HTTPS gRPC server hosted in Kestrel. The communication between C# Client to the server (HTTPS) works fine with out adding any certificate.
It looks like they are using the default certificates for communication.
Now I have a C++ gRPC Client in Windows 10 and I'm trying to connect to the same server from a client, the endpoint is https://localhost:50051.
This is my Kestrel configuration #server.
webBuilder.ConfigureKestrel(serverOptions =>
{
serverOptions.Listen(IPAddress.Any, 50051, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
listenOptions.UseHttps();
});
}).UseStartup<Startup>();
As you could see I am not using certificates in the server (wanted to use default certificates) the same way I used C# gRPC Client.
i.e. connection to server works using C# Client
var channel = GrpcChannel.ForAddress("https://localhost:50051");
ecgDataClient = new Data.DataClient(channel);
But with C++ gRPC Client Client I am unable to connect (tried both InSecure & SslCredentials):
auto channel_creds = grpc::SslCredentials(grpc::SslCredentialsOptions());
DataGrpcClient grpcClient( grpc::CreateChannel("localhost:50051", channel_creds));
With grpc::SslCredentials(grpc::SslCredentialsOptions()) I get this error:
E0709 19:46:20.488000000 6724 ssl_utils.cc:570] load_file: {"created":"#1625840180.488000000","description":"Failed to load file","file":"D:\DEV\vcpkg\buildtrees\grpc\src\17cc203898-db2679e7f2.clean\src\core\lib\iomgr\load_file.cc","file_line":72,"filename":"/usr/share/grpc/roots.pem","referenced_errors":[{"created":"#1625840180.488000000","description":"No such file or directory","errno":2,"file":"D:\DEV\vcpkg\buildtrees\grpc\src\17cc203898-db2679e7f2.clean\src\core\lib\iomgr\load_file.cc","file_line":45,"os_error":"No such file or directory","syscall":"fopen"}]}
E0709 19:46:20.509000000 6724 ssl_security_connector.cc:413] Could not get default pem root certs.
E0709 19:46:20.512000000 6724 secure_channel_create.cc:108] Failed to create secure subchannel for secure name 'localhost:50051'
E0709 19:46:20.517000000 6724 secure_channel_create.cc:50] Failed to create channel args during subchannel creation.
E0709 19:46:20.521000000 6724 ssl_security_connector.cc:413] Could not get default pem root certs.
E0709 19:46:20.525000000 6724 secure_channel_create.cc:108] Failed to create secure subchannel for secure name 'localhost:50051'
E0709 19:46:20.529000000 6724 secure_channel_create.cc:50] Failed to create channel args during subchannel creation.
It looks like unable to find the default certificates.
I am running my C++ gRPC Client in Windows 10, should I need to do anything so that the client picks the default certificates?
Thanks
Basanth

Kestrel Fails TLS Handshake after Attempt to Download Intermediate Certificate Fails

Kestrel's web server is timing out, saying Connection Closed, after loading a publicly-signed SSL Certificate.
Background - we have a docker container that hosts a dotnet 3.1 webapi/react app, where the user can upload a custom SSL certificate. The PKCS#12 certificate is stored in our database and bound at startup using .ConfigureKestrel((context,options)) and options.ConfigureHttpsDefaults(listenOptions=>{listenOptions.ServerCertificate = certFromDatabase; }). This has been working flawless.
However, the problem now is that a user is attempting to run this app in a restrictive firewalled environment and is receiving HTTP connection closed errors when attempting to access Kestrel immediately after loading a new certificate and restarting the app.
Whenever Kestrel receives an incoming request, it begins attempting to download the intermediate certificate from the certificate's CA's public CDN repository via http on port 80. It appears to be using the URL from the Authority Information Access portion of the certificate. Since the firewall is blocking this, it retries repeatedly for about 20 seconds, during which time the client's TLS handshake sits waiting on a server response. When the server eventually fails to fetch the intermediate certificate, it cancels the TLS handshake and closes the connection.
I can't figure out why it's attempting to download this certificate, considering the same certificate is embedded in the PKCS#12 PFX bundle that is bound to Kestrel. Am I supposed to load either the root CA or intermediate into the CA trust folder in file system? (Ex. /usr/local/share/ca-certificates/ - I can't load the intermediate there, only the CA?)
public static IWebHost BuildFullWebHost(string[] args)
{
var webHostBuilder = GetBaseWebHostBuilder(args);
return webHostBuilder
.ConfigureAppConfiguration((context, builder) => { [...] })
.ConfigureLogging((hostingContext, logging) => { [...] })
.UseStartup<Startup>()
.ConfigureKestrel((context, options) =>
{
var sp = options.ApplicationServices;
using (var scope = sp.CreateScope())
{
var dbContext = scope.ServiceProvider.GetService<DbContext>();
var cert = Example.Services.HttpsCertificateService.GetHttpsCert(dbContext);
//this returns a new X509Certificate2(certificate.HttpsCertificate, certificate.Password);
options.ConfigureHttpsDefaults(listenOptions =>
{
listenOptions.ServerCertificate = cert;
listenOptions.CheckCertificateRevocation = false;
});
}
})
.Build();
}
Not a great solution, but upgrading to .NET 5.0 resolved the issue. It seems that in .NET 5.0, Kestrel attempts to fetch the certificate chain during initial application startup only (and fails). Subsequent incoming HTTP requests don't trigger the fetch process and requests are served as expected.

Can't Start IIS Express: An error occurred attempting to determine the process id

When I try to start my ASP.Net Core 1.1 app, I'm receiving the following error:
An error occurred attempting to determine the process id of Blah.exe which is hosting your application. An error occurred while sending the request.
I changed the applicationUrl port number from 44300 to 44301 in `launchSettings.json' and I was able to get it to start.
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "https://localhost:44301/",
"sslPort": 44301
}
}
Why did changing the port # make it work? Where can I look to figure out why it wouldn't startup?
I ran TCPViewer and I don't see 44300 in use.
Uninstall and re-install of IIS Express fixed it.
Turns out port 44300 wasn't bound to my IIS Express cert. Bill Hiebert figured it out as documented in this developer community issue.
When I ran netsh http show sslcert, port 44300 wasn't listed. I uninstalled and re-installed IIS Express and now it is listed.
SSL Certificate bindings:
-------------------------
IP:port : 0.0.0.0:44300
Certificate Hash : somevalue
Application ID : {someid}
Certificate Store Name : MY
Verify Client Certificate Revocation : Enabled
Verify Revocation Using Cached Client Certificate Only : Disabled
Usage Check : Enabled
Revocation Freshness Time : 0
URL Retrieval Timeout : 0
Ctl Identifier : (null)
Ctl Store Name : (null)
DS Mapper Usage : Disabled
Negotiate Client Certificate : Disabled
Reject Connections : Disabled
Disable HTTP2 : Not Set

Certificate based authentication in WCF

I am trying to understand certificate based authentication using the msdn sample https://msdn.microsoft.com/en-us/library/ms731074(v=vs.90).aspx
This is the server code:
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
// Create the URI for the endpoint.
Uri httpUri = new Uri("https://localhost/Calculator");
// Create the service and add an endpoint.
ServiceHost myServiceHost = new ServiceHost(typeof(ServiceModel.Calculator), httpUri);
myServiceHost.AddServiceEndpoint(typeof(ServiceModel.ICalculator), binding, "");
// Open the service.
myServiceHost.Open();
Console.WriteLine("Listening...");
Console.ReadLine();
// Close the service.
myServiceHost.Close();
This is the client code I wrote:
ChannelFactory<ICalculator> factory = null;
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
EndpointAddress address = new EndpointAddress("https://localhost/Calculator");
factory = new ChannelFactory<ICalculator>(binding, address);
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
factory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My, X509FindType.FindBySubjectName, "sroger");
ICalculator channel = factory.CreateChannel();
int y = channel.add(9, 8);
I am getting the following exception:
An unhandled exception of type 'System.ServiceModel.CommunicationException' occurred in mscorlib.dll
Additional information: An error occurred while making the HTTP request to https://localhost/Calculator. 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.
I am running both client and server from the same machine. And "sroger" is the certificate in my current user\ personal\certificates which corresponds to my machine name..
Not sure what to do from here..Any thoughts?
In the server code what certificate server uses?
Thanks
Gulumal.
https://msdn.microsoft.com/en-us/library/ms731074(v=vs.90).aspx example you used is incomplete.
Consuming https wcf service requires a valid server certificate to work, in your case both client and server certificates are required.
This is because both client and server need to trust each other in a HTTPS connection.
To get started, read https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/message-security-with-mutual-certificates which is a more complete example that includes specifying certificate to authenticate the service.
For a hosted WCF library via https to work you need to do the following in order:
Configure the port with an X.509 certificate (which has been
answered in
webHttpBinding with certificate)
From your server, create certificate request for common name of your
server fully qualified domain name, or at-least including a DNS subjectAltName of your server fully qualified domain name.
(there are different ways to do this, you may already know this
though)
Issue certificate and install certificate on your server
Grab application id from assembly file of your App that hosts WCF
library (i.e [assembly:
Guid("5870aeed-caca-4734-8b09-5c0615402bcf")]) Grab the certificate
thumbprint by viewing certificate properties.
As administrator, open
CMD and run this command to bind X.509 certificate to the port used
by your app on server
netsh http add sslcert ipport=0.0.0.0:443 certhash= appid={} certstorename=MY
netsh http add iplisten ipaddress=0.0.0.0:443
Add this to your server code:
myServiceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySerialNumber, "<certificate thumbprint>");
In your client code, reference your server address by fully qualified domain name that certificate that is specified as certificate Common Name or subject Alt Name

couldn't setup local SOCKS5 proxy on port 7777: Address already in use: JVM_Bind

while sending meessage from agent present in spark to client present in client application
im getting following error
couldn't setup local SOCKS5 proxy on port 7777: Address already in use: JVM_Bind
the code i wrote for sending message to client is .. bellow..
i wrote the following method in the class, implemented org.jivesoftware.smackx.workgroup.agent.OfferListener
Message message1 = new Message();
message1.setBody(message);
try {
for (MultiUserChat muc : GlobalUtils.getMultiuserchat()) {
if (muc.getRoom().equals(conf)) {
muc.sendMessage(message1);
System.out.println("message sent ############# agent to client..");
}
}
} catch (Exception ex) {
System.out.println("exception while sending message in sendMessage() ");
ex.printStackTrace();
}
help me
thanks
rajesh.v
it was because you was running your server with your client on the same machine.
You know... I assume you use openfire for the server..
Openfire use port 7777 by default for file transfer proxy service and it was enabled by default.
and your client do the same by using the port 7777 for the default file transfer.
look at openfire setting at the Server Settings > File Transfer Setting.
You can disable it.
or just run your client and your server on different machine.
I think you are in development state so your server and your client on the same machine
What is the payload of your message - are there any & in it - not sure why, but this seems to trip up smack