top | item 31089216

Psychic Signatures in Java

309 points| 19870213 | 3 years ago |neilmadden.blog

116 comments

order

tptacek|3 years ago

This is probably the cryptography bug of the year. It's easy to exploit and bypasses signature verification on anything using ECDSA in Java, including SAML and JWT (if you're using ECDSA in either).

The bug is simple: like a lot of number-theoretic asymmetric cryptography, the core of ECDSA is algebra on large numbers modulo some prime. Algebra in this setting works for the most part like the algebra you learned in 9th grade; in particular, zero times any algebraic expression is zero. An ECDSA signature is a pair of large numbers (r, s) (r is the x-coordinate of a randomly selected curve point based on the infamous ECDSA nonce; s is the signature proof that combines x, the hash of the message, and the secret key). The bug is that Java 15+ ECDSA accepts (0, 0).

For the same bug in a simpler setting, just consider finite field Diffie Hellman, where we agree on a generator G and a prime P, Alice's secret key is `a mod P` and her public key is `G^a mod P`; I do the same with B. Our shared secret is `A^b mod P` or `B^a mod P`. If Alice (or a MITM) sends 0 (or 0 mod P) in place of A, then they know what the result is regardless of anything else: it's zero. The same bug recurs in SRP (which is sort of a flavor of DH) and protocols like it (but much worse, because Alice is proving that she knows a key and has an incentive to send zero).

The math in ECDSA is more convoluted but not much more; the kernel of ECDSA signature verification is extracting the `r` embedded into `s` and comparing it to the presented `r`; if `r` and `s` are both zero, that comparison will always pass.

It is much easier to mess up asymmetric cryptography than it is to mess up most conventional symmetric cryptography, which is a reason to avoid asymmetric cryptography when you don't absolutely need it. This is a devastating bug that probably affects a lot of different stuff. Thoughts and prayers to the Java ecosystem!

loup-vaillant|3 years ago

Interestingly, EdDSA (generally known as Ed25519) does not need as many checks as ECDSA, and assuming the public key is valid, an all-zero signature will be rejected with the main checks. All you need to do is verify the following equation:

R = SB - Hash(R || A || M) A

Where R and S are the two halves of the signature, A is the public key, and M is the message (and B is the curve's base point). If the signature is zero, the equation reduces to Hash(R || A || M)A = 0, which is always false with a legitimate public key.

And indeed, TweetNaCl does not explicitly check that the signature is not zero. It doesn't need to.

However.

There are still ways to be clever and shoot ourselves in the foot. In particular, there's the temptation to convert the Edwards point to Montgomery, perform the scalar multiplication there, then convert back (doubles the code's speed compared to a naive ladder). Unfortunately, doing that introduces edge cases that weren't there before, that cause the point we get back to be invalid. So invalid in fact that adding it to another point gives us zero half the time or so, causing the verification to succeed even though it should have failed!

