Search This Blog

OpenSSL Key Recovery Attack on DH small subgroups (CVE-2016-0701)

Usual Mandatory Disclaimer: IANAC (I am not a cryptographer) so I might likely end up writing a bunch of mistakes in this blog post...

tl;dr The OpenSSL 1.0.2 releases suffer from a Key Recovery Attack on DH small subgroups. This issue got assigned CVE-2016-0701 with a severity of High and OpenSSL 1.0.2 users should upgrade to 1.0.2f. If an application is using DH configured with parameters based on primes that are not "safe" or not Lim-Lee (as the one in RFC 5114) and either Static DH ciphersuites are used or DHE ciphersuites with the default OpenSSL configuration (in particular SSL_OP_SINGLE_DH_USE is not set) then is vulnerable to this attack. It is believed that many popular applications (e.g. Apache mod_ssl) do set the SSL_OP_SINGLE_DH_USE option and would therefore not be at risk (for DHE ciphersuites), they still might be for Static DH ciphersuites.

Introduction

So if you are still here it means you wanna know more. And here is the thing. In my last blog post I was literally wondering: What the heck is RFC 5114? In a nutshell RFC-5114 was described here (emphasis mine) as

...a semi-mysterious RFC 5114 – Additional
Diffie-Hellman Groups document. It introduces new MODP groups not with
higher sizes, but just with different primes.

and

the odd thing is that when I talked to people in the IPsec community, no one really knew why this document was started. Nothing triggered this document, no one really wanted these, but no one really objected to it either, so the document (originating from Defense contractor BBN) made it to RFC status.

The thing that caught my attention back then and I was trying to get an answer were:

Why the generators g (defined in this spec) are so big ? Often the generator is 2. Now I am aware that the generator g=2 leaks one bit but AFAIK this is still considered safe.

I posted those questions in my blog post and other places in the web (including randombit) hoping for an answer. Well it turned out I got a pretty decent one (thanks again Paul Wouters BTW!!). This answer was pointing to an old IETF mailing thread that contained a really interesting part (emphasis mine) :

Longer answer: FIPS 186-3 was written about generating values for DSA,
not DH. Now, for DSA, there is a known weakness if the exponents you
use are biased; these algorithms used in FIPS 186-3 were designed to
make sure that the exponents are unbiased (or close enough not to
matter). DH doesn't have similar issues, and so these steps aren't
required (although they wouldn't hurt either).

[...]

For these new groups, (p-1)/q is quite large, and in all three cases,
has a number of small factors (now, NIST could have defined groups where
(p-1)/q has 2 as the only small factor; they declined to do so). For example, for group 23 (which is the worse of the three), (p-1)/q == 2 * 3 * 3 * 5 * 43 * 73 * 157 * 387493 * 605921 * 5213881177 * 3528910760717 * 83501807020473429349 * C489 (where C489 is a 489 digit composite number with no small factors). The attacker could use this (again, if
you don't validate the peer value) to effective cut your exponent size
by about 137 bits with using only O(2**42) time); if you used 224 bit exponents, then the attacker would cut the work used to find the rest of the exponent to about O(2**44) time. Obviously, this is not
acceptable.

Reading this answer and knowing that OpenSSL does use RFC 5114 my immediate though was, I gonna try this to OpenSSL. And you know what? I actually did...

The Attack

The actual attack I performed is literally a verbatim application of a classical paper published in 1997: A Key Recovery Attack on Discrete Log-based Schemes Using a Prime Order Subgroup. The attack is as beautiful as simple. Here I will try to sketch it. For details please refer to the original paper. For the record, this attack is not the type where the other party merely forces the shared secret value to be "weak" (i.e. from a small set of possible values) without attempting to compromise the private key (like the one I previously reported for Mozilla NSS).

I would refer to the classic Diffie Hellman nomenclature

p as the prime number

g the generator with order

q the size of the prime-order subgroup generate by g

y public key

x private key

In order for the attack to succeed it needs to have two prerequisites:

requires that the attacker complete multiple handshakes in which the peer (OpenSSL in this case) uses the same private DH exponent. And this is true for the default configuration of OpenSSL for the DHE ciphersuites (namely SSL_OP_SINGLE_DH_USE is not set) and is always true for Static DH ciphersuites. As mentioned above, it is believed that many popular applications (e.g. Apache mod_ssl) do
set the SSL_OP_SINGLE_DH_USE option and would therefore not be at risk
(for DHE ciphersuites), they still might be for Static DH ciphersuites.

requires DH configured with parameters based on primes that are not "safe" or not Lim-Lee. This is well the case of RFC 5114 where p-1 = 2 *3 * 3 * 5 * 43 * 73 * 157 * 387493 * 605921 * 5213881177 * 3528910760717 * 83501807020473429349 * C489 (where C489 is a 489 digit composite number with no small factors). But the problem it is not limited to RFC 5114 (while this is a perfect example). Note in order to generate the RFC 5114 parameter file in X9.42 style using openssl just do:

As mentioned above the thing that the peers need to take in consideration is the fact that for this particular group (p-1)/2 has many small factors hence a validation of the peer public value (we will see how this can be done later) is required. Well it turns out that OpenSSL did not do this extra step probably for a couple of reason (historically OpenSSL only ever generated DH parameters based on "safe" primes, while this changed lately and the validation has a certain cost in terms of performance). So here how the attack looks like:

Assuming the server (OpenSSL in this case) chooses his DH private key to be xb

Then transmits yb = g ^ xb (mod p)

Then the attacker

choose B where ord(B) is small (and is equal to one of the small factors of p-1, (e.g. for RFC 5114 ord(B) = 2 or or 3 or 5 or 43 or 73 or 157 or 387493... )

choose xa

calculate ya = g^xa (mod p) * B

with the received yb the attacker by exhaustive search (for TLS these means try to handshake many sessions) tries yb^xa * B^j (mod p). It does it j-times where 0< j <ord (B).

At this point the attacker found j = xb (mod ord(B))

Once this is done the attacker may repeat the same steps above with a different computational feasible B' where ord(B')) is small.

