7373#include "apr_shm.h"
7474#include "apr_rmm.h"
7575#include "ap_provider.h"
76+ #include "apr_crypto.h" /* for apr_crypto_equals */
7677
7778#include "mod_auth.h"
7879
@@ -99,10 +100,17 @@ typedef struct digest_config_struct {
99100#define DFLT_NONCE_LIFE apr_time_from_sec(300)
100101#define NEXTNONCE_DELTA apr_time_from_sec(30)
101102
102-
103+ /* The server nonce has fixed length and is the concatenation of:
104+ * base64(apr_time_t timestamp) + hex(SHA1(realm+time[+opaque])) */
103105#define NONCE_TIME_LEN (((sizeof(apr_time_t)+2)/3)*4)
104106#define NONCE_HASH_LEN (2*APR_SHA1_DIGESTSIZE)
105107#define NONCE_LEN (int )(NONCE_TIME_LEN + NONCE_HASH_LEN)
108+ /* Evaluates to true if nonce string is valid. Since the time part of
109+ * the nonce is a base64 encoding of an apr_time_t (8 bytes), it
110+ * must end with a '='. */
111+ #define VALID_NONCE (n_ ) ((n_) && strlen((n_)) == NONCE_LEN && (n_)[NONCE_TIME_LEN - 1] == '=')
112+
113+ #define MD5_DIGEST_LEN (2*APR_MD5_DIGESTSIZE) /* ignoring trailing \0 */
106114
107115#define SECRET_LEN 20
108116#define RETAINED_DATA_ID "mod_auth_digest"
@@ -1013,8 +1021,9 @@ static int get_digest_rec(request_rec *r, digest_header_rec *resp)
10131021 resp -> nonce_count = apr_pstrdup (r -> pool , value );
10141022 }
10151023
1016- if (!resp -> username || !resp -> realm || !resp -> nonce || !resp -> uri
1017- || !resp -> digest
1024+ if (!resp -> username || !resp -> realm || !resp -> uri
1025+ || !VALID_NONCE (resp -> nonce )
1026+ || !resp -> digest || strlen (resp -> digest ) != MD5_DIGEST_LEN
10181027 || (resp -> message_qop && (!resp -> cnonce || !resp -> nonce_count ))) {
10191028 resp -> auth_hdr_sts = INVALID ;
10201029 return !OK ;
@@ -1066,14 +1075,9 @@ static int parse_hdr_and_update_nc(request_rec *r)
10661075}
10671076
10681077
1069- /*
1070- * Nonce generation code
1071- */
1072-
1073- /* The hash part of the nonce is a SHA-1 hash of the time, realm, server host
1074- * and port, opaque, and our secret.
1075- */
1076- static void gen_nonce_hash (char * hash , const char * timestr , const char * opaque ,
1078+ /* Writes the hash part of the server nonce to hash, which must be of
1079+ * minimum size (NONCE_HASH_LEN+1). */
1080+ static void gen_nonce_hash (char hash [NONCE_HASH_LEN + 1 ], const char * timestr , const char * opaque ,
10771081 const server_rec * server ,
10781082 const digest_config_rec * conf ,
10791083 const char * realm )
@@ -1427,27 +1431,14 @@ static int check_nonce(request_rec *r, digest_header_rec *resp,
14271431 time_rec nonce_time ;
14281432 char tmp , hash [NONCE_HASH_LEN + 1 ];
14291433
1430- /* Since the time part of the nonce is a base64 encoding of an
1431- * apr_time_t (8 bytes), it should end with a '=', fail early otherwise.
1432- */
1433- if (strlen (resp -> nonce ) != NONCE_LEN
1434- || resp -> nonce [NONCE_TIME_LEN - 1 ] != '=' ) {
1435- ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01775 )
1436- "invalid nonce '%s' received - length is not %d "
1437- "or time encoding is incorrect" ,
1438- resp -> nonce , NONCE_LEN );
1439- note_digest_auth_failure (r , conf , resp , 1 );
1440- return HTTP_UNAUTHORIZED ;
1441- }
1442-
14431434 tmp = resp -> nonce [NONCE_TIME_LEN ];
14441435 resp -> nonce [NONCE_TIME_LEN ] = '\0' ;
14451436 apr_base64_decode_binary (nonce_time .arr , resp -> nonce );
14461437 gen_nonce_hash (hash , resp -> nonce , resp -> opaque , r -> server , conf , ap_auth_name (r ));
14471438 resp -> nonce [NONCE_TIME_LEN ] = tmp ;
14481439 resp -> nonce_time = nonce_time .time ;
14491440
1450- if (strcmp (hash , resp -> nonce + NONCE_TIME_LEN )) {
1441+ if (! apr_crypto_equals (hash , resp -> nonce + NONCE_TIME_LEN , NONCE_HASH_LEN )) {
14511442 ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01776 )
14521443 "invalid nonce %s received - hash is not %s" ,
14531444 resp -> nonce , hash );
@@ -1778,7 +1769,7 @@ static int authenticate_digest_user(request_rec *r)
17781769
17791770 if (resp -> message_qop == NULL ) {
17801771 /* old (rfc-2069) style digest */
1781- if (strcmp (resp -> digest , old_digest (r , resp ))) {
1772+ if (! apr_crypto_equals (resp -> digest , old_digest (r , resp ), MD5_DIGEST_LEN )) {
17821773 ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01792 )
17831774 "user %s: password mismatch: %s" , r -> user ,
17841775 r -> uri );
@@ -1813,7 +1804,7 @@ static int authenticate_digest_user(request_rec *r)
18131804 /* we failed to allocate a client struct */
18141805 return HTTP_INTERNAL_SERVER_ERROR ;
18151806 }
1816- if (strcmp (resp -> digest , exp_digest )) {
1807+ if (! apr_crypto_equals (resp -> digest , exp_digest , MD5_DIGEST_LEN )) {
18171808 ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01794 )
18181809 "user %s: password mismatch: %s" , r -> user ,
18191810 r -> uri );
0 commit comments