Sunday, February 23, 2014

Apple iOS 7.0.6's patch and the security flaw that prompted the patch

Let's consider a scenario where you need to connect to your bank via a website. How can you ensure that the communication link between you and your bank is secure?

Secure Sockets Layer (SSL) or the newer version of SSL: Transport Layer Security (TLS) is two encryption protocols that can be used to make sure that no third party is listening in on your conversation with your bank. When a communication between two entities IS intercepted, then we consider this a Man in the Middle Attack or MitM.

A MitM attack is where the Victim is communicating with the Web Server via an SSL connection. The attacker listens in on this communication and grabs all the sensitive data being transferred between the two connections. The Victim will have no idea that this is occurring.


The issue with iOS before 7.0.6 was that this SSL connection was not verified before the connection was created. So this created issues with MitM attacks. If you have an iPhone, then you should update as soon as possible. Currently, OS X does not have a patch for this, yet.

You can see the security flaw advisement posted on Apple's website here: http://support.apple.com/kb/HT6147

The description mentions:

iOS 7.0.6

  • Data Security 
  • Available for: iPhone 4 and later, iPod touch (5th generation), iPad 2 and later 
  • Impact: An attacker with a privileged network position may capture or modify data in sessions protected by SSL/TLS 
  • Description: Secure Transport failed to validate the authenticity of the connection. This issue was addressed by restoring missing validation steps. 
  • CVE-ID 
  • CVE-2014-1266

Privileged network means that if you and the attacker are sitting at Barnes and Nobles together, then he/she can start sniffing your secure connections, which in the case of banking or any sensitive information is concerned, you don't want that.

You can see the function (highlighted below) where the issue occurs.

static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
                                 uint8_t *signature, UInt16 signatureLen)
{
    OSStatus        err;
    SSLBuffer       hashOut, hashCtx, clientRandom, serverRandom;
    uint8_t         hashes[SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN];
    SSLBuffer       signedHashes;
    uint8_t   *dataToSign;
 size_t   dataToSignLen;

 signedHashes.data = 0;
    hashCtx.data = 0;

    clientRandom.data = ctx->clientRandom;
    clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;
    serverRandom.data = ctx->serverRandom;
    serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE;


 if(isRsa) {
  /* skip this if signing with DSA */
  dataToSign = hashes;
  dataToSignLen = SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN;
  hashOut.data = hashes;
  hashOut.length = SSL_MD5_DIGEST_LEN;
  
  if ((err = ReadyHash(&SSLHashMD5, &hashCtx)) != 0)
   goto fail;
  if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0)
   goto fail;
  if ((err = SSLHashMD5.update(&hashCtx, &serverRandom)) != 0)
   goto fail;
  if ((err = SSLHashMD5.update(&hashCtx, &signedParams)) != 0)
   goto fail;
  if ((err = SSLHashMD5.final(&hashCtx, &hashOut)) != 0)
   goto fail;
 }
 else {
  /* DSA, ECDSA - just use the SHA1 hash */
  dataToSign = &hashes[SSL_MD5_DIGEST_LEN];
  dataToSignLen = SSL_SHA1_DIGEST_LEN;
 }

 hashOut.data = hashes + SSL_MD5_DIGEST_LEN;
    hashOut.length = SSL_SHA1_DIGEST_LEN;
    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;
}


SOURCE: http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c?txt

Having an extra "goto fail;" outside of an IF statement basically makes the rest of the code null and invalid. The code will execute all the way up to the IF statement, then execute the "go to fail;" statement and never makes it to the rest of the code. Apple argues that this code still takes care of MOST SSL connections, but when we are talking about sensitive information, you dont want something that works MOST of the time. You want something that works ALL the time.

No comments: