Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SslStream client on Linux incorrectly reports that it is mutually authenticated #40314

Closed
smbz opened this issue Aug 4, 2020 · 4 comments · Fixed by #63945
Closed

SslStream client on Linux incorrectly reports that it is mutually authenticated #40314

smbz opened this issue Aug 4, 2020 · 4 comments · Fixed by #63945
Labels
area-System.Net.Security help wanted [up-for-grabs] Good issue for external contributors os-linux Linux OS (any supported distro)
Milestone

Comments

@smbz
Copy link

smbz commented Aug 4, 2020

Description

When using SslStream.AuthenticateAsClient with a client certificate, IsMutuallyAuthenticated is set to true even if the server did not request a client certificate and the client didn't send one. It should be false, as the client has not authenticated itself to the server (which is the behaviour on Windows).

I've written a short demo program: smbz/IsMutuallyAuthenticatedDemo. Just so it's here, the core is:

string host = "www.microsoft.com";
TcpClient client = new TcpClient(host, 443);

SslStream stream = new SslStream(client.GetStream());
stream.AuthenticateAsClient(host, clientCertificateCollection, SslProtocols.None, true);

After the call to AuthenticateAsClient, stream.IsMutuallyAuthenticated is false on Windows but true on Linux.

Configuration

This affects Linux but not Windows (I'm not sure about Mac).

Platform details:

  • .NET Core 3.1.302
  • OpenSSL 1.1.1d
  • Debian 10

Other information

A Wireshark dump verifies that the server doesn't request a client certificate. I can provide the dump file if needed, but I won't make it public because of MAC addresses.

This is not a security vulnerability because it does not affect the authentication of the client to the server or the server to the client. It only makes the client think that it has authenticated itself to the server.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Net.Security untriaged New issue has not been triaged by the area owner labels Aug 4, 2020
@ghost
Copy link

ghost commented Aug 4, 2020

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

@wfurt
Copy link
Member

wfurt commented Aug 4, 2020

It seems like the code looks for availability of certificate for both sides. As you mentioned, that does not proof that sever actually asked for it. I don't know if OpenSSL has API to track that.

@wfurt wfurt added help wanted [up-for-grabs] Good issue for external contributors and removed untriaged New issue has not been triaged by the area owner labels Aug 4, 2020
@wfurt wfurt added this to the Future milestone Aug 4, 2020
@wfurt wfurt added the os-linux Linux OS (any supported distro) label Aug 4, 2020
@Serg046
Copy link
Contributor

Serg046 commented Aug 22, 2020

The flag is false on Windows because of the following line
https://github.com/dotnet/runtime/blob/master/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs#L592
_context.LocalClientCertificate is null if that clientCertificate is null.
Seems the line is not executed on Linux.

@rzikm rzikm self-assigned this Jan 6, 2022
@rzikm
Copy link
Member

rzikm commented Jan 10, 2022

The _context.LocalClientCertificate happens to be null on Windows because SslStreamPal.StartMutualAuthAsAnonymous is true on Windows, and the client certificate gets nulled at https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Security/src/System/Net/Security/SecureChannel.cs#L584 the first time AcquireClientCredentials is called. If server requests the client certificate, then AcquireClientCredentials is called again and full credentials are provided.

On Linux (and OSx as well), the StartMutualAuthAsAnonymous is false, so the LocalClientCertificate property gets always populated if client certificate was provided by the user. However, OpenSSL does not provide an easy way to check if the client certificate was actually requested by the server. The only way we could find out is to rewrite the code to always use cert callbacks (either using SSL_set_cert_cb or SSL_CTX_set_client_cert_cb) and note down if the callback was called during the handshake process.

#63200 already adds usage of SSL_set_cert_cb to support (.NET-side) certificate selection callback, so I suggest to revisit this issue once that PR is merged and try building on those changes.

@rzikm rzikm assigned rzikm and unassigned rzikm Jan 10, 2022
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jan 18, 2022
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jan 26, 2022
@rzikm rzikm removed their assignment Feb 14, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Mar 16, 2022
@karelz karelz modified the milestones: Future, 7.0.0 Apr 8, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Net.Security help wanted [up-for-grabs] Good issue for external contributors os-linux Linux OS (any supported distro)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants