Brief Analysis of the OpenSSL sigalg DoS (CVE-2015-0291) — aka Client Nullo
Background
Without getting too wonkish, TLS 1.2 introduces a signature algorithms extension clients can use to tell servers which hash/signature algorithms they can use when verifying server messages (e.g. server certificates, server key exchange, etc.).
This is done (mod details) by adding a sequence of hash/signature algorithm pairs in descending preference order to the client hello message of the handshake protocol.
When server-side OpenSSL receives a client hello with a signature algorithms extension, it processes the client's hash/signature algorithm list and generates a "shared" list (intersection of client's list and server's valid/allowed list).
So far, so good.
Issue
Clients may choose to update their preference-ordered hash/signature pairs by initiating a renegotiation (used to establish new cryptographic parameters over an existing encrypted channel).
This is where OpenSSL got sloppy. Though OpenSSL was discarding the previous shared signature algorithms structure before processing a new list received during renegotiation, version 1.0.2 failed to reset the shared list's size to zero.
To illustrate why this is a problem, assume 15 hash/signature pairs make it into the shared list during the initial handshake process. Later, during a renegotiation, none of the hash/signature algorithm pairs sent by the client are allowed/valid so the shared list is empty. More precisely, the shared_sigalgs pointer in the
When we arrive to the code below (present in OpenSSL 1.0.2), c->shared_sigalgslen
==15 and we get a
From t1_lib.c: 3711 for (i = 0, sigptr = c->shared_sigalgs; 3712 i < c->shared_sigalgslen; i++, sigptr++) { 3713 idx = tls12_get_pkey_idx(sigptr->rsign); 3714 if (idx > 0 && c->pkeys[idx].digest == NULL) { 3715 md = tls12_get_hash(sigptr->rhash); 3716 c->pkeys[idx].digest = md; 3717 c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN; 3718 if (idx == SSL_PKEY_RSA_SIGN) { 3719 c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = 3720 CERT_PKEY_EXPLICIT_SIGN; 3721 c->pkeys[SSL_PKEY_RSA_ENC].digest = md; 3722 } 3723 } 3724 3725 }
Solution
Systems using OpenSSL 1.0.2 should upgrade to version 1.0.2a. Those who wish to test their servers for vulnerability can use my clientnullo.c checker.