And for the yet remaining bits Shanks's method Pollard's lambda methods can be used.

Again, for details please refer to the original paper. But to be more ground on Earth this would means that for RFC 5114 group 23 (the one shown in this blog post) that has 2048-bit MODP Group with 256-bit Prime Order Subgroup the attacker would cut the work used to find the rest of the exponent to about O(2**44) time. Now this is for sure not feasible work for many common PCs (isn't it :S?) but it is for sure not a safe.

The fix

As mentioned before in order for work safely with DH parameters as the one in RFC 5114 two options are possible:

Validate the peer value. This can be easily done just checking that ya^q (mod p) = 1. The fix done by OpenSSL for this issue adds an additional check where a "q" parameter is available (as is the case in X9.42 based parameters). This detects the only known attack, and is the only possible defense for static DH ciphersuites. This could have some performance impact.

Fork Status

BoringSSL got rid of SSL_OP_SINGLE_DH_USE
support some months ago. I am not sure about the Static DH ciphersuites situation.

I gave an heads up to the LibreSSL folks as well. I know they also assigned a CVE and deprecated SSL_OP_SINGLE_DH_USE this week. Again, I am not sure about the Static DH ciphersuites situation.

Disclosure timeline

12-01-2016 -Reported to OpenSSL security team.

13-01-2016 - Vendor confirmation, CVE-2016-0701 assigned.

15-01-2016 -Disclosure scheduled.

25-01-2016 - Release publicly announced.

28-01-2016 - Public release and disclosure.

Acknowledgement

I would like to thank the OpenSSL team for the constant and quick support. Same as the LibreSSL team.

are you sure the fix is ya^q (mod p) = 1? This holds for any ya according to Fermat little theorem. If p is not a safe prime, it means order of group (since p is prime, = p-1 = q) has small prime factors, say q = q0 q1 ... qn. Assuming one of them is big (call it qi), then you ought to check that ya^qi = 1 mod p. That would ensure that your group order is big, and an attacker cannot trick u into using a small subgroup attack.Can you point out the file where the supposedly fix is done?

The answer to why RFC 5114 exists is simple. The NIST standard for Diffie-Hellman key exchanges is NIST Special Publication 800-56A. If you read page 28 of the 2007 version of this standard you will find that NIST explicitly requires that primes for use in Finite Field Diffie-Hellman have the same form as the primes they require for DSA.

As far as I know NIST has always accepted primes (p) of a forms such that (p-1)/2 is prime - thus not conforming to their standard. The writers of RFC 5114 were just supplying some primes that actually met NIST's own standard.

Regarding the question of why 2 wasn't used as a generator I think the answer is also simple. Given a prime modulus p such that there's another prime q that divides (p-1)/2 you want the generator to be an element of order q. The probability that the integer "2" happens to be of order q is very, very, small. The NIST standard for DSA has several complex processes to generate the generator given the primes p and q.

AFAIK ya^q (mod p) = 1 is the right validation. This is the OpenSSL commit https://git.openssl.org/?p=openssl.git;a=commit;h=b128abc3437600c3143cb2145185ab87ba3156a2 (For the record I update the blog post to include it now )

Great work! But I don't quite understand the step "calculate yb = g*xa (mod p) * B"... In my understanding, it should be ya = g^xa (mod p) * B , and ya is sent to the server. yb in yb^xa * B^j (mod p) is the one received from server, which is yb = g ^ xb (mod p). Please correct me if I am wrong.

Great blog! i actually love however it's straightforward on my eyes and therefore the info area unit well written. I'm curious however I'd be notified whenever a brand new post has been created. I actually have signed to your rss feed that extremely ought to do the trick! Have a pleasant day!

tl;dr I found a severe issue in the Slack's SAML implementation that allowed me to bypass the authentication. This has now been solved by Slack.
Introduction
IMHO the rule #1 of any bug hunter (note I do not consider myself one of them since I do this really sporadically) is to have a good RSS feed list. In the course of the last years I built a pretty decent one and I try to follow other security experts trying to "steal" some useful tricks. There are many experts in different fields of the security panorama and too many to quote them here (maybe another post). But one of the leading expert (that I follow) on SAML is by far Ioannis Kakavas. Indeed he was able in the last years to find serious vulnerability in the SAML implementation of Microsoft and Github. Usually I am more an "OAuth guy" but since both, SAML and OAuth, are nothing else that grandchildren of Kerberos learning SAML has been in my todo list for long time. The Github incident gave me the final…

then after that the resource owner has authorized the client the authorization server redirects the resource owner back to the client with an authorization code:
Then the OAuth dance continues....
Facebook/Dropbox i…