Bug 16974

Summary: SslStream.AuthenticateAsServer only send the EndCertificate, but not its chain….
Product: [Mono] Class Libraries Reporter: JustinC <justin>
Component: Mono.SecurityAssignee: Sebastien Pouliot <sebastien>
Status: RESOLVED FIXED    
Severity: normal CC: mono-bugs+mono, sebastien
Priority: ---    
Version: 3.2.x   
Target Milestone: Untriaged   
Hardware: Macintosh   
OS: Mac OS   
Tags: Is this bug a regression?: ---
Last known good build:
Attachments: patch file for ServerContext.cs
Added fixed ServerContext.cs for 3.2.6

Description JustinC 2013-12-27 11:26:41 UTC
Using SslStream.AuthenticateAsServer on a Windows Server with .NET 4.5 Framework send the entire chain of the ServerCertificate including it's intermediate certificates when they're available in the cert-store. Mono only sends the ServerCertificate. 

Browsers like Firefox (yeah, it's still not dead - couldn't believe it either!) won't read the authority information access extensions of the server certificate to "get" missing certificates to build it's own chain. So it's totally impossible to run a SslServer on mono which acts like one by providing the chain of trust … while same programm on a windows machine works as expected. 

How to reproduce:
1) Create a RootCA => IntermediateCA => Server-Cert structure
Demo Root CA
|_ Intermediate CA
   |_ The server certificate

2) Put everything in the cert store using certmgr
- certmgr -add -c Trust DemoRootCA.crt
- certmgr -add -c CA IntermediateCA.crt
- certmgr -add -c -p password My servercertificate.p12
- certmgr -importkey -c -p password My servercertificate.p12

3) Load the server certificate using the X509Store and check, if the chain is valid => X509Chain.Build(). 
Ignore RevocationChecks for testing purpose. It was a pain to get this working, cauz the openssl default config won't create a revocation list with a authority key identifier… 

4) Create a listing socket. Accept the first connection. Create an SslStream and calling AuthenticateAsServer.

5) Use openssl s_client -connect server-ip:port to get the - sort of frustrating result -, that mono only sends the server certificate without a chain to the intermediate ca certificate; while the same test scenario on windows with .NET 4.5 will send the entire chain...
Comment 1 JustinC 2013-12-28 09:39:05 UTC
Created attachment 5738 [details]
patch file for ServerContext.cs

I debugged the 3.2.3 sources by myself this morning and changed the part, where the certificates, which will be sent to the client during the initial handshake, are set up and added the missing certificates of the chain (excluding the root), if the chain builds at all. 

I recompiled the sources (needed to fix some parts around #if SECURITY_DEP in X509Chain, ChainElements, ChainElementEnumerator, ChainCollection and ChainPolicity to get this compiling) to test if the AuthenticateAsServer now would behaves at it is supposed to be … it does. I attached a patch for ServerContext.cs, maybe it will help u guys to fix the problem in the future. I didn’t included the fixes for compiling the whole thing cauz it was the first time i dag into the mono sources and had that sorf-of »help, i’m drowning«-feeling.
Comment 2 JustinC 2014-02-01 07:32:20 UTC
Created attachment 5956 [details]
Added fixed ServerContext.cs for 3.2.6

Now uses the Chain from Mono.Security.X509 (didn't saw that last year...), so no more fixing of #SECURITY_DEP required.
Comment 3 Sebastien Pouliot 2014-04-11 13:36:52 UTC
Yes, the whole chain (except the root) should be sent. I'll test (first) and commit your fix. Thanks.
Comment 4 Sebastien Pouliot 2014-04-11 15:56:57 UTC
Committed (with a few code formatting changes) in master 8df01216debd1c01e9582ee3d1bd598388fb6f56

Thanks!