Thanks for getting this conversation started, Michael!
We’re still working on getting Gerrit set up nicely for Chrome’s workflow, and eventually it should send e-mail when expected.
Gerrit bug 4390 has more details. Until then, you can “trick” Gerrit into sending e-mail by entering a message: hit “Reply” and type something into the “Say something nice…” box.
The trybots are currently reserved for project members.
Now, on to the meat of this issue!
Anyway, after working on this for a while, I developed some pretty strong ideas about how it should be achieved. Mostly, I want to remain as close to
RFC 7469-style pinning as possible, so:
- Require at least two pins (§4.3, §2.5). Require that the validated chain contains one match pin, and require that at least one pin be absent from the validated chain. This will encourage people to follow the best practice of having a backup key prepared ahead of time. Of course, it’s always possible to provide a dummy hash instead of a proper backup hash (as is possible with RFC 7469), but this at least raises the bar to the level that irresponsible behavior requires an explicit action.
- Pins should come with an expiration date (along the lines of §2.1.2). The date should be baked in to the Crashpad client the same way that the hashes themselves are. After expiration, pinning should be disabled and HTTPS connections should proceed normally. The expiration date should not be more than n days in the future relative to the start time of crashpad_handler. (§4.1, n = 60?)
- I feel that this is currently optional for our purposes, but pin replacement/refreshing: by implementing portions of RFC 7469 and not simply allowing for “preloaded” pins, the expiration date can be refreshed, pins can be changed, cleared, etc. If this is done, it’s probably sufficient to deal with everything in memory for the running crashpad_handler instance. I don’t think that there’s currently a need to save any of this to disk for Crashpad’s current purposes.
That’s the policy side of this. On the implementation side, after investigating how the various transport mechanisms handle this (or don’t), I’ve got this:
- We’ll need to design things to push a set of pins into the transport implementation, and then let it decide whether to allow the connection. Some transports (WinHTTP) make hashable SPKIs available, some (NSURLConnection) only provide easy access to SPKIs already hashed, and others (libcurl, judging from existing interfaces) may want to be provided with hashes and make their own assessment.
As for testing:
- As with all things TLS, testing (particularly offline) is difficult.
Suggested roadmap for this feature:
- First, land the support code in the transport implementations. This should ideally be tested, but see above. I can polish off the bits that I wrote and take this part.
- Then, work backwards to add a policy layer (requirements for pins, expiration, etc., also tested). You can take this part.
- Finally, plug it all in to crashpad_handler.
One final note: I didn’t read all of
https://chromium-review.googlesource.com/471917 exhaustively, but I saw naked std::array<uint8_t, 32> being used to ferry SHA-256 hashes around. I think that this is a crutch, and that we should have a proper SHA256Hash type. Can it use std::array<> internally? Sure! (uint8_t[32] is fine too.) I just think that it deserves a proper purpose-specific class of its own, and we should be substituting naked generic types. The class should be able to convert to and from hexadecimal strings and byte buffers, and should also provide for comparisons. This part will also be easy to test independently at the “unit” level.