Aspnetcore: SSL Certificate chain not sent when signed by one or more Intermediate CAs

Created on 6 Jun 2019  路  24Comments  路  Source: dotnet/aspnetcore

I am setting up SSL on my Kestrel Linux server using .NET Core 2.1.1.

The SSL certificate is signed by an intermediate CA.

The SSL certificate contains intermediate and root CA.

I load the pfx file as a X509Certificate2 object and use this for the server certificate.

It seems to be that the way I have set this up, the intermediate CA is not sent as part of the handshake and only the leaf is sent.

return WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseKestrel(options =>
            {
                options.Listen(IPAddress.Any,443, listenOptions =>
                {

                    listenOptions.UseHttps("ssl.pfx", "password123");

                });
            }
            )
        .Build();

So I execute this command and it shows only the leaf but not the intermediate:

openssl s_client -showcerts -connect myserver:443

I expect it to include the intermediate ca and leaf as one would expect like this for example:

openssl s_client -showcerts -connect google.com:443

Author Feedback area-servers

Most helpful comment

No no, it got moved to potentially the right place now :)

All 24 comments

This is the wrong place for support. This repo is only for announcements that have a broad audience (ie. everyone using the framework). You probably want to ask in another repo (eg. https://github.com/aspnet/AspNetCore), on Gitter, or on Stack Overflow 馃槂

Would be nice if GitHub only let the maintainers/org members open issues.

I don't think GitHub ever thought people would use issues like a blog, so they likely didn't consider this as a requirement 馃槢

Oops, sorry.
Please delete

No no, it got moved to potentially the right place now :)

I came across this same issue last week. I found that if the host operating system (Debian in this case) didn't have explicit trust in the intermediate cert itself, kestrel would not send the intermediate cert to the client. When I added the intermediate cert directly into the ca trust, it would send. Having the root certificate alone was not enough.

this is unusual behavior; i would guess that it's a bug.

We don't really control X509Certificate2's behavior here. It looks like it's only loading one of the certs which means Kestrel can only send one of the certs (the leaf, I presume). This bug is probably better filed in dotnet/corefx.

I run into the same issue today (windows 2016). I have 2 two certs, both of them are signed by the same root CA and Intermeidate CAs. the weird thing is the first certs sends, but the 2nd cert doesn't.

I tried to add the intermediate cert to trush as suggested by @scott-a-allard, but it still doesn't work
it may be bug.

We'll see if we can investigate a little further, but as I mentioned from my understanding this isn't something we're able to do with X509Certificate2 since I believe only a single certificate is loaded out of the PFX file. It may be possible to do something with direct access to the PFX file (since X509Certificate2Collection appears to be able to import a PFX), but we'd also need support from SslStream which I believe only supports returning a single certificate.

We'll see if we can investigate a little further, but as I mentioned from my understanding this isn't something we're _able_ to do with X509Certificate2 since I believe only a single certificate is loaded out of the PFX file. It may be possible to do something with direct access to the PFX file (since X509Certificate2Collection appears to be able to import a PFX), but we'd also need support from SslStream which I believe only supports returning a single certificate.

sorry, i may mislead you because of poor english. I don't mean to return 2 certs at the same Time.
My sitaution is that:

  1. I have an Azure Sevice Fabric ASP.NET Core stateless service, which use HTTPS.
