Gmane
From: Frank Ellermann <nobody <at> xyzzy.claranet.de>
Subject: Digest-MD5 to Historic
Newsgroups: gmane.ietf.sasl
Date: 2008-02-11 10:34:50 GMT (1 year, 20 weeks, 3 days, 17 hours and 14 minutes ago)

Hi, 

here is the proposed text explaining the MD5-SESS Digest-MD5
problem.  I could transform it into xml2rfc format if needed.

 Frank

-----------------------------------------------------------------
Not counting the optional and for digest calculations unused HTTP
Auth Digest <opaque> parameter DIGEST-MD5 uses up to twelve input
parameters <user>, <pass>, <realm>, <method>, <uri>, <nonce>,
<qop>, <cnonce>, <nc>, <alg>, <hash>, and <authz>.

All parameter values are given in <quoted-string>s or directly as
<token>s.  The <quoted-string> form is required for values using
characters not permitted in a <token>.  In a <quoted-string> all
characters can be given as a <quoted-pair> (a backslash followed
by the character).  Notably <quoted-pair>s are required for the
quote and backslash characters.

For all digest calculations <token> values are used "as is", for
<quoted-string>s the delimiting quotes are removed, yielding a
<qdstr-val> keeping any <quoted-pair>s.

The <alg> parameter is optional, its default value is 'MD5',  It
can be also 'MD5-SESS', a case insensitive value for comparisons.
The optional <authz> parameter can be used only with 'MD5-SESS'.

Client nonce <cnonce> and nonce count <nc> are required if <qop>
is given, the <nc> is evaluated as eight hex. digits (big endian
with leading zeros).

For backwards compatibility [RFC 2069} <qop>, <cnonce>, <nc>,
<alg>, <hash>, and <authz> can be omitted.  'MD5-SESS' cannot be
used in backwards compatible mode.

If given <qop> can be 'auth', 'auth-int', and 'auth-conf'.  The
<hash> is required for 'auth-int' and 'auth-conf'.  It consists
of 32 lower case hex. digits for the MD5 of the body, or 32 zero
digits if there is no body.  For <qop> 'auth' a <hash> cannot be
used.

For challenges the <method> is either 'AUTHENTICATE' [RFC 2831]
or 'GET', 'INVITE', etc. [RFC 2617].  For responses the method is
omitted and treated as empty string.  In digest calculations the
<uri> is always separated by a colon from the preceding <method>,
empty or otherwise.  But it is only separated by a colon from a
following <hash> if there is a <hash>, i.e. not for <qop> 'auth'.

Omitting plausibility checks and parameter parsing, as well as
all details of  XURI = <method> ":" <uri> [":" <hash>]  the code
for DIGEST-MD5 could be something (here using REXX) like this:

   parse arg USER, PASS, REALM, NONCE, CNONCE, NC, QOP, XURI, ALG
   ALG = translate( ALG )        /* ALGorithm is case insensitive */

   HA1 = MD5(  USER || ':' || REALM || ':' || PASS )
   if ALG = 'MD5-SESS'  then  do
      HA1 = x2c( HA1 ) || ':' || NONCE || ':' || CNONCE
      if arg( 10, 'e' ) then  HA1 = HA1 || ':' || arg( 10 )
      HA1 = MD5( HA1 )           /* optional 10th argument: AUTHZ */
   end

   HA2 = MD5( XURI )             /* XURI incl. hash for auth-int  */
   TMP = NONCE                   /* 2069 compatibility (= no qop) */
   if ALG = 'MD5-SESS' | QOP <> ''  then  do
      TMP = translate( d2x( NC, 8 ), 'abcdef', 'ABCDEF' )
      TMP = NONCE || ':' || TMP || ':' || CNONCE || ':' || QOP
   end

   return MD5( HA1 || ':' || TMP || ':' || HA2 )

Here MD5( x ) is a subroutine returning 32 lower case hex. digits
of the MD5 [RFC 1321].  Ideally this code should also work for an
HTTP Auth Digest [RFC 2617].  Unfortunately this is not the case
for 'MD5-SESS':  [RFC 2831] adopted the [RFC 2617] algorithms "as
is" before the 'MD5-SESS' erratum was reported.  One line in the
example code shown above has to be modified:

      HA1 = HA1 || ':' || NONCE || ':' || CNONCE

The difference is x2c( HA1 ) vs. HA1.  In other words [RFC 2831]
uses a binary MD5 where [RFC 2617] plus erratum uses a hex. MD5
string.  See the expired [I-D.smith-sipping-auth-01] for correct
2069-fallback and 'MD5-SESS' examples.

