HTTP Digest 認証の SHA-256 の扱い

HTTP Digest 認証で SHA-256 を使うための動きをメモ。 動きを見ていく要点は、 algorithm=SHA-256 の表記のぶれで、 ドラフトの初期では SHA256、 途中で SHA2-256 と変わり、 現時点では SHA-256 に落ち着いています。 SHA-256 を使った、response の求め方は変わっておらず、 H(data)SHA-256(data) とし、メッセージ・ダイジェストを英小文字 16 進数表現で出力するのは MD5 と同じです。

RFC 2617 スタンダードでは、 MD5MD5-sess が登録されていました。

RFC 2617 - HTTP Authentication: Basic and Digest Access Authentication (1999年)

    algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | token )

For the "MD5" and "MD5-sess" algorithms
    H(data) = MD5(data)

and
    KD(secret, data) = H(concat(secret, ":", data))

MD5 の利用が非推奨になってからずいぶん経た 2013 年 6 月に最初のドラフトが登場します。このドラフトの最初の原稿では SHA1、SHA224、SHA256、SHA384、SHA512 を追加していましたが、議論を経て、2013 年 9 月に追加分を SHA2-256 と SHA2-512-256 の 2 つに絞ることになりました。

draft-ietf-httpauth-digest-update-05 - HTTP Digest Update (2013 年 9 月)

    algorithm = "algorithm" "=" (
                    "MD5" | "MD5-sess" |
                    "SHA2-256" | "SHA2-256-sess" |
                    "SHA2-512-256" | "SHA2-512-256-sess" |
                    token)

For the  "MD5 and "MD5-sess" algorithms
    H(data) = MD5(data)

For the "SHA2-256" and "SHA2-256-sess" algorithms
    H(data) = SHA2-256(data)

For the "SHA2-512-256" and "SHA2-512-256-sess" algorithms
    H(data) = SHA2-512-256(data)

and
    KD(secret, data) = H(concat(secret, ":", data))

その後、 HTTP/1.1 のスタンダードが RFC 7230 から RFC 7235 までへ 2014 年に改訂され、 上のドラフトを取り込みつつ RFC 2617 の Digest 認証部分を新しいスタンダードに合わせて改訂する作業が始まりました。 その中で、 SHA2-256 は SHA-256 へ、 SHA2-512-256 は SHA-512-256 へと表記が変わります。 現在、ドラフトをめぐって議論が続いている最中で、2015 年 8 月現在の最新の原稿では、SHA-256 を必須に、 SHA-512-256 は予備、 MD5 は非推奨になりました。 ただし、 後方互換性から algorithm の指定がないときは MD5 にすることになっています。

draft-ietf-httpauth-digest-19 - HTTP Digest Access Authentication (2015 年 4 月)

This documents adds SHA-256 and SHA-512/256 algorithms.
To maintain backwards compatibility with [RFC2617],
the MD5 algorithm is still supported but NOT RECOMMENDED.

algorithm
    If this is not present it is assumed to be "MD5".

For "<algorithm>" and "<algorithm>-sess"
    H(data) = <algorithm>(data)

and
    KD(secret, data) = H(concat(secret, ":", data))

This specification defines the following algorithms:

o  SHA2-256 (mandatory to implement)
o  SHA2-512/256 (as a backup algorithm)
o  MD5 (for backward compatibility).

+----------------+-------------+-----------+
| Hash Algorithm | Digest Size | Reference |
+----------------+-------------+-----------+
| "MD5"          | 128         | RFC XXXX  |
| "SHA-512-256"  | 256         | RFC XXXX  |
| "SHA-256"      | 256         | RFC XXXX  |
+----------------+-------------+-----------+

Each one of the algorithms defined in the registry might have a -sess variant,
e.g.  MD5-sess, SHA-256-sess, etc.

ドラフト記載の例の response を計算してみます。 H(data) はメッセージ・ダイジェストの英小文字 16 進数表記法で出力するため、 perl では sha256_hex を使います。

#!/usr/bin/env perl
use feature qw(say);
use Digest::SHA qw(sha256_hex); 

=head1 internet draft
   Authorization: Digest username="Mufasa",
       realm="http-auth@example.org",
       uri="/dir/index.html",
       algorithm=SHA-256,
       nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
       nc=00000001,
       cnonce="f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ",
       qop=auth,
       response="753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1",
       opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
=cut

my $username = 'Mufasa';
my $realm = 'http-auth@example.org';
my $passwd = 'Circle of Life';
my $reqmethod = 'GET';
my $uri = '/dir/index.html';
my $nonce = '7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v';
my $nc = '00000001';
my $cnonce = 'f2/wE4q74E6zIJEtWaHKaf5wv/H5QzzpXusqGemxURZJ';
my $qop = 'auth';

my $a1 = join ':', $username, $realm, $passwd;
my $a2 = join ':', $reqmethod, $uri;
my $response = sha256_hex(join ':', sha256_hex($a1), $nonce, $nc, $cnonce, $qop, sha256_hex($a2));

say $response;
#=> 753927fa0e85d155564e2e272a28d1802ca10daf4496794697cf8db5856cb6c1

ドラフトの議論を追っての印象では、 紆余曲折が続いていた algorithm の表記は SHA-256 と SHA-256-sess に落ち着いたようなので、 スタンダードになっても、 そのまま残ってくれるのではないかと考えられます。 新規に HTTP サーバの Digest 認証を実装するなら、 この 2 つの algorithm も利用できるようにしておいて、オプションではとりあえずオフにしておき、スタンダードになったときにオンにするようにしておくと良いかもしれません。

2015 年 9 月に RFC 7616 としてスタンダードになりました。 algorithm の表記は予想通り、 SHA-256 と SHA-256-sess、 SHA-512-256 と SHA-512-256-sess を採用しています。

http://tools.ietf.org/html/rfc7616

2015 年 8 月 22 日追記

ところで、チャレンジ・レスポンスのやりとりで、algorithm のどれを使うべきかはサーバがクライアントに送るチャレンジで指示します。algorithm はチャレンジごとに一つずつ指定することができ、サーバはレスポンスに複数のチャレンジを送ることができます。RFC 7230 HTTP/1.1 によると、 1 つの WWW-Authenticate に複数のチャレンジをコンマで連結して送るのが正式な記述方法になっています。ただし、同一名のヘッダ・フィールドが繰り返し出現するときは、コンマで区切ってフィールの値を連結したものと同じ扱いにすることが定めてあるので、複数の WWW-Authenticate フィールドを並べても一緒の意味になるはずです。ドラフトの記載例では SHA-256 と MD5 のそれぞれのチャレンジをもつ WWW-Authenticate フィールドを別分けして記述してあります。この例では、algorithm が異なるだけで、nonce と opaque には同じ値を使っています。

http://tools.ietf.org/html/draft-ietf-httpauth-digest-19

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest
   realm="http-auth@example.org",
   qop="auth, auth-int",
   algorithm=SHA-256,
   nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
   opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"
WWW-Authenticate: Digest
   realm="http-auth@example.org",
   qop="auth, auth-int",
   algorithm=MD5,
   nonce="7ypf/xlj9XXwfDPEoM4URrv/xwf94BcCAzFZH4GiTo0v",
   opaque="FQhe/qaU925kfnzjCev0ciny7QMkPqMAFRtzCUYo5tdS"

この場合、 クライアントは、 MD5 か SHA-256 のどちらか一方のレスポンスを作ってサーバに返します。