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

Unable to send multiple certificates in request using .net core 3.1 within HttpClientHandler #66660

Closed
jaden-patel opened this issue Mar 15, 2022 · 9 comments

Comments

@jaden-patel
Copy link

jaden-patel commented Mar 15, 2022

Description

The code below is only sending 1 certificate even though it loops through 4 certificates and finds 4 certificates

 var handler = new HttpClientHandler();

handler.ClientCertificateOptions = ClientCertificateOption.Manual;

X509Certificate2Collection certColection = new X509Certificate2Collection();
certColection.Import(clientCertPath);

foreach (X509Certificate2 cert in certColection)
{
    handler.ClientCertificates.Add(cert);
    Log.Information($"Added certificate:");
    Log.Information($"Subject: {cert.Subject}");
    Log.Information($"Issuer: {cert.Issuer}");
    Log.Information($"Thumbprint: {cert.Thumbprint}");
}

Log.Information($"Number of client certificates found in handler: {handler.ClientCertificates.Count}");

using (var httpClient = new HttpClient(handler))
{
    using (var request = new HttpRequestMessage(new HttpMethod("POST"), apiEndPoint))
    {
        request.Headers.TryAddWithoutValidation("accept", "application/json");
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);

        request.Content = new StringContent(JsonConvert.SerializeObject(input), Encoding.UTF8, "application/json");
        request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");

        return await httpClient.SendAsync(request);
    }
}

Reproduction Steps

Follow code above

Expected behavior

Expect the code to send multiple certificates

Actual behavior

Sending 1 certificate

Regression?

No response

Known Workarounds

No response

Configuration

.net core 3.1
Windows

Other information

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added area-System.Net.Http untriaged New issue has not been triaged by the area owner labels Mar 15, 2022
@ghost
Copy link

ghost commented Mar 15, 2022

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

Issue Details

Description

The code below is only sending 1 certificate even though it loops through 4 certificates and finds 4 certificates

 var handler = new HttpClientHandler();

                handler.ClientCertificateOptions = ClientCertificateOption.Manual;

                X509Certificate2Collection certColection = new X509Certificate2Collection();
                certColection.Import(clientCertPath);

                foreach (X509Certificate2 cert in certColection)
                {
                    handler.ClientCertificates.Add(cert);
                    Log.Information($"Added certificate:");
                    Log.Information($"Subject: {cert.Subject}");
                    Log.Information($"Issuer: {cert.Issuer}");
                    Log.Information($"Thumbprint: {cert.Thumbprint}");
                }

                Log.Information($"Number of client certificates found in handler: {handler.ClientCertificates.Count}");

                using (var httpClient = new HttpClient(handler))
                {
                    using (var request = new HttpRequestMessage(new HttpMethod("POST"), apiEndPoint))
                    {
                        request.Headers.TryAddWithoutValidation("accept", "application/json");
                        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);

                        request.Content = new StringContent(JsonConvert.SerializeObject(input), Encoding.UTF8, "application/json");
                        request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");

                        return await httpClient.SendAsync(request);
                    }
                }

Reproduction Steps

Follow code above

Expected behavior

Expect the code to send multiple certificates

Actual behavior

Sending 1 certificate

Regression?

No response

Known Workarounds

No response

Configuration

.net core 3.1
Windows

Other information

No response

Author: jaden-patel
Assignees: -
Labels:

area-System.Net.Http, untriaged

Milestone: -

@rzikm
Copy link
Member

rzikm commented Mar 15, 2022

Why do you expect the code to send multiple certificates?

The underlying SslStream selects one at most one certificate (based on whether client cert is required and on the acceptable issuers specified by the server) and will use that one for the connection. That is how SSL/TLS works.

Even though the client may also send other certificates to form a chain from the selected chain to some root trusted certificate (for verification purposes), these generally are not the ones in the client certificate collection.

@jaden-patel
Copy link
Author

The request URL expects multiple certificates in order to be able to send a POST request

@jaden-patel
Copy link
Author

Our PFX contains multiple certificates, when we run this manually with a curl command it works

@wfurt
Copy link
Member

wfurt commented Mar 17, 2022

I think this is dup of #26323. There is only one certificate with private key but there are intermediate CA certificates, right @jaden-patel?

@jaden-patel
Copy link
Author

Hello @wfurt, yes it is! However we have a requirement to use .net core 3.1 - any way round this issue using .net core 3.1?

@rzikm
Copy link
Member

rzikm commented Mar 21, 2022

The workaround would be adding the intermediate certificates to the windows cert store, this comment (#55368 (comment)) shows how it can be done programmatically. This needs to happen only once on the machine (or until the certificates change).

It can also be done by double-clicking the .pfx file in Windows Explorer. Note that you need to select the "Intermediate Certificate Authorities" store in the dialog.

@wfurt
Copy link
Member

wfurt commented Mar 21, 2022

I don't know anything else for 3.1 besides what @rzikm recommended @jaden-patel.
For 7.0 I would like to add some API so the chain can be set explicitly. The ClientCertificates was never meant for the intermediate certificates. It is just collection of leaf certificates (with private keys) the client can choose from.

@karelz
Copy link
Member

karelz commented Mar 22, 2022

Duplicate of #26323

@karelz karelz marked this as a duplicate of #26323 Mar 22, 2022
@karelz karelz closed this as completed Mar 22, 2022
@karelz karelz added this to the 7.0.0 milestone Mar 22, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Apr 21, 2022
@jeffhandley jeffhandley removed the untriaged New issue has not been triaged by the area owner label May 6, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants