Reconstruct Instead of Validating
What I want to focus on is (2), because it’s a lesson we learned the hard way in cryptography and didn’t transfer effectively to the rest of security engineering.
One of my favorite cryptographic attacks is the Bleichenbacher‘06 signature forgery. I wrote up how it works when I found it in python-rsa, so again go read that, but here’s a tl;dr. When you verify an RSA PKCS#1 v1.5 signature, you get a ASN.1 DER structure wrapping the message hash that you need to check. If you don’t parse it strictly, for example by allowing extra fields or trailing bytes, an attacker can fake the signature. This was exploited countless times.
The lesson we learned was that instead of parsing the ASN.1 DER to extract the message hash, we should reconstruct the ASN.1 DER we’d expect to see, and then simply compare it byte-by-byte.
The same technique would have saved Vault.