Heartbleed問題

先週発表されたOpenSSLの脆弱性問題ですが、ここ最近の脆弱性の中で一番深刻なセキュリティホールのようです。ある発表によると深刻度10段階中、11ぐらいとのこと。

SSLは普段意識せず使用していますが、インターネット上の通信を暗号化する際に利用しています。https〜で始まるURLが該当します。

バグ自体は非常に単純な境界チェック漏れ(バッファーオーバフロー)です。
ハートビートリクエストのペイロード長フィールドに実際に送信している値より、大きな値を指定して送信するとペイロード領域を超えたメモリ領域まで読込んで、ハートビートレスポンスとして送り返すというものです。

グーグルのニールさんが発見したそうですが、さすがですね。
シンプルなバグなので、修正もシンプルで私でもよく分かりました。
単純なバグですが、影響の大きさにびっくりです。

実際悪用されても、痕跡は残らないため、どうなるのやら。
見覚えないクレジットカードの請求が来ませんように。。

OpenSSL Security Advisory [07 Apr 2014]
========================================

TLS heartbeat read overrun (CVE-2014-0160)
==========================================

A missing bounds check in the handling of the TLS heartbeat extension can be
used to reveal up to 64k of memory to a connected client or server.

Only 1.0.1 and 1.0.2-beta releases of OpenSSL are affected including
1.0.1f and 1.0.2-beta1.

Thanks for Neel Mehta of Google Security for discovering this bug and to
Adam Langley and Bodo Moeller for
preparing the fix.

Affected users should upgrade to OpenSSL 1.0.1g. Users unable to immediately
upgrade can alternatively recompile OpenSSL with -DOPENSSL_NO_HEARTBEATS.

1.0.2 will be fixed in 1.0.2-beta2.

修正前のt1_lib.c

2561         /* Read type and payload length first */
2562         hbtype = *p++;
2563         n2s(p, payload);
2564         pl = p;
2565 
2566         if (s->msg_callback)
2567                 s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
2568                         &s->s3->rrec.data[0], s->s3->rrec.length,
2569                         s, s->msg_callback_arg);
2570 
2571         if (hbtype == TLS1_HB_REQUEST)
2572                 {
2573                 unsigned char *buffer, *bp;
2574                 int r;
2575 
2576                 /* Allocate memory for the response, size is 1 bytes
2577                  * message type, plus 2 bytes payload length, plus
2578                  * payload, plus padding
2579                  */
2580                 buffer = OPENSSL_malloc(1 + 2 + payload + padding);
2581                 bp = buffer;
2582 
2583                 /* Enter response type, length and copy payload */
2584                 *bp++ = TLS1_HB_RESPONSE;
2585                 s2n(payload, bp);
2586                 memcpy(bp, pl, payload);

修正後のt1_lib.c

2596         /* Read type and payload length first */
2597         if (1 + 2 + 16 > s->s3->rrec.length)
2598                 return 0; /* silently discard */
2599         hbtype = *p++;
2600         n2s(p, payload);
2601         if (1 + 2 + payload + 16 > s->s3->rrec.length)
2602                 return 0; /* silently discard per RFC 6520 sec. 4 */
2603         pl = p;
2604 
2605         if (hbtype == TLS1_HB_REQUEST)
2606                 {
2607                 unsigned char *buffer, *bp;
2608                 int r;
2609 
2610                 /* Allocate memory for the response, size is 1 bytes
2611                  * message type, plus 2 bytes payload length, plus
2612                  * payload, plus padding
2613                  */
2614                 buffer = OPENSSL_malloc(1 + 2 + payload + padding);
2615                 bp = buffer;
2616 
2617                 /* Enter response type, length and copy payload */
2618                 *bp++ = TLS1_HB_RESPONSE;
2619                 s2n(payload, bp);
2620                 memcpy(bp, pl, payload);