From: Jim Jagielski Date: Thu, 15 Apr 2004 15:51:52 +0000 (+0000) Subject: Add in suggested patch for AuthDigestRealmSeed issue X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9e17735920f74367951350985acaf304e01ea65a;p=thirdparty%2Fapache%2Fhttpd.git Add in suggested patch for AuthDigestRealmSeed issue git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@103393 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/ApacheCore.def b/src/ApacheCore.def index 6e15c7b000b..1ce59d6c4eb 100644 --- a/src/ApacheCore.def +++ b/src/ApacheCore.def @@ -447,3 +447,4 @@ EXPORTS ap_getline @439 ap_get_chunk_size @440 ap_escape_logitem @441 + ap_auth_nonce @442 diff --git a/src/ApacheCoreOS2.def b/src/ApacheCoreOS2.def index da80ae25c99..5cf59f25f70 100644 --- a/src/ApacheCoreOS2.def +++ b/src/ApacheCoreOS2.def @@ -430,3 +430,4 @@ EXPORTS ap_escape_logitem @441 ap_popenf_ex @442 ap_psocket_ex @443 + ap_auth_nonce @444 diff --git a/src/CHANGES b/src/CHANGES index f69bacae099..16c524714d3 100644 --- a/src/CHANGES +++ b/src/CHANGES @@ -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. diff --git a/src/include/ap_mmn.h b/src/include/ap_mmn.h index 684468a2531..75d3d5c398b 100644 --- a/src/include/ap_mmn.h +++ b/src/include/ap_mmn.h @@ -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" */ diff --git a/src/include/hsregex.h b/src/include/hsregex.h index 673884b6f1e..1d76e5b41d3 100644 --- a/src/include/hsregex.h +++ b/src/include/hsregex.h @@ -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 diff --git a/src/include/http_core.h b/src/include/http_core.h index 5e20bf7014d..322b3d94cd0 100644 --- a/src/include/http_core.h +++ b/src/include/http_core.h @@ -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 */ diff --git a/src/main/http_core.c b/src/main/http_core.c index ddb090d6d30..377a5f9ebc9 100644 --- a/src/main/http_core.c +++ b/src/main/http_core.c @@ -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;iap_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, diff --git a/src/main/http_protocol.c b/src/main/http_protocol.c index c516f73918c..a1dab39b767 100644 --- a/src/main/http_protocol.c +++ b/src/main/http_protocol.c @@ -33,6 +33,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) \ @@ -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) diff --git a/src/modules/standard/mod_digest.c b/src/modules/standard/mod_digest.c index 4551e75f663..49070e1160f 100644 --- a/src/modules/standard/mod_digest.c +++ b/src/modules/standard/mod_digest.c @@ -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); diff --git a/src/os/netware/ApacheCore.imp b/src/os/netware/ApacheCore.imp index 2055ccdf67f..263de68f608 100644 --- a/src/os/netware/ApacheCore.imp +++ b/src/os/netware/ApacheCore.imp @@ -16,6 +16,7 @@ ap_array_cat, ap_auth_name, ap_auth_type, + ap_auth_nonce, ap_basic_http_header, ap_bclose, ap_bcreate, diff --git a/src/support/httpd.exp b/src/support/httpd.exp index 8ea7057c4ff..c2173890c52 100644 --- a/src/support/httpd.exp +++ b/src/support/httpd.exp @@ -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