SecureTransport/DarwinSSL: Implement public key pinning #1400
This has been a long time coming, refer to these links for history:
I have tested this with 2048 and 4096 bit RSA keys, and a ecDSA Secp256r1 key with these commands respectively:
Strangely Apple's API returns full DER encoding for the ecDSA key, but missing the header part for RSA keys. So in theory this might work for all ecDSA keys (anyone know another site to test this with other curves?), but no other RSA keys.
I have no idea if the way I hard-coded the headers is decent, curl-like, or even valid C, but it works, looking forward to comments here.
I also stumbled upon another public key pinning implementation in Objective-C and it seems to do a similar thing:
Either way, working for a subset of common keys seems better than not working at all which is the current situation. This should simply fail with a pinning error when faced with other keys. (which is fail-closed, the correct way)
Lastly I have only tested this on an OSX El Capitan box I had access to, testing on other versions and/or iOS would be appreciated. Thanks to everyone that already helped!
So, a quick test reveals that this also works on Sierra, which is a good start!
A quick dive into the docs suggests that this won't work on iOS, and won't work on macOS prior to 10.7 (
On a personal level, I don't like the
Otherwise, I've left a few comments inline in the diff.
I pushed up fixes for the comments, as a seperate commit so the comments would stay around, I'm guessing you'll want me to squish these before you merge them.
I also added support for more versions, unfortunately the new code won't link on my 10.11 box, it's only supported on 10.12+, so I can't test it at runtime. But per the docs macOS 10.7+ and iOS 10+ should be supported. 10.7 - 10.11 by one bit of code, and the rest by a different set.
Lastly, lukasa said earlier in IRC:
Which I think would be a much better solution, but unfortunately I think SecCertificateCopyValues is only macOS and not supported on iOS at all if I read this right:
Whoever knew my superpower was going to be "has access to a 10.12 macOS box"? So the build fails on Sierra:
This is because curl, by default, sets
Now, the reason you're seeing this problem is because the
You have further
You have to do:
Next up, the version check for v2 is wrong: the version code for v10.7 is
(You're right not to use the symbolic names of these constants btw, I'm just showing them for reference.)
Once that stuff gets fixed up and curl is told to compile against the 10.12 SDK, the compile appears to pass and a quick test demonstrates that both branches of code function correctly.
Thanks much for reviewing that again, hopefully one final patch.
So I managed to get access to a macOS Sierra box, and my fears were true. For RSA keys the new macOS/iOS code returns the same as the macOS 10.7+ code for RSA keys, but for ecDSA keys it returns them missing the header, while the 10.7+ code returns the full DER encoding. SecureTransport is such a mess of a library...
ANYWAY I tested all 4 supported key types with both sets of code, on a el capitan box, and a sierra box (with CFLAGS=-mmacosx-version-min=10.12), and these commands:
The last command can't use --insecure because that site requires SNI, and SecureTransport can't send SNI when certificate validation is disabled, did I mention how great SecureTransport is? :)
I feel a bit more comfortable with only supporting those 4 key types now, turns out letsencrypt only supports those 2 curves for ECC keys:
And only supports RSA keys from 2048 to 4096 (we wouldn't support anything in the middle, but whatever..).
bagder left a comment
I just found some very minor nits. Apart from those I'm fine with merging. However I think we should wait and merge this after 7.54.0 (due to ship in ~36 hours) to take the safer route.