Skip to content

Commit c3e3fd3

Browse files
notrojclaude
andcommitted
mod_auth_digest: Drop RFC 2069 and configurable qop support.
(RFC 2617, which replaced 2069, is now 26 years old) * modules/aaa/mod_auth_digest.c (digest_config_rec): Remove qop_list field. (create_digest_dir_config): Remove qop_list initialization. (set_qop): Deprecate AuthDigestQop, only "auth" is supported. (note_digest_auth_failure): Always send qop="auth". (check_nc): Remove handling for qop=none. (old_digest): Remove function. (authenticate_digest_user): Reject requests with missing or non-"auth" qop value rather than falling back to RFC 2069. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8e210c2 commit c3e3fd3

1 file changed

Lines changed: 14 additions & 99 deletions

File tree

modules/aaa/mod_auth_digest.c

Lines changed: 14 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@
8585
typedef struct digest_config_struct {
8686
const char *dir_name;
8787
authn_provider_list *providers;
88-
apr_array_header_t *qop_list;
89-
apr_sha1_ctx_t nonce_ctx;
9088
apr_time_t nonce_lifetime;
9189
int check_nc;
9290
const char *algorithm;
@@ -472,7 +470,6 @@ static void *create_digest_dir_config(apr_pool_t *p, char *dir)
472470

473471
conf = (digest_config_rec *) apr_pcalloc(p, sizeof(digest_config_rec));
474472
if (conf) {
475-
conf->qop_list = apr_array_make(p, 2, sizeof(char *));
476473
conf->nonce_lifetime = DFLT_NONCE_LIFE;
477474
conf->dir_name = apr_pstrdup(p, dir);
478475
conf->algorithm = DFLT_ALGORITHM;
@@ -558,22 +555,9 @@ static const char *add_authn_provider(cmd_parms *cmd, void *config,
558555

559556
static const char *set_qop(cmd_parms *cmd, void *config, const char *op)
560557
{
561-
digest_config_rec *conf = (digest_config_rec *) config;
562-
563-
if (!ap_cstr_casecmp(op, "none")) {
564-
apr_array_clear(conf->qop_list);
565-
*(const char **)apr_array_push(conf->qop_list) = "none";
566-
return NULL;
567-
}
568-
569-
if (!ap_cstr_casecmp(op, "auth-int")) {
570-
return "AuthDigestQop auth-int is not implemented";
558+
if (ap_cstr_casecmp(op, "auth")) {
559+
return "AuthDigestQop is deprecated: only 'auth' is supported";
571560
}
572-
else if (ap_cstr_casecmp(op, "auth")) {
573-
return apr_pstrcat(cmd->pool, "Unrecognized qop: ", op, NULL);
574-
}
575-
576-
*(const char **)apr_array_push(conf->qop_list) = op;
577561

578562
return NULL;
579563
}
@@ -1179,18 +1163,7 @@ static void note_digest_auth_failure(request_rec *r,
11791163
const char *qop, *opaque, *opaque_param, *domain, *nonce;
11801164

11811165
/* Setup qop */
1182-
if (apr_is_empty_array(conf->qop_list)) {
1183-
qop = ", qop=\"auth\"";
1184-
}
1185-
else if (!ap_cstr_casecmp(*(const char **)(conf->qop_list->elts), "none")) {
1186-
qop = "";
1187-
}
1188-
else {
1189-
qop = apr_pstrcat(r->pool, ", qop=\"",
1190-
apr_array_pstrcat(r->pool, conf->qop_list, ','),
1191-
"\"",
1192-
NULL);
1193-
}
1166+
qop = ", qop=\"auth\"";
11941167

11951168
/* Setup opaque */
11961169

@@ -1380,19 +1353,6 @@ static int check_nc(const request_rec *r, const digest_header_rec *resp,
13801353
return OK;
13811354
}
13821355

1383-
if (!apr_is_empty_array(conf->qop_list) &&
1384-
!ap_cstr_casecmp(*(const char **)(conf->qop_list->elts), "none")) {
1385-
/* qop is none, client must not send a nonce count */
1386-
if (snc != NULL) {
1387-
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01772)
1388-
"invalid nc %s received - no nonce count allowed when qop=none",
1389-
snc);
1390-
return !OK;
1391-
}
1392-
/* qop is none, cannot check nonce count */
1393-
return OK;
1394-
}
1395-
13961356
nc = strtol(snc, &endptr, 16);
13971357
if (endptr < (snc+strlen(snc)) && !apr_isspace(*endptr)) {
13981358
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01773)
@@ -1473,19 +1433,6 @@ static int check_nonce(request_rec *r, digest_header_rec *resp,
14731433

14741434
/* The actual MD5 code... whee */
14751435

1476-
/* RFC-2069 */
1477-
static const char *old_digest(const request_rec *r,
1478-
const digest_header_rec *resp)
1479-
{
1480-
const char *ha2;
1481-
1482-
ha2 = ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, resp->method, ":",
1483-
resp->uri, NULL));
1484-
return ap_md5(r->pool,
1485-
(unsigned char *)apr_pstrcat(r->pool, resp->ha1, ":",
1486-
resp->nonce, ":", ha2, NULL));
1487-
}
1488-
14891436
/* RFC-2617 */
14901437
static const char *new_digest(const request_rec *r,
14911438
digest_header_rec *resp)
@@ -1758,39 +1705,18 @@ static int authenticate_digest_user(request_rec *r)
17581705
return HTTP_INTERNAL_SERVER_ERROR;
17591706
}
17601707

1761-
if (resp->message_qop == NULL) {
1762-
/* old (rfc-2069) style digest */
1763-
if (!ap_memeq_timingsafe(old_digest(r, resp), resp->digest, MD5_DIGEST_LEN)) {
1764-
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01792)
1765-
"user %s: password mismatch: %s", r->user,
1766-
r->uri);
1767-
note_digest_auth_failure(r, conf, resp, 0);
1768-
return HTTP_UNAUTHORIZED;
1769-
}
1708+
if (resp->message_qop == NULL
1709+
|| ap_cstr_casecmp(resp->message_qop, "auth")) {
1710+
/* RFC 2069-style Digest is no longer supported. */
1711+
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10560)
1712+
"invalid or missing qop value '%s', RFC 2069 is "
1713+
"no longer supported: %s", resp->message_qop, r->uri);
1714+
note_digest_auth_failure(r, conf, resp, 0);
1715+
return HTTP_UNAUTHORIZED;
17701716
}
17711717
else {
1772-
const char *exp_digest;
1773-
int match = 0, idx;
1774-
const char **tmp = (const char **)(conf->qop_list->elts);
1775-
for (idx = 0; idx < conf->qop_list->nelts; idx++) {
1776-
if (!ap_cstr_casecmp(*tmp, resp->message_qop)) {
1777-
match = 1;
1778-
break;
1779-
}
1780-
++tmp;
1781-
}
1782-
1783-
if (!match
1784-
&& !(apr_is_empty_array(conf->qop_list)
1785-
&& !ap_cstr_casecmp(resp->message_qop, "auth"))) {
1786-
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01793)
1787-
"invalid qop `%s' received: %s",
1788-
resp->message_qop, r->uri);
1789-
note_digest_auth_failure(r, conf, resp, 0);
1790-
return HTTP_UNAUTHORIZED;
1791-
}
1792-
1793-
exp_digest = new_digest(r, resp);
1718+
/* RFC 2617 (or 7616)-style Digest hash calculation. */
1719+
const char *exp_digest = new_digest(r, resp);
17941720
if (!exp_digest) {
17951721
/* we failed to allocate a client struct */
17961722
return HTTP_INTERNAL_SERVER_ERROR;
@@ -1836,9 +1762,6 @@ static int add_auth_info(request_rec *r)
18361762
return OK;
18371763
}
18381764

1839-
/* 2069-style entity-digest is not supported (it's too hard, and
1840-
* there are no clients which support 2069 but not 2617). */
1841-
18421765
/* setup nextnonce
18431766
*/
18441767
if (conf->nonce_lifetime > 0) {
@@ -1861,15 +1784,7 @@ static int add_auth_info(request_rec *r)
18611784
/* else nonce never expires, hence no nextnonce */
18621785

18631786

1864-
/* do rfc-2069 digest
1865-
*/
1866-
if (!apr_is_empty_array(conf->qop_list) &&
1867-
!ap_cstr_casecmp(*(const char **)(conf->qop_list->elts), "none")
1868-
&& resp->message_qop == NULL) {
1869-
/* use only RFC-2069 format */
1870-
ai = nextnonce;
1871-
}
1872-
else {
1787+
{
18731788
const char *resp_dig, *ha1, *a2, *ha2;
18741789

18751790
/* calculate rspauth attribute

0 commit comments

Comments
 (0)