The epic “goto fail” in Apple’s SSL implementation

Security and Privacy

I wrote here about the SSL bug and what it could do for your security and privacy…

There is a website which helps users checking if they are affected by this bug: gotofail.com. Here are more details about the gotofail bug. 

Here is a pretty good explanation about how this bug “works” (courtesy of gotofail.com):

Normal SSL/TLS:

  • Client (browser): Hey server, let’s speak in private. Here is a list of ciphers I know that we could use.
  • RealServer: Okay, we can speak in private, here is my identification paperwork.
  • Client: Your paperwork looks good, lets continue.
  • RealServer: Let’s use cipher XYZ. Please encrypt the conversation key you want to use to this public key. I have signed our conversation so far with the key from my identification paperwork to prove everything is legit.
  • Client: Okay, your signature looks good, here’s the conversation key encrypted so only you can read it. I am switching to cipher XYZ with that key now.
  • Client and RealServer converse privately.

SSL/TLS with a vulnerable Apple product:

  • Client (browser): Hey server, let’s speak in private. Here is a list of ciphers I know that we could use.
  • FakeServer: Okay, we can speak in private, here is my identification paperwork (RealServer’s identification paperwork).
  • Client: Your paperwork looks good, lets continue.
  • FakeServer: Let’s use cipher XYZ. Please encrypt the conversation key you want to use to this public key. Here’s a picture of a cat I found, isn’t it great?
  • Client: Oh, sooo cute! What were we talking about? Oh yeah, here’s the conversation key encrypted so that only you can read it. I am switching to cipher XYZ with that key now.
  • FakeServer (thinking to itself): I can’t believe Client fell for that trick. Now I just set up a conversation with RealServer…
  • Client and RealServer converse with FakeServer able to see and change everything

 

What I didn’t write so far is the more technical meaning of this bug. And by that I mean the code…

Why using GOTO ?

Using this statement is almost always a bad idea.

Microsoft describes here the usage of GoTo: http://msdn.microsoft.com/en-us/library/b34dt9cd.aspx

It is good programming style to use the break, continue, and return statements instead of the goto statement whenever possible. However, because the break statement exits from only one level of a loop, you might have to use a goto statement to exit a deeply nested loop.

However, use of goto statement is highly discouraged in any programming language because it makes difficult to trace the control flow of a program, making the program hard to understand and hard to modify. Any program that uses a goto can be rewritten so that it doesn’t need the goto.

 

What Apple did was:

if (something bad happens)

goto fail;

This should have not been here:

goto fail;

… do server validation according to the SSL certificate

 

fail:

… gracefully exit

return the_error_code;

 

Corrected code:

while (1)
{

if ( (error = something bad happens) != 0)
break;

if ( (error = something else bad happens) != 0)
break;

break; // exit the loop gracefully.

}

do something with the error code.

if (error)
display error code

Code analysis

File http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c
Function: SSLVerifySignedServerKeyExchange

 

The original, not-recommended usage of goto

 

if ((err = SSLFreeBuffer(&hashCtx)) != 0)
        goto fail;

    if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
        goto fail;
    if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
        goto fail;
    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;

	err = sslRawVerify(ctx,
                       ctx->peerPubKey,
                       dataToSign,				/* plaintext */
                       dataToSignLen,			/* plaintext length */
                       signature,
                       signatureLen);
	if(err) {
		sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
                    "returned %d\n", (int)err);
		goto fail;
	}

fail:
    SSLFreeBuffer(&signedHashes);
    SSLFreeBuffer(&hashCtx);
    return err;

The correct code

while (1)
{

if ((err = SSLFreeBuffer(&hashCtx)) != 0)
        break;

    if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
        break;
    if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
        break;
    if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
        break;
    if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
        break;

    if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
        break;

	err = sslRawVerify(ctx,
                       ctx->peerPubKey,
                       dataToSign,				/* plaintext */
                       dataToSignLen,			/* plaintext length */
                       signature,
                       signatureLen);
	if(err) {
		sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
                    "returned %d\n", (int)err);
		break;
	}

printf("\nAll was good");

break;//exit the loop

}//while 1

    SSLFreeBuffer(&signedHashes);
    SSLFreeBuffer(&hashCtx);
    return err;

 

 


© Copyright 2014 Sorin Mustaca, All rights Reserved. Written For: Sorin Mustaca on Cybersecurity


Check www.endpoint-cybersecurity.com for seeing the consulting services we offer.

Visit www.itsecuritynews.info for latest security news in English
Besuchen Sie de.itsecuritynews.info für IT Sicherheits News auf Deutsch