]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Add in suggested patch for AuthDigestRealmSeed issue
authorJim Jagielski <jim@apache.org>
Thu, 15 Apr 2004 15:51:52 +0000 (15:51 +0000)
committerJim Jagielski <jim@apache.org>
Thu, 15 Apr 2004 15:51:52 +0000 (15:51 +0000)
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@103393 13f79535-47bb-0310-9956-ffa450edef68

src/ApacheCore.def
src/ApacheCoreOS2.def
src/CHANGES
src/include/ap_mmn.h
src/include/hsregex.h
src/include/http_core.h
src/main/http_core.c
src/main/http_protocol.c
src/modules/standard/mod_digest.c
src/os/netware/ApacheCore.imp
src/support/httpd.exp

index 6e15c7b000bb61858b7873d187a7b562a8d18446..1ce59d6c4eb9e805adaf51d59ca12695579f9a20 100644 (file)
@@ -447,3 +447,4 @@ EXPORTS
         ap_getline @439
         ap_get_chunk_size @440
         ap_escape_logitem @441
+        ap_auth_nonce @442
index da80ae25c996ec0d677eace1ed1728029b6b05df..5cf59f25f7033cff4639664586ac9e2e0329b638 100644 (file)
@@ -430,3 +430,4 @@ EXPORTS
        ap_escape_logitem @441
        ap_popenf_ex @442
        ap_psocket_ex @443
+       ap_auth_nonce @444
index f69bacae0994b299b385fc4bf4e0958dec66b515..16c524714d3a3e9dcc11b9f3089d1a3f19e3dc6c 100644 (file)
@@ -1,5 +1,11 @@
 Changes with Apache 1.3.31
 
+  *) SECURITY: CAN-2003-0987 (cve.mitre.org)
+     Verification as to whether the nonce returned in the client response 
+     is one we issued ourselves by means of a AuthNonce secret exposed as an 
+     md5(). See mod_digest documentation for more details. The experimental
+     mod_auth_digest.c does not have this issue.  [Dirk-Willem van Gulik]
+
 Changes with Apache 1.3.30
 
   *) Fix memory corruption problem with ap_custom_response() function.
index 684468a2531962e067870f2c9bd75a16fb5f691d..75d3d5c398bcdc37e354f9e7f201b44ba4b30dfa 100644 (file)
  *                        ap_popenf_ex() and ap_psocket_ex().
  * 19990320.15          - ap_is_recursion_limit_exceeded()
  * 19990320.16          - ap_escape_errorlog_item()
