httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jim Jagielski <...@jaguNET.com>
Subject [PATCH 1.3.30/31] Re: 1.3.3x digest/nonce issue
Date Wed, 14 Apr 2004 16:15:32 GMT
On Apr 13, 2004, at 11:13 AM, Jim Jagielski wrote:

> There is a known bug/issue in the current implementation
> of mod_digest regarding the nonce. I am looking to
> have this plugged for our next 1.3 release.
>
> There are 2 suggested patches, which I will post under
> separate Emails. I will also adjust STATUS to reflect
> these 2 potential patches.
>
> PLEASE look these over! I would still like to get a
> 1.3 release out soon. My expectation is that we
> will toss 1.3.30...
>

Suggested patch:

Index: src/ApacheCore.def
===================================================================
RCS file: /home/cvs/apache-1.3/src/ApacheCore.def,v
retrieving revision 1.35
diff -u -u -r1.35 ApacheCore.def
--- src/ApacheCore.def	18 Jun 2002 04:19:46 -0000	1.35
+++ src/ApacheCore.def	14 Apr 2004 15:57:44 -0000
@@ -447,3 +447,4 @@
          ap_getline @439
          ap_get_chunk_size @440
          ap_escape_logitem @441
+        ap_auth_nonce @442
Index: src/ApacheCoreOS2.def
===================================================================
RCS file: /home/cvs/apache-1.3/src/ApacheCoreOS2.def,v
retrieving revision 1.13
diff -u -u -r1.13 ApacheCoreOS2.def
--- src/ApacheCoreOS2.def	22 May 2003 09:45:28 -0000	1.13
+++ src/ApacheCoreOS2.def	14 Apr 2004 15:57:45 -0000
@@ -430,3 +430,4 @@
  	ap_escape_logitem @441
  	ap_popenf_ex @442
  	ap_psocket_ex @443
+       ap_auth_nonce @444
Index: src/CHANGES
===================================================================
RCS file: /home/cvs/apache-1.3/src/CHANGES,v
retrieving revision 1.1935
diff -u -u -r1.1935 CHANGES
--- src/CHANGES	9 Apr 2004 17:01:50 -0000	1.1935
+++ src/CHANGES	14 Apr 2004 15:58:14 -0000
@@ -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: src/include/ap_mmn.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/ap_mmn.h,v
retrieving revision 1.67
diff -u -u -r1.67 ap_mmn.h
--- src/include/ap_mmn.h	16 Feb 2004 22:25:08 -0000	1.67
+++ src/include/ap_mmn.h	14 Apr 2004 15:58:23 -0000
@@ -201,6 +201,8 @@
   *                        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: src/include/http_core.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/http_core.h,v
retrieving revision 1.74
diff -u -u -r1.74 http_core.h
--- src/include/http_core.h	29 Mar 2004 18:35:29 -0000	1.74
+++ src/include/http_core.h	14 Apr 2004 15:58:24 -0000
@@ -119,6 +119,7 @@

  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 *);

@@ -313,6 +314,9 @@
       * direct command line parameters or argv elements?
       */
      ap_flag_e cgi_command_args;
+
+    /* Digest auth. */
+    char *ap_auth_nonce;

  } core_dir_config;

Index: src/main/http_core.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_core.c,v
retrieving revision 1.332
diff -u -u -r1.332 http_core.c
--- src/main/http_core.c	29 Mar 2004 18:35:29 -0000	1.332
+++ src/main/http_core.c	14 Apr 2004 15:58:42 -0000
@@ -202,6 +202,9 @@
      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 @@
      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 AuthNonce 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 @@
      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 "AuthNonce 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 "AuthNonce 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 @@
    "An HTTP authorization type (e.g., \"Basic\")" },
  { "AuthName", set_authname, NULL, OR_AUTHCFG, TAKE1,
    "The authentication realm (e.g. \"Members Only\")" },
