dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.26k stars 4.73k forks source link

ClientWebSocket client certificate not working with .NET Core #21916

Closed mvput closed 4 years ago

mvput commented 7 years ago

Using the ClientWebSocket to establish a secure WebSocket connection with client certificates. The project is targeting netcoreapp1.1. With the following code, the ConnectAsync throws an exception: WinHttpException: A certificate is required to complete client authentication. When changing the TFM to net461 the connection is successfully established. I removed the template id of the certificate for security reasons.

ClientWebSocket client = new ClientWebSocket();

X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var cert = store.Certificates.Find(X509FindType.FindByTemplateName, "<templateid>", true);

client.Options.ClientCertificates = new X509CertificateCollection();
client.Options.ClientCertificates.Add(cert[0]);
client.ConnectAsync(new Uri("wss://localhost:44301/path"), CancellationToken.None).Wait();
davidsh commented 7 years ago

This is a known issue. WebSocketOptions is not supported/implemented yet on .NET Core.

davidsh commented 7 years ago

Dupe of dotnet/runtime#15994.

pinchizzo commented 6 years ago

Is it resolved?

stephentoub commented 6 years ago

Is it resolved?

Yes, in .NET Core 2.1 ClientCertificates should work.

pinchizzo commented 6 years ago

So what am I doing wrong then? I get the same error as above when trying to create similar websocket request to visualization tool Qlik as in this Node.js example:

image

https://help.qlik.com/en-US/sense-developer/April2018/Subsystems/EngineAPI/Content/GettingStarted/connecting-to-engine-api.htm

Here is my code snippet:

var certificate = this.LoadQlikCertificate(); X509CertificateCollection certCollection = new X509CertificateCollection(); certCollection.Add(certificate);

ClientWebSocket ws = new ClientWebSocket(); ws.Options.ClientCertificates = certCollection; ws.Options.SetRequestHeader("X-Qlik-User", "UserDirectory=internal; UserId=sa_engine"); await ws.ConnectAsync(new Uri(qlikRef.EngineApiUrl), CancellationToken.None);

Error message: {System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server ---> System.Net.Http.WinHttpException (80072F0C, 12044): A certificate is required to complete client authentication at System.Net.WebSockets.WinHttpWebSocket.d18.MoveNext() at System.Net.WebSockets.WebSocketHandle.d22.MoveNext()}

Certificate should be ok as I use it in REST API without any problem. I'm using .NET Core 2.1. preview.

Many thanks. Michal

davidsh commented 6 years ago

System.Net.Http.WinHttpException (80072F0C, 12044): A certificate is required to complete client authentication at System.Net.WebSockets.WinHttpWebSocket.d__18.MoveNext()

This tells me that you aren't running against .NET Core 2.1. WinHTTP is only used for WebSocket on .NET Core 2.0.

Please re-target your app to .NET Core 2.1.

To validate what .NET Core version you are running against, you can add code like this to your app:

Console.WriteLine($"(Framework: {Path.GetDirectoryName(typeof(object).Assembly.Location)})");
davidsh commented 6 years ago

Also, please try out the final .NET Core 2.1 release: https://blogs.msdn.microsoft.com/dotnet/2018/05/30/announcing-net-core-2-1/

pinchizzo commented 6 years ago

Finally updated SDk and Websocket works!

Great! Many thanks David!

m