(Pro tip: don't bother with that conversion, variable time double scalarmult https://loup-vaillant.fr/tutorials/fast-scalarmult is even faster.)

A pretty subtle error, though with eerily similar consequences. It looked like a beginner-nuclear-boyscout error, but my only negligence there was messing with maths I only partially understood. (A pretty big no-no, but I have learned my lesson since.)

Now if someone could contact the Whycheproof team and get them to fix their front page so people know they have EdDSA test vectors, that would be great. https://github.com/google/wycheproof/pull/79 If I had known about those, the whole debacle could have been avoided. Heck, I bet my hat their ECDSA test vectors could have avoided the present Java vulnerability. They need to be advertised better.

DyslexicAtheist|3 years ago

> Thoughts and prayers to the Java ecosystem!

some very popular PKI systems (many CA's) are powered by Java and BouncyCastle ...

na85|3 years ago

>infamous ECDSA nonce

Why "infamous"?

Zababa|3 years ago

Thank you for that, that was a great explanation.

tialaramex|3 years ago

This is the sort of dumb mistake that ought to get caught by unit testing. A junior, assigned the task of testing this feature, ought to see that in the cryptographic signature design these values are checked as not zero, try setting them to zero, and... watch it burn to the ground.

Except that, of course, people don't actually do unit testing, they're too busy.

Somebody is probably going to mention fuzz testing. But, if you're "too busy" to even write the unit tests for the software you're about to replace, you aren't going to fuzz test it are you?

hsbauauvhabzb|3 years ago

The issue is the assumption juniors should be writing the unit tests, sounds like you might be part of the problem.

tptacek|3 years ago

The point of fuzz testing is not having to think of test cases in the first place.

ramblerman|3 years ago

Imaging being so senior you no longer need to write unit tests yourself, but just delegate them.

Sounds exactly like the kind of disconnected environment that would lead to such bugs.

ptx|3 years ago

Apparently you have to get a new CPU to fix this Java vulnerability, or alternatively a new PSU.

(That is to say: a Critical Patch Update or a Patch Set Update. Did they really have to overload these TLAs?)

RandomBK|3 years ago

Does anyone know why this was only given a CVSS score of 7.5? Based on the description this sounds way worse, but Oracle only gave it a CVSS Confidentiality Score of "None", which doesn't sound right. Is there some mitigating factor that hasn't been discussed?

In terms of OpenJDK 17 (latest LTS), the issue is patched in 17.0.3, which was release ~12h ago. Note that official OpenJDK docker images are still on 17.0.2 as of time of writing.

tptacek|3 years ago

CVSS is a completely meaningless Ouija board that says whatever the person authoring the score wants it to say.

vlowrian|3 years ago

What puzzles me most is that two days after the announcement of the vulnerability and the release of the patched Oracle JDK, there is still no patched version of OpenJDK for most distributions.

We're running some production services on OpenJDK and CentOS and until now there are only two options to be safe: shutdown the services or change the crypto provider to BouncyCastle or something else.

The official OpenJDK project lists the planned release date of 17.0.3 as April 19th, still the latest available GA release is 17.0.2 (https://wiki.openjdk.java.net/display/JDKUpdates/JDK+17u).

Adoptium have a large banner on their website and until now there is not a single patched release of OpenJDK available from them (https://github.com/adoptium/adoptium/issues/140).

There are no patched packages for CentOS, Debian or openSUSE.

The only available version of OpenJDK 17.0.3 I've seen until now seems to be the Archlinux package (https://archlinux.org/packages/extra/x86_64/jdk17-openjdk/). They obviously have their own build.

How can it be that this is not more of an issue? I honestly don't get how the release process of something as widely used as OpenJDK can take more than 2 days to provide binary packages for something already fixed in the code.

This shouldn't be much more effort than letting the CI do its job.

Edit: Typo.

gunnarmorling|3 years ago

For folks on RHEL, the java-17-openjdk package for RHEL 8 has been updated: https://access.redhat.com/errata/RHSA-2022:1445.

> The official OpenJDK project lists the planned release date of 17.0.3 as April 19th, still the latest available GA release is 17.0.2

> (https://wiki.openjdk.java.net/display/JDKUpdates/JDK+17u).

I don't think there 17.0.3 ever will be available from openjdk.java.net; there's no LTS for upstream builds, and since Java 18 is out already, no further builds of 17 should be expected there. IMO, this warrants some clarification on that site though.

Razhan|3 years ago

Amazon had releases of Corretto available on April 19th, Corretto 17 was released before 10am PDT, less than one hour after the announcement

LaputanMachine|3 years ago

>Just a basic cryptographic risk management principle that cryptography people get mad at me for saying (because it’s true) is: don’t use asymmetric cryptography unless you absolutely need it.

Is there any truth to this? Doesn't basically all Internet traffic rely on the security of (correctly implemented) asymmetric cryptography?

fabian2k|3 years ago

I've seen this argument often on the topic of JWTs, which are also mentioned in the tweets here. In many situations there are simpler methods than JWTs that don't require any cryptography, e.g. simply storing session ids server-side. With these simple methods there isn't anything cryptographic that could break or be misused.

The TLS encryption is of course assumed here, but that is nothing most developers ever really touch in a way that could break it. And arguably this part falls under the "you absolutely need it" exception.

nicoburns|3 years ago

> Is there any truth to this?

Yes, symmetric cryptography is a lot more straightforward and should be preferred where it is easy to use a shared secret.

> Doesn't basically all Internet traffic rely on the security of (correctly implemented) asymmetric cryptography?

It does. This would come under the "unless you absolutely need it" exception.

lazide|3 years ago

Initial connection negotiation and key exchange does, anything after that no. It will use some kind of symmetric algo (generally AES).

It's a bad idea (and no one should be doing it) to continue using asymmetric crypto algorithms after that. If someone can get away with a pre-shared (symmetric) key, sometimes/usually even better, depending on the risk profiles.

smegsicle|3 years ago

if people were getting mad at him, he must have been pretty obnoxious about it because i don't think there's much controversy- Asymmetric encryption is pretty much just used for things like sharing the Symmetric key that will be used for the rest of the session

of course it would be more secure to have private physical key exchange, but that's not a practical option, so we rely on RSA or whatever

Sirened|3 years ago

It's generally good to use symmetric cryptography wherever possible because it usually (!) is faster and simpler. More complex crypto systems provide interesting properties but if you can pull off whatever you're doing without it, why bother. The author tries to make a security claim for this but IMO that's not even the real issue

formerly_proven|3 years ago

I wouldn't be particularly worried of someone decrypting a file encrypted in the 80s using Triple DES anytime soon. I don't think I'll live to see AES being broken.

I wouldn't bet on the TLS session you're using to have that kind of half life.

dynamite-ready|3 years ago

Wonder if someone can add a little more info to the title of this story. It's would probably draw more clicks if the title wasn't so cryptic. This is essentially a Java dev infosec post.

pas|3 years ago

Just wait a few days and it'll be on the news like the log4j2 vulnerability :) (Though it might not, because in practice BouncyCastle is used in a most big/old Java software - as far as I know.)

danmur|3 years ago

It's crazy that the check for this was right there in the original code and was obviously missed when porting to Java. Great example of why unit tests are part of the code (and were missing in both in this case).

stolsvik|3 years ago

The title of the blogpost is now updated to "CVE-2022-21449: Psychic Signatures in Java" - maybe this HN post could too?

vemv|3 years ago

Agreed (@dang)

ccbccccbbcccbb|3 years ago

Q: Which type of cryptography is implied to be unsafe in the following sentence?:

"Immediately ditch RSA in favor of EC, for it is too hard to implement safely!"

tedunangst|3 years ago

What's java's RSA history look like?

lobstey|3 years ago

I doubt how many companies are actually using java15+. Many still sticks to 8 or 11

pluc|3 years ago

Not a good few months for Java

lobstey|3 years ago

Not that a lot of companies are using the Java 15+. People generally stick to 8 or 11.

needusername|3 years ago

I believe Oracle 11 is affected.

m00dy|3 years ago

[deleted]

0des|3 years ago

I want to live in this world, but no.

cesarb|3 years ago

And once again, you'd be saved if you stayed on an older release. This is the third time this has happened recently in the Java world: the Spring4Shell vulnerability only applies to Java 9 and later (that vulnerability depends on the existence of a method introduced by Java 9, since all older methods were properly blacklisted by Spring), and the Log4Shell vulnerability only applies to log4j 2.x (so if you stayed with log4j 1.x, and didn't explicitly configure it to use a vulnerable appender, you were safe). What's going on with Java?

KronisLV|3 years ago

> ...the Log4Shell vulnerability only applies to log4j 2.x (so if you stayed with log4j 1.x, and didn't explicitly configure it to use a vulnerable appender, you were safe)

Seems like someone likes to live dangerously: using libraries that haven't been updated since 2012 is a pretty risky move, especially given that if an RCE is discovered now, you'll find yourself without too many options to address it, short of migrating over to the new release (which will be worse than having to patch a single dependency in a backwards compatible manner): https://logging.apache.org/log4j/1.2/changes-report.html

Admittedly, i wrote a blog post called "Never update anything" a while back, even if in a slightly absurdist manner: https://blog.kronis.dev/articles/never-update-anything and personally think that frequent updates are a pain to deal with, but personally i'd only advocate for using stable/infrequently updated pieces of software if they're still supported in one way or another.

You do bring up a nice point about the recent influx of vulnerabilities and problems in the Java ecosystem, which i believe is created by the fact that they're moving ahead at a faster speed and are attempting to introduce new language features to stay relevant and make the language more inviting for more developers.

That said, with how many GitHub outages there have been in the past year and how many other pieces of software/services have broken in a variety of ways, i feel like chasing after a more rapid pace of changes and breaking things in the process is an industry wide problem.

ragnese|3 years ago

Was Spring4Shell Java's fault, or Spring's fault? Log4Shell was obviously (mostly) log4j's fault.

This one, I gather, is actually Java's fault.

It sounds like three unrelated security bugs from totally different teams of developers.

taeric|3 years ago

You make this sound like it is unique to java. I remember heartbleed had similar, in that the lts I was on did not have the vulnerable library.

At some level, as long as releases add functionality, the basic rules of systemantics will guarantee unintended interactions.

jatone|3 years ago

gasp new code can introduce bugs... whatever will one do?!