[Mono-list] Mono SSL server fails to send intermediate to client
Edward Ned Harvey (mono)
edward.harvey.mono at clevertrove.com
Fri Apr 25 17:08:42 UTC 2014
> From: Sebastien Pouliot [mailto:sebastien.pouliot at gmail.com]
> >> I'm using SslStream. When I connect a mono client to a mono server, I can
> >> step through mono source on the client and I can see the server doesn't
> >> send the chain. The client therefore checks root CA's but no
> > That's already fixed in git.
> Awesome - I was just writing a bug report in bugzilla - so I'll stop that now -
I found that the fixed code wasn't working, so I put in the effort yesterday & today, to completely get the root cause of this issue, and patch it. (Pull request submitted.) Here's what it comes down to:
I reviewed the commit to ServerContext.cs on Apr 11, and I stepped through the code, and I found...
(a) After the commit, the server requires to have pre-populated intermediate cert into IntermediateCACertificates. This doesn't happen automatically, and it's not obvious how to do it, so I figured out how to do it manually. But *then* it still wasn't working. Because:
(b) X509Chain.Build would build the chain, without the leaf in it. And the for-loop in ServerContext.cs which does ServerSettings.Certificates.Add, actually assumes chain.Chain is the leaf and therefore never adds it to ServerSettings.Certificates. So even if you populated IntermediateCACertificates, the intermediate still failed to get into the server config.
(c) When I got that much figured out, I started wondering, how to automatically populate IntermediateCACertificates. I saw, in the X509Certificate2 ctor, it makes a call to Import(rawData,etc) which then does ImportPkcs12(rawData,etc) which then does PKCS12.Decode()... In here, the pfx is perfectly constructed, including the private key, leaf cert, and chain certs... But then it's all discarded and only the leaf cert with private key are returned. At this point, there is no further reference available, for the chain to ever be built, because the intermediate has been discarded. To solve this problem, it seemed best, to populate IntermediateCACertificates. See below:
So I wrote patches for all this.
My first commit, "chain should contain leaf" solves problem (b). So after this commit, if you have found a way to manually add your intermediate cert to IntermediateCACertificates, then the server works.
My second commit, "automatically build intermediates" will capture the chain at the time of pkcs12 import, automatically store the intermediates in IntermediatCACertificates, and correctly reconstruct the chain later. On my systems, these changes have all been tested, and should be good as long as I didn't break any unit tests. (Not sure if unit tests are being used, and if so, I'm not sure if/how I can run them myself.)
While testing, I noticed: The X509Store got loaded once. (Returned the property X509CertificateCollection Certificates). And then a call was made to X509Store.Import(cert). And later, another object referenced Certificates, which had not been updated to reflect the newly imported certificate. End result was: First time I launch my server, the intermediate chain certs get imported, but the server still fails. Simply relaunch the server, and it works the second time, because of course, after the application crashed and restarted, it obviously rebuilt Certificates fresh. So the application worked the second time. In order to fix this, I added calls to Clear() whenever somebody calls Import() or Remove(). So this is the third commit, "clear Certificates after Import or Remove." This way, you don't have to restart your application (or remember in userland to call Clear() every time you call Import or Remove) in order for the changes to take effect.
More information about the Mono-list