+ * 19990320.17          - ap_auth_nonce() and ap_auth_nonce added
+ *                        in core_dir_config.
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503133UL /* "AP13" */
index 673884b6f1e8bdb04ce28672517afe9c698a321a..1d76e5b41d3433a14210ab528e4fb1b79d445209 100644 (file)
@@ -16,8 +16,7 @@ extern "C" {
 #endif
 #endif
 
-#undef ap_private_extern
-#if defined(MAC_OS) || defined(MAC_OS_X_SERVER) || (defined(DARWIN) && defined(__DYNAMIC__))
+#if defined(MAC_OS) || defined(MAC_OS_X_SERVER)
 #define ap_private_extern __private_extern__
 #else
 #define ap_private_extern
index 5e20bf7014d18b54bce1e5fd67904124d72106f3..322b3d94cd02f45ccca7643f7dafb7f49e785302 100644 (file)
@@ -119,6 +119,7 @@ typedef struct {
      
 API_EXPORT(const char *) ap_auth_type (request_rec *);
 API_EXPORT(const char *) ap_auth_name (request_rec *);     
+API_EXPORT(const char *) ap_auth_nonce (request_rec *);
 API_EXPORT(int) ap_satisfies (request_rec *r);
 API_EXPORT(const array_header *) ap_requires (request_rec *);    
 
@@ -314,6 +315,9 @@ typedef struct {
      */
     ap_flag_e cgi_command_args;
 
+    /* Digest auth. */
+    char *ap_auth_nonce;
+
 } core_dir_config;
 
 /* Per-server core configuration */
index ddb090d6d302a88c025e6f1ba0cabdb45def9a7a..377a5f9ebc97da67dfac301f28ed5fb3d2a1beae 100644 (file)
@@ -202,6 +202,9 @@ static void *merge_core_dir_configs(pool *a, void *basev, void *newv)
     if (new->ap_auth_name) {
         conf->ap_auth_name = new->ap_auth_name;
     }
+    if (new->ap_auth_nonce) {
+        conf->ap_auth_nonce = new->ap_auth_nonce;
+    }
     if (new->ap_requires) {
         conf->ap_requires = new->ap_requires;
     }
@@ -543,6 +546,32 @@ API_EXPORT(const char *) ap_auth_name(request_rec *r)
     return conf->ap_auth_name;
 }
 
+API_EXPORT(const char *) ap_auth_nonce(request_rec *r)
+{
+    core_dir_config *conf;
+    conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
+                                                   &core_module);
+    if (conf->ap_auth_nonce)
+       return conf->ap_auth_nonce;
+
+    /* Ideally we'd want to mix in some per-directory style
+     * information; as we are likely to want to detect replay
+     * across those boundaries and some randomness. But that
+     * is harder due to the adhoc nature of .htaccess memory
+     * structures, restarts and forks.
+     *
+     * But then again - you should use AuthDigestRealmSeed in your config
+     * file if you care. So the adhoc value should do.
+     */
+    return ap_psprintf(r->pool,"%lu%lu%lu%lu%lu%s",
+           *(unsigned long *)&((r->connection->local_addr).sin_addr ),
+           *(unsigned long *)ap_user_name,
+           *(unsigned long *)ap_listeners,
+           *(unsigned long *)ap_server_argv0,
+           *(unsigned long *)ap_pid_fname,
+           "WHAT_THE_HECK_GOES_HERE?");
+}
+
 API_EXPORT(const char *) ap_default_type(request_rec *r)
 {
     core_dir_config *conf;
@@ -2811,6 +2840,28 @@ static const char *set_authname(cmd_parms *cmd, void *mconfig, char *word1)
     return NULL;
 }
 
+/*
+ * Load an authorisation nonce into our location configuration, and
+ * force it to be in the 0-9/A-Z realm.
+ */
+static const char *set_authnonce (cmd_parms *cmd, void *mconfig, char *word1)
+{
+    core_dir_config *aconfig = (core_dir_config *)mconfig;
+    int i;
+
+    aconfig->ap_auth_nonce = ap_escape_quotes(cmd->pool, word1);
+
+    if (strlen(aconfig->ap_auth_nonce) > 510)
+       return "AuthDigestRealmSeed length limited to 510 chars for browser compatibility";
+
+    for(i=0;i<strlen(aconfig->ap_auth_nonce );i++)
+       if (!ap_isalnum(aconfig->ap_auth_nonce [i]))
+         return "AuthDigestRealmSeed limited to 0-9 and A-Z range for browser compatibility";
+
+    return NULL;
+}
+
+
 #ifdef _OSD_POSIX /* BS2000 Logon Passwd file */
 static const char *set_bs2000_account(cmd_parms *cmd, void *dummy, char *name)
 {
@@ -3425,6 +3476,9 @@ static const command_rec core_cmds[] = {
   "An HTTP authorization type (e.g., \"Basic\")" },
 { "AuthName", set_authname, NULL, OR_AUTHCFG, TAKE1,
   "The authentication realm (e.g. \"Members Only\")" },
+{ "AuthDigestRealmSeed", set_authnonce, NULL, OR_AUTHCFG, TAKE1,
+  "An authentication token which should be different for each logical realm. "\
+  "A random value or the servers IP may be a good choise.\n" },
 { "Require", require, NULL, OR_AUTHCFG, RAW_ARGS,
   "Selects which authenticated users or groups may access a protected space" },
 { "Satisfy", satisfy, NULL, OR_AUTHCFG, TAKE1,
index c516f73918c7256becfc6513914d113d438706fd..a1dab39b767d9386ff206c0d204e0cdb130517d1 100644 (file)
@@ -33,6 +33,7 @@
 #include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
 #include <stdarg.h>
 #include "http_conf_globals.h"
+#include "util_md5.h"           /* For digestAuth */
 
 #define SET_BYTES_SENT(r) \
   do { if (r->sent_bodyct) \
@@ -1348,11 +1349,25 @@ API_EXPORT(void) ap_note_basic_auth_failure(request_rec *r)
 
 API_EXPORT(void) ap_note_digest_auth_failure(request_rec *r)
 {
+    /* We need to create a nonce which:
+     * a) changes all the time (see r->request_time)
+     *    below and
+     * b) of which we can verify that it is our own
+     *    fairly easily when it comes to veryfing
+     *    the digest coming back in the response.
+     * c) and which as a whole should not
+     *    be unlikely to be in use anywhere else.
+     */
+    char * nonce_prefix = ap_md5(r->pool,
+           (unsigned char *)
+           ap_psprintf(r->pool, "%s%lu",
+                       ap_auth_nonce(r), r->request_time));
+
     ap_table_setn(r->err_headers_out,
            r->proxyreq == STD_PROXY ? "Proxy-Authenticate"
                  : "WWW-Authenticate",
-           ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%lu\"",
-               ap_auth_name(r), r->request_time));
+           ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%s%lu\"",
+               ap_auth_name(r), nonce_prefix, r->request_time));
 }
 
 API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw)
