<p>For one of our projects we require only one endpoint of a service to have client certificate validation. The code will be running on Kubernetes and I've passed the client certificate through to the pod in the form of a header. This seems to be received by the code without any problems.</p>
<p>Now, the client certificate needs to be in a specific chain of certificates (they're signed by the government and not trusted by default). My approach was setting a <code>CustomTrustStore</code> with the entire chain of certificates. This does not seem to give me the result I was looking for.</p>
<p>So I've added the following:</p>
<pre><code>services.AddCertificateForwarding(options =&gt;
{
    options.CertificateHeader = &quot;ssl-client-cert&quot;;
    options.HeaderConverter = (headerValue) =&gt;
    {
        X509Certificate2? clientCertificate = null;

        if (!string.IsNullOrWhiteSpace(headerValue))
        {
            clientCertificate = X509Certificate2.CreateFromPem(WebUtility.UrlDecode(headerValue));
        }

        return clientCertificate!;
    };
});

services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(options =&gt;
{
    options.AllowedCertificateTypes = CertificateTypes.All;
    options.ChainTrustValidationMode = X509ChainTrustMode.CustomRootTrust;
    options.CustomTrustStore = getTrustStore(configData);
    options.Events = new CertificateAuthenticationEvents
    {
        ...
    };
});
</code></pre>
<p>The forwarding seems to work, the breakpoint shows that <code>clientCertificate</code> has a correct value.</p>
<p>The <code>getTrustStore</code> method returns an <code>X509Certificate2Collection</code> with all the certificates (simply loads a bunch of .CER files, puts them in an <code>X509Certificate2</code> object and adds it to the collection):</p>
<ul>
<li>Root certificate (Government)
<ul>
<li>Intermediate (Government)
<ul>
<li>Intermediate (Reseller1)</li>
<li>Intermediate (Reseller2)</li>
<li>Intermediate (Reseller3)</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>The client certificate needs to be purchased from one of the resellers and be part of that chain.</p>
<p>Local debugging makes the certificate check succeed (ends up in the <code>OnCertificateValidated</code> event), even if the <code>X509Certificate2Collection</code> is missing some certificates. Is it looking at my computer's store anyway? Deployed inside Kubernetes it seems to fail (ends up in the <code>OnChallenge</code> event), no matter what. There's no additional logging either.</p>
<p>I tried debugging but I got stuck and have no idea where to look. The documentation on these methods is pretty minimalistic. All controller methods have the correct <code>Authorization</code> attribute with the correct scheme provided.</p>

Roel
<p>For best results, the root certificate should be the only one in <code>CustomTrustStore</code>, the remainder should be in <code>ExtraStore</code>.  But, since no one understands that, we were nice and let the <code>CustomRootTrust</code> mode just copy everything that's not self-signed over into ExtraStore.  (A theoretical future mode of <code>CustomAnchors</code> would tell the chain engine to stop at the first certificate it finds in CustomTrustStore... not the first one that's self-signed).  Though I'm not sure how those X509ChainPolicy properties map to the ASP.NET versions, maybe you can't influence ExtraStore at that level.</p>
<blockquote>
<p>Local debugging makes the certificate check succeed (ends up in the OnCertificateValidated event), even if the X509Certificate2Collection is missing some certificates. Is it looking at my computer's store anyway?</p>
</blockquote>
<p>Yes. The chain engine will use your computer's cache of certificates (in the CurrentUser\CA, CurrentUser\My, LocalMachine\CA, and maybe LocalMachine\My stores... and possibly in the CU/LM Root and/or ThirdPartyRoot stores) in addition to the ones you specified programmatically for <em>building</em> the chain (it will also, unless disabled, attempt to download anything it can't find via a mechanism called &quot;AIA fetching&quot;).  Since you're in a custom trust mode it will only call the chain <em>trusted</em> (and thus, successful) if it contains the root certificate that you specified in your custom collection.</p>
