Disassembler

Artificial intelligence is no match for natural stupidity.
08března2014

Kritické chyby v kryptografických knihovnách


Neštěstí nechodí nikdy samo. I tak by se dalo popsat dění okolo SSL a TLS knihoven v minulých čtrnácti dnech. Nejprve se linuxáci smáli jablíčkářům, že TLS/SSL implementace v jejich iOS obsahuje chybu umožňující podvržení certifikátu a man-in-the-middle útok. O necelých čtrnáct dní později si pak zúčastněné strany vinou podobného bugu v GnuTLS knihovně vyměnily role.

iOS a goto fail


21. února vydalo Apple bezpečnostní aktualizaci záplatující CVE-2014-1266 s poněkud děsivým komentářem, zmiňujícím že aktualizace zabraňuje tomu, aby potenciální útočník s privilegovanou pozicí v síti mohl zachytávat nebo pozměňovat data chráněná TLS/SSL. Pointou TLS a SSL je jaksi právě to, aby data nemohla být zachycena a přečtena, takže pokud to do té doby bylo možné, bylo něco zatraceně špatně. Jádro celého patche ovšem spočívalo pouze v jediném magickém řádku kódu. Respektive v jeho odstranění z funkce pro ověření podpisu.

static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams, uint8_t *signature, UInt16 signatureLen)
{
	OSStatus        err;
	...
	if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
		goto fail;
	if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
		goto fail;
		goto fail;
	if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
		goto fail;
	...
fail:
	SSLFreeBuffer(&signedHashes);
	SSLFreeBuffer(&hashCtx);
	return err;
}

Támhleto dvojité goto uprostřed vinou absence množinových závorek, které by označovaly tělo větve podmínky, totiž způsobilo, že funkce přeskočila na návěstí fail vždy. Tedy i v případě, kdy update SHA-1 byl proveden úspěšně a metoda SSLHashSHA1.update vrátila nulu. A protože hodnotou proměnné err mohla být právě ona vrácená nula, znamenalo to, že celá funkce pro verifikaci nakonec ohlásila úspěch, nehledě na to, co by vrátila metoda SSLHashSHA1.final kdyby se na ni dostalo.

Funkce SSLVerifySignedServerKeyExchange je použita při výměně symetrických klíčů pomocí Diffie-Hellman algoritmu používaného při navazování SSL/TLS spojení. Pomocí tohoto algoritmu si protistrany vymění části sdíleného klíče způsobem, který případnému čmuchalovi zabraňuje složený klíč odposlechnout a zároveň si při výměně sdělí svoje identity a veřejné klíče, na základě kterých ověřují, zda část sdíleného klíče přišla skutečně od toho, od koho měla. Výše zmíněný bug umožnil příjem a následnou úspěšnou verifikaci i v případě, že protistrana použila úplně jiný soukromý klíč (tedy nepasující ke klíči veřejnému), případně žádný soukromý klíč vůbec nepoužila a data si vymyslela.

GnuTLS a goto cleanup


GnuTLS je, podobně jako známější OpenSSL, kryptografická knihovna, používaná převážně v open-source, resp. GPL-licensed softwaru. OpenSSL je totiž vydáváno pod Apache a BSD licencí a nikoliv pod sluníčkovou GPL/LGPL, takže by licenční puristé při použití OpenSSL museli použít GPL linking exception, což samozřejmě málokdy chtějí. Oproti OpenSSL je na GnuTLS knihovnu je obecně pohlíženo jako na tu, která má více prasečí kód, ale která má jednodušší API, lépe se s ní pracuje a lépe se implementuje do nejrůznějších projektů.[citation needed] 27. Února přibyl v repozitáři GnuTLS commit 6aa26f78150ccbdf0aec1878a41c17c41d358a3b opravující jakési návratové kódy. Tato chyba pro změnu umožňovala, že funkce pro ověřování X.509 certifikátů používaných při navazování SSL/TLS spojení, mohla ohlásit úspěšné ověření i v případě, že tomu tak nebylo. Kde už jsem to jenom viděl...

Vzhledem k tomu, že se jedná o chybu skutečně kritickou a GnuTLS je použito v několika stovkách, možná i tisících aplikacích používaných po celém světě a přítomných v základních repozitářích prakticky všech linuxových distribucí, doporučuju se podívat na aktualizace čekající na vašich serverech a aplikovat alespoň ty, které mají co do činění se SSL/TLS, případně službami u kterých byste neradi, aby vám do nich někdo strkal nos.

10: Nepoužívejte goto! 20: GOTO 10


Goto, tedy nepodmíněný skok v programu na určité návěstí nebo číslo řádku, je jazykový konstrukt, který tu s námi přežívá již více než padesát let. Od příchodu strukturovaných a později i objektově orientovaných jazyků se na něj nahlíží jako na věc velmi nežádoucí, ztěžující orientaci v programu a náchylnou k chybám a přehlédnutím, jak se v obou případech potvrdilo. Ve vyšších programovacích jazycích (.NET, Java) se podobné veletoče k jakým bylo goto v případech výše užito, dají použít výjimky a jejich zpracování v try-catch-finally blocích. V C++ pak existuje koncept zvaný resource acquisition is initialization (RAII), který se používá k alokaci a dealokaci prostředků při zpracování výjimek. Podobně jako oheň nebo flaška kořalky, může být i goto dobrý sluha, ale zlý pán. Nepoužívejte jej, pokud bezpodmínečně nemusíte. Lenost se jako důvod nepočítá!

Obligatory xkcd

Update - 9.4.2013


Jak že zněla první věta článku? „Neštěstí nechodí nikdy samo.“? OpenSSL heartbleed bug.