new WebHostBuilder().UseKestrel(opt =>
  {
     opt.Listen(IPAddress.Any, 443, listenOptions =>
       {
       listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
         listenOptions.UseHttps(new HttpsConnectionAdapterOptions
            {
                ServerCertificate =  GetCertificateFromStore("mycert",StoreLocation.LocalMachine),
                 ClientCertificateMode = ClientCertificateMode.RequireCertificate
               });
                 listenOptions.NoDelay = true;
           });
     })
  1. If I use an self-signed cert on my local, it works fine.
  2. if i use a real cert from CA( let's name it Cert A ), it works fine.
  3. if i use another cert( let's name it Cert B ), which signed by the same root CA and Intermeidate CAs with Cert A, it does't send.

i use openssl to verify it, by running openssl s_client -connect mywebite:443

CONNECTED(00000003)

write:errno=0

no peer certificate available

No client certificate CA names sent

SSL handshake has read 0 bytes and written 324 bytes

Verification: OK

New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)

So you're saying that Cert B (the leaf cert) doesn't send? I'd expect that to work.

If Cert B is sent but the intermediate cert isn't sent, that's what I'm talking about requiring loading more than one cert. When an intermediate is in use, you have to send all the certs required to chain up to the root.

the weird thing is the first certs sends

That's what I was basing my understanding on. The fact that you said the first cert is sent.

@anurse my solution is an Azure service fabric asp.net core stateless service( my solution->azure service fabric -> asp.net core).

To make it simple, I created a simple asp.net core web site on my local with the same code. 1, self-signed cert, works fine. 2, cert A sends, 3. cert B send.

so it looks like a service frabric kestrel bug.

@anurse sorry, please ingore my previous comments, my problem solved.

Azure service fabric solution is running under "network service" account. "network service" account has access to self-signed cert(i must have granted it before), but no access to real cert. That is why it doesn't sent cert.

Asp.net core is by default running under your windows account(admin),that is why it sends all certs.

Ah, so it was a permissions issue all along? Glad to hear it's resolved. Does that resolve the entire issue or are you still having issues with intermediate certificates?

Still issues with intermediate certs here! lovelangy is referring to a user permissions issue in Microsoft OS environment whilst I am referring to Kestrel on Linux issue to do with how the certs are /are not being picked up during handshake request (same issue as scott-a-allard).

@ririlele So to be clear, you are loading a PFX file containing two or more certificates (the leaf, and the intermediate(s)/root CAs) into an X509Certificate2 object, passing it to Kestrel, and only one certificate (the leaf) is being transmitted? I'd like to be extremely clear about how this is working so that I understand things.

As far as I know, the X509Certificate2 class represents a single certificate, so even if your PFX contains additional certs, they are lost when you load them into an X509Certificate2, hence there's no way for Kestrel to actually send them.

Now, if you're using UseHttps("pfxfilename.pfx", "password"), then there may be something we can do, though it depends on support for sending multiple certificates in SslStream.

Perhaps the easiest thing to do here would be if you can provide a runnable sample that reproduces the issue?

Closing this as we haven't heard from you and generally close issues with no response after some time. Please feel free to comment if you're able to get the information we're looking for and we can reopen the issue to investigate further!

@anurse the issue here still persists: for Public Web PKI as well as private PKI best practice is to use certificate chains (pathlen >0; usually min of 1)... The API here either needs to read the entire chain contained in the PKCS#12 file and pass it down to the the TLS stack or alternatively I would expect the listenOptions.UseHttps to accept a X509Chain object vs a single leaf cert (it that's the restriction of X509Certificate2). Happy to put an example repo together if that'd help.

@sourishkrout We are having a similar issue, and while I tried to repro that, I noticed the following:
At least on windows (there seems to be a different implementation on *nix), Kestrel does send the intermediate certificate along with the actual server certificate, if that intermediate certificate is installed in the server's certificate store.

Seems, the underlying SslStream does amend the certificates sent to the clients if it finds the corresponding cert in the computers certificate store (not taking into account that the certs are actually available in the pfx).

Can you verify that this would also be the case for your? Maybe even on Linux (no idea where you are hosting)?

@sourishkrout I'd suggest opening a new issue if you are still seeing an issue here. Since this is closed it's easy for comments to get lost, I'd rather have a new issue if you're still hitting a problem :).

Most of the cert logic here is in corefx, since we just give the certificate to SslStream to send, so it's likely this issue would fit better in the https://github.com/dotnet/corefx repository.

@gingters started with macOS and then moved into Windows to "compare". Let me do a bit more probing and I will get back to you.

@anurse sounds good! Will lodge a new issue at the respective project(s).

@gingters I can confirm that on Windows the intermediate cert will be sent to the client as part of the handshake granted it's inserted into the system trust store. - That is not the case on macOS. Haven't tried Linux yet.

@gingters actually... it's the same on macOS. Realized I had to change the intermediate cert's properties in the system keychain to allow trust for TLS/SSL explicitly.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

BrennanConroy picture BrennanConroy  路  3Comments

farhadibehnam picture farhadibehnam  路  3Comments

aurokk picture aurokk  路  3Comments

FourLeafClover picture FourLeafClover  路  3Comments

markrendle picture markrendle  路  3Comments