Subject: Digest-MD5 to Historic

From: "Frank Ellermann" <[email-masked]>
Date: Mon, 11 Feb 2008 11:34:50 +0100

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:[email-masked]"
   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:[email-masked]"
   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:[email-masked]"
   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:[email-masked]"
   nonce  = "dcd98b7102dd2f0e8b11d0f600bfb0c093"
   qop    = "auth-int"
   cnonce = "0a4f113b"
   nc     = 1
   alg    = "MD5-sess"
   hash   = "c1ed018b8ec4a3b170c0921f5b564e48"

   RFC 2617 digest = "91984da2d8663716e91554859c22ca70"

---

From: "Frank Ellermann" <[email-masked]>
Date: Fri, 22 Feb 2008 10:44:38 +0100

> problem.  I could transform it into xml2rfc format if needed.

Of course it should be "algorithm" instead of "alg" in the MD5
examples, sorry.  I've updated the test suite also for RFC 5090,
http://omniplex.blogspot.com/2008/02/md5-sess-and-rfc-5090.html

 Frank