Skip to content

Developers using Kestrel can configure the list of CAs per-hostname #45456

Closed
@avparuch

Description

@avparuch

AB#1253385
Our Service has the need to configure the certificate trust lists sent in the "Certificate Request" of the TLS handshake on a per-hostname basis. Currently, we configure this via Http.Sys APIs.

We want to move to Kestrel, however SSLStream does not currently support this feature per my understanding.

This issue was raised in #31097. # 1 and # 3 mentioned at the bottom of that issue were addressed in .NET 5.0. Unfortunately, # 2 was not addressed in .NET 5.0.

Let's go through the specific details/scenarios:

As a pre-requisite, the following registry key is set in order for the server to send Trusted Issuer List during TLS handshake. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\SendTrustedIssuerList is set to 1. Details : https://docs.microsoft.com/en-us/windows-server/security/tls/what-s-new-in-tls-ssl-schannel-ssp-overview

Scenario 1: Mutual Auth with no defined CTL store.

We configure a binding as follows:

netsh http add sslcert hostnameport=pas.windows.net:443 certhash=EB3C3B94F10E948463929BCF4C7000C1E7BD0AC1 appid='{4dc3e181-e14b-4a21-b022-59fc669b0914}' certstorename=MY clientcertnegotiation=enable verifyclientcertrevocation=disable.

To emphasize, I have not picked any particular CTL store for this binding.

When a request comes in for the hostname pas.windows.net : during TLS handshake, in the "Certificate Request", the "Distinguished Names" is populated based on the trusted root of the server. (by default, since I did not pick a particular CTL store in the binding).

Please look at frame 19 of the attached wireshark capture. (Transport Layer Security -> TLS 1.2 record layer ->HandShake Protocol: Certificate Request -> DistinguishedNames).

The relevant snippet from frame 19 is below. The snippet shows that "Distinguished Names" is populated from trusted root on the server.

packet19

Below snippet shows the trusted root store on the machine: the "Distinguished Names" above are populated from the trusted root shown below.

CTL1

Scenario 2: Mutual Auth: a defined CTL store with a non-empty list

We configure a binding as follows:

netsh http add sslcert hostnameport=device.login.microsoftonline.com:443 certhash=963B55D3E94101B70F1654FBF90D6006BAFAD513 appid='{4dc3e181-e14b-4a21-b022-59fc669b0914}' certstorename=MY clientcertnegotiation=enable verifyclientcertrevocation=disable sslctlstorename=DeviceLoginCTLStore

To emphasize, I have picked a particular sslctlstore (DeviceLoginCTLStore) for this binding.

When a request comes in for the hostname device.login.microsoftonline.com : during TLS handshake, in the "Certificate Request", the "Distinguished Names" list is populated from the CTL store specified in the binding (which is (DeviceLoginCTLStore)).

Please look at frame 43 of the attached wireshark capture. (Transport Layer Security -> TLS 1.2 record layer ->HandShake Protocol: Certificate Request -> DistinguishedNames).

The relevant snippet from frame 43 is below. You will see only one entry in the Distinguished Names because that particular store (DeviceLoginCTLStore) has only one entry.

packet43

Below snippet shows the DeviceLoginCTLStore on the server: the "Distinguished Names" above are populated from the DeviceLoginCTLStore below.

CTL2

Scenario 3: Mutual Auth: a defined CTL store with a empty list

We configure a binding as follows:

netsh http add sslcert hostnameport=v2.aaddc.activedirectory.windowsazure.com:443 certhash=963B55D3E94101B70F1654FBF90D6006BAFAD513 appid='{4dc3e181-e14b-4a21-b022-59fc669b0914}' certstorename=MY clientcertnegotiation=enable verifyclientcertrevocation=disable sslctlstorename=EmptyCTLStore

To emphasize, I have picked a particular sslctlstore (EmptyCTLStore) for this binding. EmptyCTLStore happens to be empty.

When a request comes in for the hostname v2.aaddc.activedirectory.windowsazure.com : during TLS handshake, in the "Certificate Request", the "Distinguished Names" list is populated from the CTL store specified in the binding (which is (EmptyCTLStore)).

Please look at frame 55 of the attached wireshark capture. (Transport Layer Security -> TLS 1.2 record layer ->HandShake Protocol: Certificate Request -> DistinguishedNames).

The relevant snippet from frame 55 is below. You will see zero entries in the Distinguished Names because that particular store (EmptyCTLStore) has no entries.

image

Below snippet shows the EmptyCTLStore on the server:

EmptyCTL

serverhello.zip

Metadata

Metadata

Assignees

Labels

Bottom Up WorkNot part of a theme, epic, or user storyCost:MWork that requires one engineer up to 2 weeksPriority:1Work that is critical for the release, but we could probably ship withoutTeam:LibrariesUser StoryA single user-facing feature. Can be grouped under an epic.area-System.Net.Security

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions