Return-Path: Delivered-To: apmail-httpd-dev-archive@www.apache.org Received: (qmail 51631 invoked from network); 18 Dec 2003 21:38:38 -0000 Received: from daedalus.apache.org (HELO mail.apache.org) (208.185.179.12) by minotaur-2.apache.org with SMTP; 18 Dec 2003 21:38:38 -0000 Received: (qmail 77366 invoked by uid 500); 18 Dec 2003 21:38:20 -0000 Delivered-To: apmail-httpd-dev-archive@httpd.apache.org Received: (qmail 77332 invoked by uid 500); 18 Dec 2003 21:38:20 -0000 Mailing-List: contact dev-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: dev@httpd.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list dev@httpd.apache.org Received: (qmail 77318 invoked from network); 18 Dec 2003 21:38:20 -0000 Received: from unknown (HELO skutsje.san.webweaving.org) (209.132.96.45) by daedalus.apache.org with SMTP; 18 Dec 2003 21:38:20 -0000 Received: from skutsje.san.webweaving.org (localhost [127.0.0.1]) by skutsje.san.webweaving.org (8.12.9/8.12.9) with ESMTP id hBILZfEJ022483 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Thu, 18 Dec 2003 13:35:41 -0800 (PST) (envelope-from dirkx@webweaving.org) Received: from localhost (dirkx@localhost) by skutsje.san.webweaving.org (8.12.9/8.12.9/Submit) with ESMTP id hBILZfGs022478 for ; Thu, 18 Dec 2003 13:35:41 -0800 (PST) (envelope-from dirkx@webweaving.org) X-Authentication-Warning: skutsje.san.webweaving.org: dirkx owned process doing -bs Date: Thu, 18 Dec 2003 13:35:41 -0800 (PST) From: Dirk-Willem van Gulik X-X-Sender: dirkx@skutsje.san.webweaving.org To: dev@httpd.apache.org Subject: [patch] - digest nonce including MM bump, doc and changes. Message-ID: <20031218132438.K21394@skutsje.san.webweaving.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=ISO-8859-1 Content-Transfer-Encoding: 8BIT X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: minotaur-2.apache.org 1.6.2 0/1000/N More complete patch, thanks for the feedback. Other options include -> kill mod_digest.c and/or -> move mod_auth_digest.c from exp. into standard as this fix requires a MM bump _or_ so much rewriting that it may be easier to spend some cycles on mod_auth_digest.c. Dw Index: src/ApacheCore.def =================================================================== RCS file: /home/cvs/apache-1.3/src/ApacheCore.def,v retrieving revision 1.35 diff -u -r1.35 ApacheCore.def --- src/ApacheCore.def 18 Jun 2002 04:19:46 -0000 1.35 +++ src/ApacheCore.def 18 Dec 2003 21:25:49 -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 -r1.13 ApacheCoreOS2.def --- src/ApacheCoreOS2.def 22 May 2003 09:45:28 -0000 1.13 +++ src/ApacheCoreOS2.def 18 Dec 2003 21:25:50 -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.1914 diff -u -r1.1914 CHANGES --- src/CHANGES 14 Dec 2003 18:16:49 -0000 1.1914 +++ src/CHANGES 18 Dec 2003 21:25:56 -0000 @@ -1,5 +1,11 @@ Changes with Apache 1.3.30 + *) SECURITY - verification as to wether 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] + *) SECURITY [CAN-2003-0020]: Escape arbitrary data before writing into the errorlog. [Andr� Malo] Index: src/include/ap_mmn.h =================================================================== RCS file: /home/cvs/apache-1.3/src/include/ap_mmn.h,v retrieving revision 1.65 diff -u -r1.65 ap_mmn.h --- src/include/ap_mmn.h 14 Dec 2003 18:16:49 -0000 1.65 +++ src/include/ap_mmn.h 18 Dec 2003 21:25:56 -0000 @@ -244,6 +244,8 @@ * ap_popenf_ex() and ap_psocket_ex(). * 19990320.15 - ap_is_recursion_limit_exceeded() * 19990320.16 - ap_escape_errorlog_item() + * 20031212 1.3.30-dev - ap_auth_nonce() and auth_nonce added + * in the request_rec. */ #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.71 diff -u -r1.71 http_core.h --- src/include/http_core.h 7 Jul 2003 00:34:09 -0000 1.71 +++ src/include/http_core.h 18 Dec 2003 21:25:56 -0000 @@ -162,6 +162,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 *); @@ -244,6 +245,7 @@ int satisfy; char *ap_auth_type; char *ap_auth_name; + char *ap_auth_nonce; /* digest auth */ array_header *ap_requires; /* Custom response config. These can contain text or a URL to redirect to. Index: src/main/http_core.c =================================================================== RCS file: /home/cvs/apache-1.3/src/main/http_core.c,v retrieving revision 1.327 diff -u -r1.327 http_core.c --- src/main/http_core.c 17 Nov 2003 17:14:53 -0000 1.327 +++ src/main/http_core.c 18 Dec 2003 21:25:58 -0000 @@ -236,6 +236,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; } @@ -577,6 +580,29 @@ 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 ), + ap_user_name, ap_listeners, ap_server_argv0, ap_pid_fname + ); +} + API_EXPORT(const char *) ap_default_type(request_rec *r) { core_dir_config *conf; @@ -2797,6 +2823,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;iap_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) { @@ -3411,6 +3459,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.330 diff -u -r1.330 http_protocol.c --- src/main/http_protocol.c 3 Feb 2003 17:13:22 -0000 1.330 +++ src/main/http_protocol.c 18 Dec 2003 21:26:00 -0000 @@ -76,6 +76,7 @@ #include "util_date.h" /* For parseHTTPdate and BAD_DATE */ #include #include "http_conf_globals.h" +#include "util_md5.h" /* For digestAuth */ #define SET_BYTES_SENT(r) \ do { if (r->sent_bodyct) \ @@ -1391,11 +1392,24 @@ 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, + 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.52 diff -u -r1.52 mod_digest.c --- src/modules/standard/mod_digest.c 3 Feb 2003 17:13:27 -0000 1.52 +++ src/modules/standard/mod_digest.c 18 Dec 2003 21:26:00 -0000 @@ -316,6 +316,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, 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, 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, @@ -339,7 +356,6 @@ /* Determine user ID, and check if it really is that user, for HTTP * basic authentication... */ - static int authenticate_digest_user(request_rec *r) { digest_config_rec *sec = @@ -355,7 +371,16 @@ 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: 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 18 Dec 2003 21:26:51 -0000 @@ -48,17 +48,28 @@

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.