index 4551e75f6637ca59b39fd6dc6d55804b222daa27..49070e1160fc992f9adb08795285f4d0e593174b 100644 (file)
@@ -273,6 +273,23 @@ static int get_digest_rec(request_rec *r, digest_header_rec * response)
 
 /* The actual MD5 code... whee */
 
+/* Check that a given nonce is actually one which was
+ * issued by this server in the right context.
+ */
+static int check_nonce(pool *p, const char *prefix, const char *nonce) {
+    char *timestamp = (char *)nonce + 2 * MD5_DIGESTSIZE;
+    char *md5;
+
+    if (strlen(nonce) < MD5_DIGESTSIZE)
+       return AUTH_REQUIRED;
+
+    md5 = ap_md5(p, (unsigned char *)ap_pstrcat(p, prefix, timestamp, NULL));
+
+    return strncmp(md5, nonce, 2 * MD5_DIGESTSIZE);
+}
+
+/* Check the digest itself.
+ */
 static char *find_digest(request_rec *r, digest_header_rec * h, char *a1)
 {
     return ap_md5(r->pool,
@@ -313,6 +330,15 @@ static int authenticate_digest_user(request_rec *r)
     if (!sec->pwfile)
        return DECLINED;
 
+    /* Check that the nonce was one we actually issued. */
+    if (check_nonce(r->pool, ap_auth_nonce(r), response->nonce)) {
+        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+            "Client is using a nonce which was not issued by "
+            "this server for this context: %s", r->uri);
+        ap_note_digest_auth_failure(r);
+        return AUTH_REQUIRED;
+    }
+
     if (!(a1 = get_hash(r, c->user, sec->pwfile))) {
        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
                    "user %s not found: %s", c->user, r->uri);
index 2055ccdf67f4e9988c1788821f7a456c59bb524c..263de68f6089cd0b07662ad49a6f40df01840bc2 100644 (file)
@@ -16,6 +16,7 @@
  ap_array_cat,
  ap_auth_name,
  ap_auth_type,
+ ap_auth_nonce,
  ap_basic_http_header,
  ap_bclose,
  ap_bcreate,
index 8ea7057c4ff82b8c150ed456dd0fc86f2ffcc6f5..c2173890c5247e7e1114b078813bd69d902c6399 100644 (file)
@@ -22,6 +22,7 @@ ap_append_arrays
 ap_array_cat
 ap_array_pstrcat
 ap_auth_name
+ap_auth_nonce
 ap_auth_type
 ap_base64encode
 ap_base64encode_binary