I have two console applications to test a Mutual SSL connection with an API, one is .NET 6 the other is .NET 4.8.
Both run the following code:
X509Certificate2 certificate;
// The following Find Certificate code is from https://learn.microsoft.com/en-us/archive/msdn-magazine/2007/march/support-certificates-in-your-apps-with-the-net-framework-2-0
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
try
{
// create and open store for read-only access
store.Open(OpenFlags.ReadOnly);
// search store
X509Certificate2Collection col = store.Certificates.Find(
X509FindType.FindBySubjectKeyIdentifier, "my_subject_key_id", true);
// return first certificate found
certificate = col[0];
}
// always close the store
finally { store.Close(); }
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;
handler.ClientCertificates.Add(certificate);
var httpClient = new HttpClient(handler);
var content = new Dictionary<string, string>();
content.Add("grant_type", "client_credentials");
content.Add("client_id", "123");
content.Add("client_secret", "abc");
content.Add("scope", "MyScope");
var encodedContent = new FormUrlEncodedContent(content);
encodedContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
HttpResponseMessage tokenResponse = await httpClient.PostAsync("https://sample.com/api/v1/conf/oauth2/token",
encodedContent);
The .NET 6 application runs and the SSL/TLS connection succeeds with no problem, but the .NET 4.8 Framework console app, while it seemingly gets the certificate fine in code (including the private key), and the system.diagnostics tracing logs seem to show the certificate being sent (I see the byte data for it in those logs), the Wireshark logs show the certificate as missing.
EDIT: One thing that's different between the 4.8 and 6 calls is that the Private Key on the handler in .NET 6 has as KeyExchangeAlgorithm and SignatureAlgorithm of "RSA" while the .NET 4.8 Private Key has a KeyExchangeAlgorithm of "RSA-PKCS1-KeyEx" and SignatureAlgorithm of "http://www.w3.org/2000/09/xmldsig#rsa-sha1".
The SHA1 seems out of place since in Windows the Signature Algorithm for the cert says sha256RSA
Any ideas why this works in .NET 6 but not .NET 4.8? Any suggestions welcome. Thanks!
EDIT: Since this is apparently a relatively popular question, for posterity I have to say that I never figured this out. But since I needed to make the connection work with both frameworks, as a workaround, I opened up an internal API between the two and called the working .NET 6 API from the .NET 4.8 solution. I'm still interested if anyone else has figure this out, though.