An Empirical Study of Vulnerabilities in Cryptographic Libraries
arxiv.org
arxiv.org
I think "You Shouldn't Roll Your Own Crypto" is really three separate pieces of advice, each of which deserves justifying independently.
Roughly:
- You shouldn't try to invent your own cryptographic primitives.
- You shouldn't try to design your own equivalent to (say) SSL.
- You shouldn't try to implement something like SSL, or parse ASN.1, yourself.
I don't think many people are likely to fall foul of the first.
It seems to me the second is where the real devils lurk: dealing with padding and cipher modes and all that kind of stuff.
But it's not at all clear to me that the third has been historically justified.
I think if someone in the early 2000s had thought "I don't like the look of OpenSSL and I don't think C is a good choice of language. I'm going to write my own implementation of the parts I need in (say) Ada" they might well not have regretted that choice.
> "ASN.1 is a serialization format which enables C programmers to turn binary data into remote code execution vulnerabilities" -- https://twitter.com/bascule/status/1086778481864658945
Also https://twitter.com/TwitchiH/status/1382649508371308547, discussing it in context of the San Bernadino iPhone being broken with an ASN.1 vuln.
ASN.1 is however structured in a way that such a simple library looks like incomplete; it looks like that a correct way to parse BER/DER is an ASN.1 compiler, which tends to be bulky and annoying to integrate. As a result for a long time most ASN.1 implementations were either a "complete" ASN.1 compiler or a hand-crafted parser, with no middle ground of a library that is simple enough and prevents you from memory unsafety.
I think it's rather more than this. ASN.1 is deeply embedded in daily life: 3G/4G/LTE/5G, V2X, and many other protocols are specified in ASN.1. The inertia has as much to do with backwards compatibility as anything else. If you need to read call data records, you have to parse BER; if you want to deal with vehicle to vehicle communications you have to parse OER. 3G protocols are generally PER. Crypto is DER.
Are there alternatives that are better in some respects? Sure. Are they likely to supplant existing telecommunications standards? No. Should move away from ASN.1 for crypto purposes? Probably, though I'm not experienced enough to have a strong opinion. I'd be interested to see whether we could install a new standard in a suitable time frame, and indeed what form that would take. (In the two links you cited, I didn't see anything, but I'm actually really interested!)
I think ASN.1 is probably here to stay for a long time, and not merely as a resume polishing agent.
It's a little bit more than that: cryptographic container formats usually need to be stable on traversal/canonicalized so that things like hashes remain consistent.
JSON alone doesn't have a canonicalized format (there are various suggested canonical forms), and leaves details about key iteration, duplication, etc. ambiguous in ways that are potential sources of vulnerability (what happens if a particular protocol allows users to introduce untrusted attributes to a JSON object and doesn't check for name clashes?).
Edit: not to mention integer width/representation of large integers! That's a big one for cryptographic protocols.
Yeah, this, too: there's got to be a single way of representing the same message. (BER, in contrast to DER, has multiple means of writing the same message. BOOLEAN types, for example, indicate FALSE by 0x00, but TRUE is any non-zero value. I forget how DER resolves this. DER disallows the use of indefinite lengths, while BER admits both definite and indefinite lengths. Etc., etc.)
I'm sympathetic to the challenges people face with ASN.1, having worked with it rather extensively in my career. I don't recommend it to people who have serialization challenges usually because something like protobuf or flatbuffers seems like a more reasonable choice in this day and age...but at the same time ASN.1 has a history of mistakes and innovations for solving some challenging problems in representation and encoding that should inform decision-making moving forward.
Long before folks understood the security implications of a buffer overflow, we've been parsing ASN.1.
Most of the vulnerabilities stem from the basic problem of trusting length fields. Any binary encoding is going to have similar issues.
In this case you really don't need a DER calibre encoding either, you just need a standard in the first place. It’s just that the standard would historically likely use asn.1. But that doesn't have to be the case. Maybe the closest thing is the ECDSA point form specified in https://www.secg.org/sec1-v2.pdf#page16. The the curve domain parameters in sec2 are, you guessed it, specified in asn.1.
> - You shouldn't try to design your own equivalent to (say) SSL.
> - You shouldn't try to implement something like SSL, or parse ASN.1, yourself.
Why not? You should do all those things, how else can one get a deeper insight into how things work. It's just that you probably don't want to use that in production environment unless you really know what you're doing.
> [...] get a deeper insight into how things work. It's just that you probably don't want to use that in production [...]
That is the gist of it. If you are really into applied cryptography, then rolling your own crypto - and I can't stress this enough - for PURELY ACADEMIC purposes is fine. As long as you are honest with yourself, writing some applied crypto code is a good way to learn some of the horrible ways things can go wrong. Know deep in your heart that no matter how well you thought you did, the code you wrote is broken. Badly.
The "oh... oh shit..." realisation when looking back at the code will be enlightening.
Just please, for the love of all that is good, do not publish the code you wrote. Otherwise, thanks to the law of large numbers, someone, somewhere will grab your code, embed it in their production systems and the next thing you know, a toy library you wrote is now responsible for yet another IoT disaster.
Learn from other people's mistakes. You cannot possibly afford to make all those mistakes yourself.
What would you recommend for compiling and decoding/encoding ASN.1 using Java? I tried OSS NOKALVA's ASN.1 for Java but constraint checking is non-existent or very limited. I am forced to implement it myself as it does not exist from what I gathered. If you know one that does constraint checking, that would be amazing.
A quick search gave me this: https://github.com/yafred/asn1-tool/issues/13, so perhaps it does not seem so infeasible.
> I think if someone in the early 2000s had thought "I don't like the look of OpenSSL and I don't think C is a good choice of language. I'm going to write my own implementation of the parts I need in (say) Ada"
https://github.com/Componolit/libsparkcrypto might be of interest to some. It is written in Ada/SPARK.
A quick look at their documentation suggests the use of the -constraints option.[1] Constraints are such a basic part of the ASN.1 specifications I can't imagine any vendor not implementing it. I know for a fact that Objective Systems' compiler does.[2]
[1]: https://www.oss.com/asn1/products/documentation/asn1_java_8....
I know, Erlang's ASN.1 compiler does it too, automatically. It is pretty awesome.
---
Update: `-constraints` does work (`validConstraint = temp1 >= 10 && temp1 <= 20`)
I will try out more complex ones. :)
They say "Our case study of the LibreSSL and BoringSSL forks further demonstrates a linear correspondence between source code removal and vulnerability removal." Possibly a useful finding! But we still don't know what happens when you remove a ton of someone else's code, but then add a ton of your own unique code. To research that, they'd need competing projects that similarly care about vulnerability IDs (CVEs or other IDs), and have similar populations of potential bug reporters and/or similar opportunities for bug bounties.
This, to me at least, seems like a strange conclusion for this paper to reach. While there are evidently more vulnerabilities reported in NVD/CVE for cryptographic libraries, does this necessarily correlate with a larger number of vulnerabilities being present? Or could it be that cryptographic code is much more heavily scrutinised, and so it’s more likely that vulns will be found? I think the former is probably more reasonable, but I’m not sure you can come to either conclusion based on CVE data alone. Or am I missing something?
If you are interested you definitely should. Implement existing ciphers, learn, compare, create your own ciphers, test, crack, research and discuss. It's the perfect way to learn more and become better at it.
However, don't put it in production or with real data.
For my part, I've met people who have told me to not even try because I need to get a PhD before I even implement crypto. Not design crypto; implement crypto.
So while you are correct that it is the mainstream interpretation, that's not how it looks from the outside.
I've been deeply fuzzing cryptographic libraries for a few years and found about 130 bugs [1]. The vast majority of these did not receive a CVE. Now some of these are merely theoretical, others will only manifest under particular circumstances like specific calling sequences, others were caught in the development phase before landing in stable releases, but a number of them are outright vulnerabilities. The usefulness of CVE incidence is questionable when it is so strongly influenced by the vendor's propensity for reporting these.
[1] https://github.com/guidovranken/cryptofuzz#bugs-found-by-cry...
But those libraries show up recommended on forums and subreddits everywhere. And if you inherit such a system and try to do something like "add an HMAC", you'll be cursed at for "rolling your own crypto" when you should apparently be trusting the library.
Many Wireshark CVEs with numbers CVE-2018-16058 and lower (up until August 29, 2018) say that 2.2.0 was the lowest affected version. A bunch after that say that 2.4.0 was the lowest affected version. Is it plausible that everything discovered after August 2018 just randomly happened to be in code that was introduced on the 2.4 branch? I feel it's much more plausible that this is just an artifact of the Wireshark support policy. https://wiki.wireshark.org/Development/LifeCycle says the 2.2 version series hit End of Life on September 7, 2018. When Wireshark reported CVEs after then (such as CVE-2018-19622 up to CVE-2018-19627), I suspect they intentionally didn't list 2.2 affected versions because they weren't supported. So, I disagree that Wireshark advisories "have sufficiently accurate version reporting to calculate lifetime" and I feel that "Of the 509 CVEs in Wireshark, the average and median lifetimes are 1.29 and 1.4 years" may be hugely inaccurate.
Guess what, cryptographic library developers go the same schools as the rest of us. That's there's some sort of development that's somehow out of reach for "regular" devs is elitist and counterproductive.
It means there's a generation of graduates that don't do systems programming or anything where security is important.
Schools are dodging the important societal responsibility of teaching students how one designs and implements software that really, really needs to be correct.
Gotta trust something, we decided we mainly trust the OS download and the repository keys that came with it.
Anyway we seem to have been talking about different kinds of verification, like checking that what Joan Daemen and Vincent Rijmen wrote is really what your CPU is executing versus verifying that implementations of a trusted algorithm aren't broken. We're not in the conspiracy theory or incident response business, so unless someone comes with something that sounds like we should forward them to incident response, the former is not what we do.
But I think a good way to think about it is this: This shouldn't be on top of your list when you learn crypto. Before you even think about rolling your own crypto you should break other people's crypto. That'll help you to gain deeper insights in how the whole thing works.
(Disclaimer: I broke other people's crypto, I wrote papers about it. I still never tried to roll my own crypto.)
At peak, and in multiple independent courses, the teacher would step through a well-made AES key schedule visualization while none of us are (even planning on) doing the heavy math studies necessary to design a successor to or find vulnerabilities in something like AES. Most of us would be software engineers, sysadmins, or perhaps a handful of us might go into security fields like forensics or pentesting. The internals of AES are completely irrelevant. A curiosity maybe, but not something to be quizzed on. Then I went to do my master's and the teacher started about caesar ciphers...
All formal cryptography-for-non-cryptographers education I've ever had was completely useless (I was in tertiary education in the Netherlands between 2010 and 2018, in case anyone is wondering how dated this is).
The concept of authenticated encryption was mentioned in passing I think, though in one course I had to prompt the teacher to mention that as what you would want to be doing, but got far less attention or practice than doing things like a Caesar cipher or AES key schedule by hand.
Merely knowing that you have to look for the keyword authenticated encryption (when you want to do encryption for some reason) would already be enough in my opinion, from there you can find good answers. Or for secure connections, keyword searches should include something about key distribution/verification and, if you want to use something configurable like TLS, also configuration choices like enforcing allowed protocol versions. Which versions those are, that changes over time and there is little point memorizing it. You should just know that you should look into this when you need it.
Maybe it should be "never roll out your own crypto without independent review and verification as well as thorough testing" .
[1] https://loup-vaillant.fr/articles/rolling-your-own-crypto , discussed here:
https://news.ycombinator.com/item?id=13221923 and related
[0] https://monocypher.org/quality-assurance/audit
No high or critical issues were found. The issues that were found were addressed in a timely manner.
Edit: Also, not sure why the author chose to use Argon2i over Argon2id as the PBKDF for Monocypher, my perception was that the id variant should be used unless you have a reason not to. Would be interested to hear other opinions on this.
It is interesting to see the trend split between crypto and non-crypto vulnerability. There is only one trendline, LOC, but I would like to see CVE trends over time as well because that would indicate if we are making progress. This is useful framework for a longer-term study.