New "fixed" [RFC 2617] 'MD5-SESS' results for examples published
in [RFC 2831] and [RFC 4643] are shown below, followed by four
relevant examples found in [I-D.smith-sipping-auth-01]:

1: user   = "chris"
   pass   = "secret"
   realm  = "elwood.innosoft.com"
   method = "AUTHENTICATE"
   uri    = "imap/elwood.innosoft.com"
   nonce  = "OA6MG9tEQGm2hh"
   qop    = "auth"
   cnonce = "OA6MHXh6VqTrRk"
   nc     = 1
   alg    = "md5-sess"

   RFC 2831 digest  = "d388dad90d4bbd760a152321f2143af7"
   RFC 2831 rspauth = "ea40f60335c427b5527b84dbabcdfffd"

   RFC 2617 digest  = "26ef1190b643a36e879673066098379c"
   RFC 2617 rspauth = "c316c87a595a2cbfb4405784db016e34"

2: user   = "chris"
   pass   = "secret"
   realm  = "elwood.innosoft.com"
   method = "AUTHENTICATE"
   uri    = "acap/elwood.innosoft.com"
   nonce  = "OA9BSXrbuRhWay"
   qop    = "auth"
   cnonce = "OA9BSuZWMSpW8m"
   nc     = 1
   alg    = "md5-sess"

   RFC 2831 digest  = "6084c6db3fede7352c551284490fd0fc"
   RFC 2831 rspauth = "2f0b3d7c3c2e486600ef710726aa2eae"

   RFC 2617 digest  = "90771dc5643a801bb9a9bcbb1ed3cd34"
   RFC 2617 rspauth = "ec0700b2da00dd133bcb0c841f42d341"

3: user   = "test"
   pass   = "test"
   realm  = "eagle.oceana.com"
   method = "AUTHENTICATE"
   uri    = "nntp/localhost"
   nonce  = "sayAOhCEKGIdPMHC0wtleLqOIcOI2wQYIe4zzeAtuiQ="
   qop    = "auth-conf"
   cnonce = "0Y3JQV2Tg9ScDip+O1SVC0rhVg//+dnOIiGz/7CeNJ8="
   nc     = 1
   alg    = "md5-sess"
   hash   = "00000000000000000000000000000000"

   RFC 2831 digest  = "d43cf66cffa903f9eb0356c08a3db0f2"
   RFC 2831 rspauth = "de2e127e5a81cda53d97acda35cde83a"

   RFC 2617 digest  = "41e814138958b1a0f08ef8b2dbe94ee9"
   RFC 2617 rspauth = "3f4d2b034c67c0c77df650f34ece6127"

4: user   = "bob"
   pass   = "zanzibar"
   realm  = "biloxi.com"
   method = "INVITE"
   uri    = "sip:bob <at> biloxi.com"
   nonce  = "dcd98b7102dd2f0e8b11d0f600bfb0c093"
   cnonce = "0a4f113b"
   nc     = 1

   digest = "bf57e4e0d0bffc0fbaedce64d59add5e"
   No <qop> => 2069-fallback, <cnonce> and <nc> ignored

5: user   = "bob"
   pass   = "zanzibar"
   realm  = "biloxi.com"
   method = "INVITE"
   uri    = "sip:bob <at> biloxi.com"
   nonce  = "dcd98b7102dd2f0e8b11d0f600bfb0c093"
   qop    = "auth"
   cnonce = "0a4f113b"
   nc     = 1

   digest = "89eb0059246c02b2f6ee02c7961d5ea3"
   No <alg> => default 'MD5', <cnonce> and <nc> honored

6: user   = "bob"
   pass   = "zanzibar"
   realm  = "biloxi.com"
   method = "INVITE"
   uri    = "sip:bob <at> biloxi.com"
   nonce  = "dcd98b7102dd2f0e8b11d0f600bfb0c093"
   qop    = "auth"
   cnonce = "0a4f113b"
   nc     = 1
   alg    = "MD5-sess"

   RFC 2617 digest = "e4e4ea61d186d07a92c9e1f6919902e9"

7: user   = "bob"
   pass   = "zanzibar"
   realm  = "biloxi.com"
   method = "INVITE"
   uri    = "sip:bob <at> biloxi.com"
   nonce  = "dcd98b7102dd2f0e8b11d0f600bfb0c093"
   qop    = "auth-int"
   cnonce = "0a4f113b"
   nc     = 1
   alg    = "MD5-sess"
   hash   = "c1ed018b8ec4a3b170c0921f5b564e48"

   RFC 2617 digest = "91984da2d8663716e91554859c22ca70"