+ "AuthUserFile". + +

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 AuthNonce. +

+

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. +

+

The experimental mod_auth_digest + module offers a number of additinal protections against replay. +

+ +

Everything else should remain the same.

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 Opera 4.0, - MS Internet - Explorer 5.0 and Amaya. - 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.

+ (December 2003), most major browsers support digest authentication. +

See also mod_auth_digest, which is an updated version of this module, in order to determine 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.257 diff -u -r1.257 core.html.en --- htdocs/manual/mod/core.html.en 3 Dec 2003 10:35:24 -0000 1.257 +++ htdocs/manual/mod/core.html.en 18 Dec 2003 21:36:14 -0000 @@ -37,6 +37,8 @@

  • AuthName
  • +
  • AuthNonce
  • +
  • AuthType
  • BindAddress
  • @@ -498,6 +500,7 @@ href="mod_auth_dbm.html#authdbmuserfile">AuthDBMUserFile, AuthGroupFile, AuthName, AuthNonce, AuthType, AuthUserFile, Require, etc.). @@ -593,6 +596,42 @@ Access Control


    +

    AuthNonce + directive

    + + Syntax: AuthNonce + secret-real-string
    + Context: directory, + .htaccess
    + Override: AuthConfig
    + Status: core + +

    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. +

    +

    It only applies to mod_digest.html, + the experimental mod_auth_digest.html + implements its own (more advanced and also time sensitive) replay protection. +

    + + It must be accompanied by AuthType of + type Digest, one or more + Require directives, and directives such + as AuthUserFile and AuthGroupFile to + work.

    + +

    See also: Authentication, Authorization, and + Access Control

    +
    +

    AuthType directive

    @@ -616,6 +655,9 @@ as AuthUserFile and AuthGroupFile to work.

    + +

    When AuthDigest is used an AuthNonce + should also be set.

    See also: Authentication, Authorization, and