2018-11-13 16:57 CET

View Issue Details Jump to Notes ]
IDProjectCategoryView StatusLast Update
0005397libmicrohttpddigest authentication (HTTP)public2018-11-06 19:46
ReporterDirk Brinkmeier 
Assigned ToChristian Grothoff 
PrioritynormalSeveritytweakReproducibilityN/A
StatusclosedResolutionfixed 
Product Version0.9.59 
Target Version0.9.60Fixed in Version0.9.60 
Summary0005397: Patch for digest authentication from user database with precalculated 'username:realm:password' hash
DescriptionI'm using a a user database for digest authentication.
To avoid using clear text password storage, I precalculate the 'username:realm:password' MD5 hash and store the hash value in the database.

To be able to use digest authentication with libmicrohttpd, I modified/duplicated the given function MHD_digest_auth_check(...) and extend this one to MHD_digest_auth_check_digest(...).
I attached a patch for that purpose.

I hope you can use the patch, if you think that this is a useful extension...

Regards,
Dirk.


TagsNo tags attached.
Attached Files
  • diff file icon digestauth_by_hash.diff (9,039 bytes) 2018-07-07 15:44 -
    diff -ur ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/include/microhttpd.h ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/include/microhttpd.h
    --- ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/include/microhttpd.h	2018-02-01 20:12:55.000000000 +0100
    +++ ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/include/microhttpd.h	2018-07-07 11:15:15.994086680 +0200
    @@ -292,6 +292,9 @@
     _MHD_DEPR_MACRO("Macro MHD_LONG_LONG_PRINTF is deprecated, use MHD_UNSIGNED_LONG_LONG_PRINTF")
     #endif
     
    +#ifndef MD5_DIGEST_SIZE
    +#define	 MD5_DIGEST_SIZE 16
    +#endif
     
     /**
      * @defgroup httpcode HTTP response codes.
    @@ -3140,10 +3143,32 @@
      */
     _MHD_EXTERN int
     MHD_digest_auth_check (struct MHD_Connection *connection,
    -		       const char *realm,
    -		       const char *username,
    -		       const char *password,
    -		       unsigned int nonce_timeout);
    +				const char *realm,
    +				const char *username,
    +				const char *password,
    +				unsigned int nonce_timeout);
    +
    +/**
    + * Authenticates the authorization header sent by the client
    + *
    + * @param connection The MHD connection structure
    + * @param realm The realm presented to the client
    + * @param username The username needs to be authenticated
    + * @param digest An `unsigned char *' pointer to the binary MD5 sum
    + * 			for the precalculated hash value "username:realm:password"
    + * 			of MD5_DIGEST_SIZE bytes
    + * @param nonce_timeout The amount of time for a nonce to be
    + * 			invalid in seconds
    + * @return #MHD_YES if authenticated, #MHD_NO if not,
    + * 			#MHD_INVALID_NONCE if nonce is invalid
    + * @ingroup authentication
    + */
    +_MHD_EXTERN int
    +MHD_digest_auth_check_digest (struct MHD_Connection *connection,
    +				const char *realm,
    +				const char *username,
    +				const unsigned char digest[MD5_DIGEST_SIZE],
    +				unsigned int nonce_timeout);
     
     
     /**
    diff -ur ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c
    --- ./libmicrohttpd-0.9.59_org/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c	2018-02-01 20:12:55.000000000 +0100
    +++ ./libmicrohttpd-0.9.59_new/libmicrohttpd-0.9.59/src/microhttpd/digestauth.c	2018-07-07 11:16:41.251463205 +0200
    @@ -93,8 +93,62 @@
     
     
     /**
    - * calculate H(A1) as per RFC2617 spec and store the
    - * result in 'sessionkey'.
    + * calculate H(A1) from given hash as per RFC2617 spec
    + * and store the * result in 'sessionkey'.
    + *
    + * @param alg The hash algorithm used, can be "md5" or "md5-sess"
    + * @param digest An `unsigned char *' pointer to the binary MD5 sum
    + * 			for the precalculated hash value "username:realm:password"
    + * 			of MD5_DIGEST_SIZE bytes
    + * @param nonce A `char *' pointer to the nonce value
    + * @param cnonce A `char *' pointer to the cnonce value
    + * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
    + */
    +static void
    +digest_calc_ha1_from_digest (const char *alg,
    +		 const unsigned char digest[MD5_DIGEST_SIZE],
    +		 const char *nonce,
    +		 const char *cnonce,
    +		 char sessionkey[HASH_MD5_HEX_LEN + 1])
    +{
    +  struct MD5Context md5;
    +  if (MHD_str_equal_caseless_(alg,
    +                              "md5-sess"))
    +    {
    +	  unsigned char ha1[MD5_DIGEST_SIZE];
    +      MD5Init (&md5);
    +      MD5Update (&md5,
    +                 (const unsigned char *) digest,
    +                 MD5_DIGEST_SIZE);
    +      MD5Update (&md5,
    +                 (const unsigned char *) ":",
    +                 1);
    +      MD5Update (&md5,
    +                 (const unsigned char *) nonce,
    +                 strlen (nonce));
    +      MD5Update (&md5,
    +                 (const unsigned char *) ":",
    +                 1);
    +      MD5Update (&md5,
    +                 (const unsigned char *) cnonce,
    +                 strlen (cnonce));
    +      MD5Final (ha1,
    +                &md5);
    +      cvthex (ha1,
    +              sizeof (ha1),
    +              sessionkey);
    +    }
    +  else
    +    {
    +	  cvthex (digest,
    +			  MD5_DIGEST_SIZE,
    +	          sessionkey);
    +    }
    +}
    +
    +/**
    + * calculate H(A1) from username, realm and password as per RFC2617 spec
    + * and store the result in 'sessionkey'.
      *
      * @param alg The hash algorithm used, can be "md5" or "md5-sess"
      * @param username A `char *' pointer to the username value
    @@ -105,7 +159,7 @@
      * @param sessionkey pointer to buffer of HASH_MD5_HEX_LEN+1 bytes
      */
     static void
    -digest_calc_ha1 (const char *alg,
    +digest_calc_ha1_from_user (const char *alg,
     		 const char *username,
     		 const char *realm,
     		 const char *password,
    @@ -134,31 +188,7 @@
                  strlen (password));
       MD5Final (ha1,
                 &md5);
    -  if (MHD_str_equal_caseless_(alg,
    -                              "md5-sess"))
    -    {
    -      MD5Init (&md5);
    -      MD5Update (&md5,
    -                 (const unsigned char *) ha1,
    -                 sizeof (ha1));
    -      MD5Update (&md5,
    -                 (const unsigned char *) ":",
    -                 1);
    -      MD5Update (&md5,
    -                 (const unsigned char *) nonce,
    -                 strlen (nonce));
    -      MD5Update (&md5,
    -                 (const unsigned char *) ":",
    -                 1);
    -      MD5Update (&md5,
    -                 (const unsigned char *) cnonce,
    -                 strlen (cnonce));
    -      MD5Final (ha1,
    -                &md5);
    -    }
    -  cvthex (ha1,
    -          sizeof (ha1),
    -          sessionkey);
    +  digest_calc_ha1_from_digest(alg, ha1, nonce, cnonce, sessionkey);
     }
     
     
    @@ -664,6 +694,9 @@
      * @param realm The realm presented to the client
      * @param username The username needs to be authenticated
      * @param password The password used in the authentication
    + * @param digest An optional `unsigned char *' pointer to the binary MD5 sum
    + * 			for the precalculated hash value "username:realm:password"
    + * 			of MD5_DIGEST_SIZE bytes
      * @param nonce_timeout The amount of time for a nonce to be
      * 			invalid in seconds
      * @return #MHD_YES if authenticated, #MHD_NO if not,
    @@ -671,10 +704,11 @@
      * @ingroup authentication
      */
     int
    -MHD_digest_auth_check (struct MHD_Connection *connection,
    +MHD_digest_auth_check_all (struct MHD_Connection *connection,
     		       const char *realm,
     		       const char *username,
     		       const char *password,
    +		       const unsigned char digest[MD5_DIGEST_SIZE],
     		       unsigned int nonce_timeout)
     {
       struct MHD_Daemon *daemon = connection->daemon;
    @@ -868,13 +902,21 @@
           return MHD_NO;
         }
     
    -    digest_calc_ha1 ("md5",
    -                     username,
    -                     realm,
    -                     password,
    -                     nonce,
    -                     cnonce,
    -                     ha1);
    +    if (digest) {
    +		digest_calc_ha1_from_digest ("md5",
    +									 digest,
    +									 nonce,
    +									 cnonce,
    +									 ha1);
    +    } else {
    +		digest_calc_ha1_from_user ("md5",
    +								 username,
    +								 realm,
    +								 password,
    +								 nonce,
    +								 cnonce,
    +								 ha1);
    +    }
         digest_calc_response (ha1,
     			  nonce,
     			  nc,
    @@ -885,6 +927,7 @@
     			  hentity,
     			  respexp);
     
    +
         /* Need to unescape URI before comparing with connection->url */
         daemon->unescape_callback (daemon->unescape_callback_cls,
                                    connection,
    @@ -929,6 +972,62 @@
       }
     }
     
    +/**
    + * Authenticates the authorization header sent by the client
    + *
    + * @param connection The MHD connection structure
    + * @param realm The realm presented to the client
    + * @param username The username needs to be authenticated
    + * @param password The password used in the authentication
    + * @param nonce_timeout The amount of time for a nonce to be
    + * 			invalid in seconds
    + * @return #MHD_YES if authenticated, #MHD_NO if not,
    + * 			#MHD_INVALID_NONCE if nonce is invalid
    + * @ingroup authentication
    + */
    +_MHD_EXTERN int
    +MHD_digest_auth_check (struct MHD_Connection *connection,
    +				const char *realm,
    +				const char *username,
    +				const char *password,
    +				unsigned int nonce_timeout)
    +{
    +	return MHD_digest_auth_check_all(
    +			connection,
    +			realm, username, password,
    +			NULL,
    +			nonce_timeout);
    +}
    +
    +/**
    + * Authenticates the authorization header sent by the client
    + *
    + * @param connection The MHD connection structure
    + * @param realm The realm presented to the client
    + * @param username The username needs to be authenticated
    + * @param digest An `unsigned char *' pointer to the binary MD5 sum
    + * 			for the precalculated hash value "username:realm:password"
    + * 			of MD5_DIGEST_SIZE bytes
    + * @param nonce_timeout The amount of time for a nonce to be
    + * 			invalid in seconds
    + * @return #MHD_YES if authenticated, #MHD_NO if not,
    + * 			#MHD_INVALID_NONCE if nonce is invalid
    + * @ingroup authentication
    + */
    +_MHD_EXTERN int
    +MHD_digest_auth_check_digest (struct MHD_Connection *connection,
    +				const char *realm,
    +				const char *username,
    +				const unsigned char digest[MD5_DIGEST_SIZE],
    +				unsigned int nonce_timeout)
    +{
    +	return MHD_digest_auth_check_all(
    +			connection,
    +			realm, username, NULL,
    +			digest,
    +			nonce_timeout);
    +}
    +
     
     /**
      * Queues a response to request authentication from the client
    
    diff file icon digestauth_by_hash.diff (9,039 bytes) 2018-07-07 15:44 +

-Relationships Relation Graph ] Dependency Graph ]
+Relationships

-Notes

~0013143

Christian Grothoff (manager)

Patch integrated in Git head. Thanks, Dirk!
+Notes

-Issue History
Date Modified Username Field Change
2018-07-07 15:44 Dirk Brinkmeier New Issue
2018-07-07 15:44 Dirk Brinkmeier File Added: digestauth_by_hash.diff
2018-07-14 13:23 Christian Grothoff Assigned To => Christian Grothoff
2018-07-14 13:23 Christian Grothoff Status new => assigned
2018-07-14 13:24 Christian Grothoff Status assigned => resolved
2018-07-14 13:24 Christian Grothoff Resolution open => fixed
2018-07-14 13:24 Christian Grothoff Fixed in Version => 0.9.60
2018-07-14 13:24 Christian Grothoff Note Added: 0013143
2018-07-14 13:24 Christian Grothoff Target Version => 0.9.60
2018-11-06 19:46 Christian Grothoff Status resolved => closed
+Issue History