-
Notifications
You must be signed in to change notification settings - Fork 4.6k
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
Http client certificate authorization regression in .NET 5 #47580
Comments
Tagging subscribers to this area: @dotnet/ncl Issue DetailsDescriptionAfter our project was updated to .NET 5 we found serious regression when trying to send certificate authorized HTTP request using HttpClient to our partner's API and were forced to roll back to .NET Core 3.1 where it works normally. The problem is a little tricky to reproduce. It is reproducible only when a client is running on a Linux environment (we are using an official docker image based on Debian Buster). The problem is not reproducible on Windows 10. What it looked like: To reproduce the problem on Linux we created a simple console application. The code creates HttpClient with certification authorization handler in a loop and tries to make a request to the partner's API. The only first request was successful, the others failed with 401 error. In order to investigate the problem by ourselves, we tried to debug .NET internal libraries' code, but we have not found any obvious errors. The only clue was SSL cache. Clearing cache between requests solves the problem, but we have no idea what is wrong with it. We obviously can't share the production certificate with the private key and provide access to the partner's API, so I've created an alternative server and certificate. The server is written in Go for simplicity and the certificate is issued by Let's Encrypt. We weren't able to reproduce the problem using a self-signed certificate issued by self-signed CA, so we suspect that the problem is somewhere in certificate chain handling. You can reproduce the problem using the client, server, and certificate provided in the repository below following the instructions: Configuration
Regression?Yes, the problem is not observable using .NET Core 3.1. Other informationIf you use provided client and server, you will see that the first two requests are successful, then the following two will throw an exception, and the last one will be successful again:
At the same time go server will print this error to standard output:
|
Thanks for the repro case. I was able to reproduce it on Ubuntu 18 as well. In the failing handshake, client sends only the provided certificate. In case of the successful case it sends the full chain. I'll take a look why this is happening and why this is not consistent as it should. It should be sufficient IMHO to feed the intermediate CA to the server. (e.g. feed the give the ca.crt) Note that the server does not send the chain either - as it should. It works because of the hijacked validation callback. In "normal" case, .NET would try to fetch the chain but it seems like GO does not try it and simply fail. |
@wfurt Unfortunately we can't change software on the partner's side and thereby fix the problem. |
I think this is regression caused by #38364 and I have preliminary fix. I need to work out test cases. |
@wfurt I have also reproduced the bug on Mac OS 11.2. All 5 requests are failing with exception:
.NET Core 3.1 works fine. |
reopening for servicing |
@SukharevAndrey +1 thanks for providing such a good actionable repro case. |
fix will come out in 5.0.4. |
Description
After our project was updated to .NET 5 we found serious regression when trying to send certificate authorized HTTP request using HttpClient to our partner's API and were forced to roll back to .NET Core 3.1 where it works normally.
The problem is a little tricky to reproduce. It is reproducible only when a client is running on a Linux environment (we are using an official docker image based on Debian Buster). The problem is not reproducible on Windows 10.
What it looked like:
After an updated version of our service was released we noticed HTTP requests with certificate authorization started to fail (status code 401) after several successful attempts and then never succeeded again until the service was redeployed. Then we started to debug the application on Windows, but it worked just fine.
To reproduce the problem on Linux we created a simple console application. The code creates HttpClient with certification authorization handler in a loop and tries to make a request to the partner's API. The only first request was successful, the others failed with 401 error.
If we use the same HttpClient for every request then all works fine.
If we create two identical http handlers and corresponding HttpClients, then we try to send requests one by one, then requests made by the first client will succeed while requests made by the second one will fail (the order does not matter). If we will clean SSL sessions cache using reflection before making requests by the other client, it will also work fine. You can see that version of the code in the repository below.
When using .NET Core 3.1 all the requests are made successfully.
In order to investigate the problem by ourselves, we tried to debug .NET internal libraries' code, but we have not found any obvious errors. The only clue was SSL cache. Clearing cache between requests solves the problem, but we have no idea what is wrong with it.
We obviously can't share the production certificate with the private key and provide access to the partner's API, so I've created an alternative server and certificate. The server is written in Go for simplicity and the certificate is issued by Let's Encrypt. We weren't able to reproduce the problem using a self-signed certificate issued by self-signed CA, so we suspect that the problem is somewhere in certificate chain handling.
You can reproduce the problem using the client, server, and certificate provided in the repository below following the instructions:
https://github.com/SukharevAndrey/CertificateAuthBugReproduce
Configuration
.NET 5.0.2
Debian Buster
x64
Regression?
Yes, the problem is not observable using .NET Core 3.1.
Other information
If you use provided client and server, you will see that the first two requests are successful, then the following two will throw an exception, and the last one will be successful again:
At the same time go server will print this error to standard output:
The text was updated successfully, but these errors were encountered: