Search code examples
c#.net-corecertificatex509certificate2ssl-handshake

.NET 7.0/8.0 MacOS 12.7.2 refuses to include CA certificate in TLS1.2 handshake


Communicating with mutual certificate authentication endpoint always results in handshake failure in MacOS, the exact same code works fine in Windows. Browser in MacOS works fine.

I've tried loading the X509Certificate class many ways, including reading directly from a file that includes the CA cert and private key. Mac keychain has the CA/intermediate cert and Root cert in login and system keychains, they're trusted but when I look at the packets in Wireshark, the MacOS erroring packets includes only the entity certificate...not the CA also, where as Wireshark in Windows (and macOS Firefox) correctly shows two certificates, the entity and the CA.

Successful call in Windows with 2 certs and macOS Firefox: enter image description hereWireshark Success

Failed call in MacOS with 1 cert: enter image description here

Not sure if the difference in handshake messages is meaningful, the successful Windows handshake (and Mac browser) is Cert, Client Key Exchange, Cert Verify and Change Cipher Spec (followed by a packet with Encrypted Handshake Message only) whereas the failing MacOS packet has only Certificate & Client Key Exchang and subsequent packet has Certificate Verify, Change Cipher Spec and Encrypted Handshake Message.

MacOS Console shows the following on the handshake failure, not surprising given the CA cert is not included in the SSL call: enter image description here

X509Chain.Build returns valid=true but contains only one element in the ChainElements collection. I would have expected to see the CA and/or root. I need to use X509RevocationMode.NoCheck or I get "An incomplete certificate revocation check occurred.". Same results with X509RevocationFlag.EntireChain, X509RevocationFlag.EndCertificateOnly and X509RevocationFlag.ExcludeRoot.

Tried unsetting the trust on the intermediate cert but no difference. When I first added the root cert, it said "not trusted"...so I had to manually set it to trusted in Keychain. Not sure if this is significant.

How do I get a successful call in MacOS dotnet?


Solution

  • @bartonjs came to my rescue. Following his comment "c) maybe you put a trust on an intermediate certificate and that confused macOS into giving back only a partial chain", I resolved this by changing the entity cert in Keychain to be 'Use System Defaults' instead of 'Always Trust'. Setting it to always trust mucked things up with macOS. Thank you kindly!