+{ "AuthNonce", 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: src/main/http_protocol.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_protocol.c,v
retrieving revision 1.334
diff -u -u -r1.334 http_protocol.c
--- src/main/http_protocol.c	29 Mar 2004 18:23:03 -0000	1.334
+++ src/main/http_protocol.c	14 Apr 2004 15:58:50 -0000
@@ -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_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: src/modules/standard/mod_digest.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_digest.c,v
retrieving revision 1.54
diff -u -u -r1.54 mod_digest.c
--- src/modules/standard/mod_digest.c	20 Feb 2004 20:37:40 -0000	1.54
+++ src/modules/standard/mod_digest.c	14 Apr 2004 15:59:14 -0000
@@ -273,6 +273,23 @@

  /* 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,
@@ -312,6 +329,15 @@

      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,
Index: src/support/httpd.exp
===================================================================
RCS file: /home/cvs/apache-1.3/src/support/httpd.exp,v
retrieving revision 1.42
diff -u -u -r1.42 httpd.exp
--- src/support/httpd.exp	28 Jan 2004 21:22:21 -0000	1.42
+++ src/support/httpd.exp	14 Apr 2004 15:59:52 -0000
@@ -22,6 +22,7 @@
  ap_array_cat
  ap_array_pstrcat
  ap_auth_name
+ap_auth_nonce
  ap_auth_type
  ap_base64encode
  ap_base64encode_binary
Index: htdocs/manual/mod/core.html.en
===================================================================
RCS file: /home/cvs/httpd-docs-1.3/htdocs/manual/mod/core.html.en,v
retrieving revision 1.259
diff -u -r1.259 core.html.en
--- htdocs/manual/mod/core.html.en      29 Jan 2004 17:01:53 -0000      
1.259
+++ htdocs/manual/mod/core.html.en      17 Mar 2004 13:52:34 -0000
@@ -37,6 +37,8 @@

        <li><a href="#authname">AuthName</a></li>

+      <li><a href="#AuthNonce">AuthNonce</a></li>
+
        <li><a href="#authtype">AuthType</a></li>

        <li><a href="#bindaddress">BindAddress</a></li>
@@ -500,6 +502,7 @@
        href="mod_auth_dbm.html#authdbmuserfile">AuthDBMUserFile</a>,
        <a href="mod_auth.html#authgroupfile">AuthGroupFile</a>, <a
        href="#authname">AuthName</a>, <a
+      href="#AuthNonce">AuthNonce</a>, <a
        href="#authtype">AuthType</a>, <a
        href="mod_auth.html#authuserfile">AuthUserFile</a>, <a
        href="#require">Require</a>, <em>etc.</em>).</dd>
@@ -595,6 +598,42 @@
      Access Control</a></p>
      <hr />

+    <h2><a id="AuthNonce" name="AuthNonce">AuthNonce
+    directive</a></h2>
+
+    <a href="directive-dict.html#Syntax"
+    rel="Help"><strong>Syntax:</strong></a> AuthNonce
+    <em>secret-real-string</em><br />
+     <a href="directive-dict.html#Context"
+    rel="Help"><strong>Context:</strong></a> directory,
+    .htaccess<br />
+     <a href="directive-dict.html#Override"
+    rel="Help"><strong>Override:</strong></a> AuthConfig<br />
+     <a href="directive-dict.html#Status"
+    rel="Help"><strong>Status:</strong></a> core
+
+    <p>This directive sets a per realm secret nonce prefix
+    which is used to ensure that a captured username, password
+    and realm string during a Digest exchange cannot
+    be replayed at other places.
+    </p>
+    <p>It only applies to <a 
href="mod_digest.html">mod_digest.html</a>,
+    the experimental <a 
href="mod_auth_digest.html">mod_auth_digest.html</a>
+    implements its own (more advanced and also time sensitive) replay 
protection.
+    </p>
+
+    It must be accompanied by <a href="#authtype">AuthType</a> of
+    type Digest, one or more
+    <a href="#require">Require</a> directives, and directives such
+    as <a href="mod_auth.html#authuserfile">AuthUserFile</a> and <a
+    href="mod_auth.html#authgroupfile">AuthGroupFile</a> to
+    work.</p>
+
+    <p><strong>See also:</strong> <a
+    href="../howto/auth.html">Authentication, Authorization, and
+    Access Control</a></p>
+    <hr />
+
      <h2><a id="authtype" name="authtype">AuthType
      directive</a></h2>

@@ -618,6 +657,9 @@
      as <a href="mod_auth.html#authuserfile">AuthUserFile</a> and <a
      href="mod_auth.html#authgroupfile">AuthGroupFile</a> to
      work.</p>
+
+    <p>When AuthDigest is used an <a href="#AuthNonce">AuthNonce</a>
+    should also be set.</p>

      <p><strong>See also:</strong> <a
      href="../howto/auth.html">Authentication, Authorization, and
Index: htdocs/manual/mod/mod_digest.html
===================================================================
RCS file: /home/cvs/httpd-docs-1.3/htdocs/manual/mod/mod_digest.html,v
retrieving revision 1.14
diff -u -r1.14 mod_digest.html
--- htdocs/manual/mod/mod_digest.html   23 Jan 2002 02:51:03 -0000      
1.14
+++ htdocs/manual/mod/mod_digest.html   17 Mar 2004 13:52:34 -0000
@@ -48,17 +48,28 @@
      <p>Using MD5 Digest authentication is very simple. Simply set
      up authentication normally. However, use "AuthType Digest" and
      "AuthDigestFile" instead of the normal "AuthType Basic" and
-    "AuthUserFile". Everything else should remain the same.</p>
+    "AuthUserFile".</p>
+
+    <p>As to make sure that replay is not possible across
+    sections of the site, or across sites (assuming a realm,
+    userid and password are valid in that wider context) a
+    secret nonce prefix can be configured with the
+    core directive <a href="core.html#AuthNonce">AuthNonce</a>.
+    </p>
+    <p>If none if configured a sensible, but not particular
+    secure, default is used. When used in load balancing
+    situations the prefix should be shared across servers.
+    </p>
+    <p>The experimental <a 
href="mod_auth_digest.html">mod_auth_digest</a>
+    module offers a number of additinal protections against replay.
+    </p>
+
+    <p>Everything else should remain the same.</p>

      <p>MD5 authentication provides a more secure password system,
      but only works with supporting browsers. As of this writing
-    (January 2002), the only major browsers which support digest
-    authentication are <a href="http://www.opera.com/">Opera 4.0</a>,
-    <a href="http://www.microsoft.com/windows/ie/">MS Internet
-    Explorer 5.0</a> and <a href="http://www.w3.org/Amaya/">Amaya</a>.
-    Therefore, we do not recommend using this feature on a large
-    Internet site. However, for personal and intra-net use, where
-    browser users can be controlled, it is ideal.</p>
+    (December 2003), most major browsers support digest authentication.
+    </p>

      <p>See also <a href="mod_auth_digest.html">mod_auth_digest</a>,
      which is an updated version of this module, in order to determine


Mime
View raw message