summaryrefslogtreecommitdiff
path: root/daemon/digest.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/digest.c')
-rw-r--r--daemon/digest.c822
1 files changed, 411 insertions, 411 deletions
diff --git a/daemon/digest.c b/daemon/digest.c
index 405a661..099bf31 100644
--- a/daemon/digest.c
+++ b/daemon/digest.c
@@ -12,103 +12,103 @@ static unsigned int g_digest_unique = 0;
typedef struct internal_nonce
{
- unsigned char hash[MD5_LEN];
- time_t tm;
- unsigned int unique;
+ unsigned char hash[MD5_LEN];
+ time_t tm;
+ unsigned int unique;
}
internal_nonce_t;
void digest_makenonce(unsigned char* nonce, unsigned char* secret, unsigned char* old)
{
- internal_nonce_t in;
- md5_ctx_t md5;
-
- ASSERT(nonce && secret);
- ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN);
-
- if(old)
- {
- internal_nonce_t* nold = (internal_nonce_t*)old;
- in.tm = nold->tm;
- in.unique = nold->unique;
- }
- else
- {
- in.tm = time(NULL);
- ha_lock(NULL);
- in.unique = g_digest_unique++;
- ha_unlock(NULL);
- }
-
- md5_init(&md5);
- md5_update(&md5, secret, DIGEST_SECRET_LEN);
- md5_update(&md5, &(in.tm), sizeof(in.tm));
- md5_update(&md5, &(in.unique), sizeof(in.unique));
- md5_final(in.hash, &md5);
-
- memcpy(nonce, &in, DIGEST_NONCE_LEN);
+ internal_nonce_t in;
+ md5_ctx_t md5;
+
+ ASSERT(nonce && secret);
+ ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN);
+
+ if(old)
+ {
+ internal_nonce_t* nold = (internal_nonce_t*)old;
+ in.tm = nold->tm;
+ in.unique = nold->unique;
+ }
+ else
+ {
+ in.tm = time(NULL);
+ ha_lock(NULL);
+ in.unique = g_digest_unique++;
+ ha_unlock(NULL);
+ }
+
+ md5_init(&md5);
+ md5_update(&md5, secret, DIGEST_SECRET_LEN);
+ md5_update(&md5, &(in.tm), sizeof(in.tm));
+ md5_update(&md5, &(in.unique), sizeof(in.unique));
+ md5_final(in.hash, &md5);
+
+ memcpy(nonce, &in, DIGEST_NONCE_LEN);
}
int digest_checknonce(unsigned char* nonce, unsigned char* secret, time_t* tm)
{
- internal_nonce_t in;
+ internal_nonce_t in;
- ASSERT(nonce && secret);
- ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN);
+ ASSERT(nonce && secret);
+ ASSERT(sizeof(internal_nonce_t) == DIGEST_NONCE_LEN);
- digest_makenonce((unsigned char*)&in, secret, nonce);
+ digest_makenonce((unsigned char*)&in, secret, nonce);
- if(memcmp((unsigned char*)&in, nonce, DIGEST_SECRET_LEN) == 0)
- {
- if(tm)
- *tm = in.tm;
+ if(memcmp((unsigned char*)&in, nonce, DIGEST_SECRET_LEN) == 0)
+ {
+ if(tm)
+ *tm = in.tm;
- return HA_OK;
- }
+ return HA_OK;
+ }
- return HA_FALSE;
+ return HA_FALSE;
}
digest_record_t* digest_makerec(unsigned char* nonce, const char* user)
{
- digest_record_t* rec = (digest_record_t*)malloc(sizeof(*rec));
+ digest_record_t* rec = (digest_record_t*)malloc(sizeof(*rec));
- ASSERT(nonce && user);
+ ASSERT(nonce && user);
- if(!rec)
- {
- ha_messagex(LOG_CRIT, "out of memory");
- return NULL;
- }
+ if(!rec)
+ {
+ ha_messagex(NULL, LOG_CRIT, "out of memory");
+ return NULL;
+ }
- memset(rec, 0, sizeof(*rec));
- memcpy(rec->nonce, nonce, DIGEST_NONCE_LEN);
+ memset(rec, 0, sizeof(*rec));
+ memcpy(rec->nonce, nonce, DIGEST_NONCE_LEN);
- md5_string(rec->userhash, user);
- return rec;
+ md5_string(rec->userhash, user);
+ return rec;
}
const char* digest_challenge(ha_buffer_t* buf, const char* nonce_str,
const char* realm, const char* domains, int stale)
{
- ASSERT(buf && realm && nonce_str);
+ ASSERT(buf && realm && nonce_str);
- ha_bufmcat(buf, HA_PREFIX_DIGEST, " realm=\"", realm, "\", nonce=\"",
- nonce_str, "\", qop=\"auth\", algorithm=\"MD5\"", NULL);
+ ha_bufmcat(buf, HA_PREFIX_DIGEST, " realm=\"", realm, "\", nonce=\"",
+ nonce_str, "\", qop=\"auth\", algorithm=\"MD5\"", NULL);
- if(domains)
- {
- ha_bufjoin(buf);
- ha_bufmcat(buf, ", domain=\"", domains, "\"", NULL);
- }
+ if(domains)
+ {
+ ha_bufjoin(buf);
+ ha_bufmcat(buf, ", domain=\"", domains, "\"", NULL);
+ }
- if(stale)
- {
- ha_bufjoin(buf);
- ha_bufcat(buf, ", stale=true");
- }
+ if(stale)
+ {
+ ha_bufjoin(buf);
+ ha_bufcat(buf, ", stale=true");
+ }
- return ha_bufdata(buf);
+ return ha_bufdata(buf);
}
/*
@@ -130,316 +130,396 @@ const char* digest_challenge(ha_buffer_t* buf, const char* nonce_str,
int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec,
unsigned char* nonce)
{
- char next;
- char* key;
- char* value;
-
- ASSERT(header && buf && rec);
-
- header = ha_bufcpy(buf, header);
-
- if(!header)
- return HA_CRITERROR;
-
- memset(rec, 0, sizeof(*rec));
-
- while(header[0])
- {
- /* find key */
- header = (char*)trim_start(header);
- key = header;
+ char next;
+ char* key;
+ char* value;
- while(header[0] && header[0] != '=' && header[0] != ',' &&
- !isspace(header[0]))
- header++;
+ ASSERT(header && buf && rec);
- /* null terminate and move on */
- next = header[0];
- header[0] = '\0';
- header++;
+ header = ha_bufcpy(buf, header);
- if(!next)
- break;
-
- if(isspace(header[0]))
- {
- header = (char*)trim_start(header);
- next = header[0];
- }
+ if(!header)
+ return HA_CRITERROR;
- /* find value */
+ memset(rec, 0, sizeof(*rec));
- if(next == '=')
+ while(header[0])
{
- header = (char*)trim_start(header);
+ /* find key */
+ header = (char*)trim_start(header);
+ key = header;
- if(header[0] == '\"') /* quoted string */
- {
- header++;
- value = header;
-
- while(header[0] && header[0] != '\"')
- header++;
+ while(header[0] && header[0] != '=' && header[0] != ',' &&
+ !isspace(header[0]))
+ header++;
+ /* null terminate and move on */
next = header[0];
- header[0] = 0;
+ header[0] = '\0';
header++;
- }
- else /* token */
- {
- value = header;
+ if(!next)
+ break;
+
+ if(isspace(header[0]))
+ {
+ header = (char*)trim_start(header);
+ next = header[0];
+ }
- while(header[0] && header[0] != ',' && !isspace(header[0]))
- header++;
+ /* find value */
- next = header[0];
- header[0] = 0;
- header++;
- }
-
- if(next != ',')
- {
- while(header[0] && header[0] != ',')
- header++;
-
- if(header[0])
- header++;
- }
-
- if(!strcasecmp(key, "username"))
- rec->username = value;
- else if(!strcasecmp(key, "realm"))
- rec->realm = value;
- else if (!strcasecmp(key, "nonce"))
- rec->nonce = value;
- else if (!strcasecmp(key, "uri"))
- rec->uri = value;
- else if (!strcasecmp(key, "response"))
- rec->digest = value;
- else if (!strcasecmp(key, "algorithm"))
- rec->algorithm = value;
- else if (!strcasecmp(key, "cnonce"))
- rec->cnonce = value;
- else if (!strcasecmp(key, "opaque"))
- rec->opaque = value;
- else if (!strcasecmp(key, "qop"))
- rec->qop = value;
- else if (!strcasecmp(key, "nc"))
- rec->nc = value;
+ if(next == '=')
+ {
+ header = (char*)trim_start(header);
+
+ if(header[0] == '\"') /* quoted string */
+ {
+ header++;
+ value = header;
+
+ while(header[0] && header[0] != '\"')
+ header++;
+
+ next = header[0];
+ header[0] = 0;
+ header++;
+ }
+
+ else /* token */
+ {
+ value = header;
+
+ while(header[0] && header[0] != ',' && !isspace(header[0]))
+ header++;
+
+ next = header[0];
+ header[0] = 0;
+ header++;
+ }
+
+ if(next != ',')
+ {
+ while(header[0] && header[0] != ',')
+ header++;
+
+ if(header[0])
+ header++;
+ }
+
+ if(!strcasecmp(key, "username"))
+ rec->username = value;
+ else if(!strcasecmp(key, "realm"))
+ rec->realm = value;
+ else if (!strcasecmp(key, "nonce"))
+ rec->nonce = value;
+ else if (!strcasecmp(key, "uri"))
+ rec->uri = value;
+ else if (!strcasecmp(key, "response"))
+ rec->digest = value;
+ else if (!strcasecmp(key, "algorithm"))
+ rec->algorithm = value;
+ else if (!strcasecmp(key, "cnonce"))
+ rec->cnonce = value;
+ else if (!strcasecmp(key, "opaque"))
+ rec->opaque = value;
+ else if (!strcasecmp(key, "qop"))
+ rec->qop = value;
+ else if (!strcasecmp(key, "nc"))
+ rec->nc = value;
+ }
}
- }
- if(nonce)
- {
- memset(nonce, 0, DIGEST_NONCE_LEN);
-
- if(rec->nonce)
+ if(nonce)
{
- size_t len = DIGEST_NONCE_LEN;
- void* d = ha_bufdechex(buf, rec->nonce, &len);
+ memset(nonce, 0, DIGEST_NONCE_LEN);
+
+ if(rec->nonce)
+ {
+ size_t len = DIGEST_NONCE_LEN;
+ void* d = ha_bufdechex(buf, rec->nonce, &len);
- if(d && len == DIGEST_NONCE_LEN)
- memcpy(nonce, d, DIGEST_NONCE_LEN);
+ if(d && len == DIGEST_NONCE_LEN)
+ memcpy(nonce, d, DIGEST_NONCE_LEN);
+ }
}
- }
- return HA_OK;
+ return HA_OK;
}
int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t* ctx,
ha_buffer_t* buf, const char* method, const char* uri)
{
- unsigned char hash[MD5_LEN];
- md5_ctx_t md5;
- const char* digest;
- const char* t;
-
- ASSERT(ctx && method && buf && dg && rec);
-
- /* TODO: Many of these should somehow communicate BAD REQ back to the client */
-
- /* Check for digest */
- if(!dg->digest || !dg->digest[0])
- {
- ha_messagex(LOG_WARNING, "digest response missing digest");
- return HA_BADREQ;
- }
-
- /* Username */
- if(!dg->username || !dg->username[0])
- {
- ha_messagex(LOG_WARNING, "digest response missing username");
- return HA_BADREQ;
- }
-
- if(md5_strcmp(rec->userhash, dg->username) != 0)
- {
- ha_messagex(LOG_ERR, "digest response contains invalid username");
- return HA_FALSE;
- }
-
- /* The realm */
- if(!dg->realm)
- {
- ha_messagex(LOG_WARNING, "digest response contains missing realm");
- return HA_BADREQ;
- }
-
- if(strcmp(dg->realm, ctx->realm) != 0)
- {
- ha_messagex(LOG_ERR, "digest response contains invalid realm: %s", dg->realm);
- return HA_FALSE;
- }
+ unsigned char hash[MD5_LEN];
+ md5_ctx_t md5;
+ const char* digest;
+ const char* t;
- /* Components in the new RFC */
- if(dg->qop)
- {
- /*
- * We only support 'auth' qop. We don't have access to the data
- * and wouldn't be able to support anything else.
- */
- if(strcmp(dg->qop, "auth") != 0)
+ ASSERT(ctx && method && buf && dg && rec);
+
+ /* TODO: This stuff should probably go into bd.c */
+
+ /* Check for digest */
+ if(!dg->digest || !dg->digest[0])
{
- ha_messagex(LOG_WARNING, "digest response contains unknown or unsupported qop: '%s'",
- dg->qop ? dg->qop : "");
- return HA_BADREQ;
+ ha_messagex(NULL, LOG_WARNING, "digest response missing digest");
+ return HA_BADREQ;
}
- /* The cnonce */
- if(!dg->cnonce || !dg->cnonce[0])
+ /* Username */
+ if(!dg->username || !dg->username[0])
{
- ha_messagex(LOG_WARNING, "digest response is missing cnonce value");
- return HA_BADREQ;
+ ha_messagex(NULL, LOG_WARNING, "digest response missing username");
+ return HA_BADREQ;
+ }
+
+ if(md5_strcmp(rec->userhash, dg->username) != 0)
+ {
+ ha_messagex(NULL, LOG_ERR, "digest response contains invalid username");
+ return HA_FALSE;
}
- if(!ctx->digest_ignorenc)
+ /* The realm */
+ if(!dg->realm)
{
- /* The nonce count */
- if(!dg->nc || !dg->nc[0])
- {
- ha_messagex(LOG_WARNING, "digest response is missing nc value");
+ ha_messagex(NULL, LOG_WARNING, "digest response contains missing realm");
return HA_BADREQ;
- }
+ }
- /* Validate the nc */
- else
- {
- char* e;
- long nc = strtol(dg->nc, &e, 16);
+ if(strcmp(dg->realm, ctx->realm) != 0)
+ {
+ ha_messagex(NULL, LOG_ERR, "digest response contains invalid realm: %s", dg->realm);
+ return HA_FALSE;
+ }
- if(*e)
+ /* Components in the new RFC */
+ if(dg->qop)
+ {
+ /*
+ * We only support 'auth' qop. We don't have access to the data
+ * and wouldn't be able to support anything else.
+ */
+ if(strcmp(dg->qop, "auth") != 0)
{
- ha_messagex(LOG_ERR, "digest response has invalid nc value: %s", dg->nc);
- return HA_BADREQ;
+ ha_messagex(NULL, LOG_WARNING, "digest response contains unknown or unsupported qop: '%s'",
+ dg->qop ? dg->qop : "");
+ return HA_BADREQ;
}
- /* If we didn't a nc then save it away */
- if(!*e && rec->nc == 0)
- rec->nc = nc;
+ /* The cnonce */
+ if(!dg->cnonce || !dg->cnonce[0])
+ {
+ ha_messagex(NULL, LOG_WARNING, "digest response is missing cnonce value");
+ return HA_BADREQ;
+ }
- if(*e || nc != rec->nc)
+ if(!ctx->digest_ignorenc)
{
- ha_messagex(LOG_WARNING, "digest response has wrong nc value. "
- "possible replay attack: %s", dg->nc);
- return HA_FALSE;
+ /* The nonce count */
+ if(!dg->nc || !dg->nc[0])
+ {
+ ha_messagex(NULL, LOG_WARNING, "digest response is missing nc value");
+ return HA_BADREQ;
+ }
+
+ /* Validate the nc */
+ else
+ {
+ char* e;
+ long nc = strtol(dg->nc, &e, 16);
+
+ if(*e)
+ {
+ ha_messagex(NULL, LOG_ERR, "digest response has invalid nc value: %s", dg->nc);
+ return HA_BADREQ;
+ }
+
+ /* If we didn't a nc then save it away */
+ if(!*e && rec->nc == 0)
+ rec->nc = nc;
+
+ if(*e || nc != rec->nc)
+ {
+ ha_messagex(NULL, LOG_WARNING, "digest response has wrong nc value. "
+ "possible replay attack: %s", dg->nc);
+ return HA_FALSE;
+ }
+ }
}
- }
}
- }
-
- /* The algorithm */
- if(dg->algorithm && strcasecmp(dg->algorithm, "MD5") != 0)
- {
- ha_messagex(LOG_WARNING, "digest response contains unknown or unsupported algorithm: '%s'",
- dg->algorithm ? dg->algorithm : "");
- return HA_BADREQ;
- }
-
- /* Request URI */
- if(!dg->uri)
- {
- ha_messagex(LOG_WARNING, "digest response is missing uri");
- return HA_BADREQ;
- }
-
- if(!ctx->digest_ignoreuri && strcmp(dg->uri, uri) != 0)
- {
- ha_uri_t d_uri;
- ha_uri_t s_uri;
-
- if(ha_uriparse(buf, dg->uri, &d_uri) < 0)
+
+ /* The algorithm */
+ if(dg->algorithm && strcasecmp(dg->algorithm, "MD5") != 0)
{
- if(ha_buferr(buf))
- return HA_CRITERROR;
+ ha_messagex(NULL, LOG_WARNING, "digest response contains unknown or unsupported algorithm: '%s'",
+ dg->algorithm ? dg->algorithm : "");
+ return HA_BADREQ;
+ }
- ha_messagex(LOG_WARNING, "digest response constains invalid uri: %s", dg->uri);
- return HA_BADREQ;
+ /* Request URI */
+ if(!dg->uri)
+ {
+ ha_messagex(NULL, LOG_WARNING, "digest response is missing uri");
+ return HA_BADREQ;
}
- if(ha_uriparse(buf, uri, &s_uri) < 0)
+ if(!ctx->digest_ignoreuri && strcmp(dg->uri, uri) != 0)
{
- if(ha_buferr(buf))
+ ha_uri_t d_uri;
+ ha_uri_t s_uri;
+
+ if(ha_uriparse(buf, dg->uri, &d_uri) < 0)
+ {
+ if(ha_buferr(buf))
+ return HA_CRITERROR;
+
+ ha_messagex(NULL, LOG_WARNING, "digest response constains invalid uri: %s", dg->uri);
+ return HA_BADREQ;
+ }
+
+ if(ha_uriparse(buf, uri, &s_uri) < 0)
+ {
+ if(ha_buferr(buf))
+ return HA_CRITERROR;
+
+ ha_messagex(NULL, LOG_ERR, "server sent us an invalid uri");
+ return HA_BADREQ;
+ }
+
+ if(ha_uricmp(&d_uri, &s_uri) != 0)
+ {
+ ha_messagex(NULL, LOG_ERR, "digest response contains wrong uri: %s "
+ "(should be %s)", dg->uri, uri);
+ return HA_FALSE;
+ }
+ }
+
+ /*
+ * nonce: should have already been validated by the caller who
+ * found this nice rec structure to pass us.
+ *
+ * opaque: We also don't use opaque. The caller should have validated it
+ * if it's used there.
+ */
+
+ /*
+ * Now we validate the digest response
+ */
+
+ /* Encode ha1 */
+ t = ha_bufenchex(buf, rec->ha1, MD5_LEN);
+
+ if(t == NULL)
+ return HA_CRITERROR;
+
+ /* Encode ha2 */
+ md5_init(&md5);
+ md5_update(&md5, method, strlen(method));
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, dg->uri, strlen(dg->uri));
+ md5_final(hash, &md5);
+
+ ha_bufenchex(buf, hash, MD5_LEN);
+
+ if(!ha_bufdata(buf))
return HA_CRITERROR;
- ha_messagex(LOG_ERR, "server sent us an invalid uri");
- return HA_BADREQ;
+
+ /* Old style digest (RFC 2069) */
+ if(!dg->qop)
+ {
+ md5_init(&md5);
+ md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha1 */
+ md5_final(hash, &md5);
+ }
+
+ /* New style 'auth' digest (RFC 2617) */
+ else
+ {
+ md5_init(&md5);
+ md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, dg->nc, strlen(dg->nc)); /* nc */
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, dg->cnonce, strlen(dg->cnonce)); /* cnonce */
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, dg->qop, strlen(dg->qop)); /* qop */
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */
+ md5_final(hash, &md5);
}
- if(ha_uricmp(&d_uri, &s_uri) != 0)
+ /* Encode the digest */
+ digest = ha_bufenchex(buf, hash, MD5_LEN);
+
+ if(digest == NULL)
+ return HA_CRITERROR;
+
+ if(strcasecmp(dg->digest, digest) != 0)
{
- ha_messagex(LOG_ERR, "digest response contains wrong uri: %s "
- "(should be %s)", dg->uri, uri);
- return HA_FALSE;
+ ha_messagex(NULL, LOG_WARNING, "digest authentication failed for user: %s", dg->username);
+ return HA_FALSE;
}
- }
- /*
- * nonce: should have already been validated by the caller who
- * found this nice rec structure to pass us.
- *
- * opaque: We also don't use opaque. The caller should have validated it
- * if it's used there.
- */
+ return HA_OK;
+}
- /*
- * Now we validate the digest response
- */
+const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
+ digest_record_t* rec, unsigned char* next)
+{
+ unsigned char hash[MD5_LEN];
+ md5_ctx_t md5;
+ const char* nextnonce = NULL;
+ const char* t;
- /* Encode ha1 */
- t = ha_bufenchex(buf, rec->ha1, MD5_LEN);
+ ASSERT(buf && dg && rec);
- if(t == NULL)
- return HA_CRITERROR;
+ /* This makes a new buffer */
+ ha_bufcpy(buf, "");
- /* Encode ha2 */
- md5_init(&md5);
- md5_update(&md5, method, strlen(method));
- md5_update(&md5, ":", 1);
- md5_update(&md5, dg->uri, strlen(dg->uri));
- md5_final(hash, &md5);
+ if(next)
+ {
+ nextnonce = ha_bufenc64(buf, next, DIGEST_NONCE_LEN);
- ha_bufenchex(buf, hash, MD5_LEN);
+ if(nextnonce == NULL)
+ return NULL;
+ }
- if(!ha_bufdata(buf))
- return HA_CRITERROR;
+ /* For older clients RFC 2069 */
+ if(!dg->qop)
+ {
+ if(nextnonce)
+ ha_bufmcat(buf, "nextnonce=\"", nextnonce, "\"", NULL);
+
+ return ha_bufdata(buf);
+ }
+
+ /* Otherwise we do the whole song and dance */
+ /* Encode ha1 */
+ t = ha_bufenchex(buf, rec->ha1, MD5_LEN);
- /* Old style digest (RFC 2069) */
- if(!dg->qop)
- {
+ if(t == NULL)
+ return NULL;
+
+ /* Encode ha2 */
md5_init(&md5);
- md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
- md5_update(&md5, ":", 1);
- md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */
md5_update(&md5, ":", 1);
- md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha1 */
+ md5_update(&md5, dg->uri, strlen(dg->uri));
md5_final(hash, &md5);
- }
- /* New style 'auth' digest (RFC 2617) */
- else
- {
+ ha_bufenchex(buf, hash, MD5_LEN);
+
+ if(!ha_bufdata(buf))
+ return NULL;
+
+ /* New style 'auth' digest (RFC 2617) */
md5_init(&md5);
md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
md5_update(&md5, ":", 1);
@@ -453,119 +533,39 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t*
md5_update(&md5, ":", 1);
md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */
md5_final(hash, &md5);
- }
- /* Encode the digest */
- digest = ha_bufenchex(buf, hash, MD5_LEN);
+ /* Encode the digest */
+ t = ha_bufenchex(buf, hash, MD5_LEN);
- if(digest == NULL)
- return HA_CRITERROR;
+ if(t == NULL)
+ return NULL;
- if(strcasecmp(dg->digest, digest) != 0)
- {
- ha_messagex(LOG_WARNING, "digest authentication failed for user: %s", dg->username);
- return HA_FALSE;
- }
-
- return HA_OK;
-}
-
-const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
- digest_record_t* rec, unsigned char* next)
-{
- unsigned char hash[MD5_LEN];
- md5_ctx_t md5;
- const char* nextnonce = NULL;
- const char* t;
-
- ASSERT(buf && dg && rec);
+ ha_bufmcat(buf, "rspauth=\"", t, "\"",
+ ", qop=", dg->qop,
+ ", nc=", dg->nc,
+ ", cnonce=\"", dg->cnonce, "\"", NULL);
- /* This makes a new buffer */
- ha_bufcpy(buf, "");
-
- if(next)
- {
- nextnonce = ha_bufenc64(buf, next, DIGEST_NONCE_LEN);
-
- if(nextnonce == NULL)
- return NULL;
- }
-
- /* For older clients RFC 2069 */
- if(!dg->qop)
- {
if(nextnonce)
- ha_bufmcat(buf, "nextnonce=\"", nextnonce, "\"", NULL);
+ {
+ ha_bufjoin(buf);
+ ha_bufmcat(buf, ", nextnonce=\"", nextnonce, "\"", NULL);
+ }
return ha_bufdata(buf);
- }
-
- /* Otherwise we do the whole song and dance */
-
- /* Encode ha1 */
- t = ha_bufenchex(buf, rec->ha1, MD5_LEN);
-
- if(t == NULL)
- return NULL;
-
- /* Encode ha2 */
- md5_init(&md5);
- md5_update(&md5, ":", 1);
- md5_update(&md5, dg->uri, strlen(dg->uri));
- md5_final(hash, &md5);
-
- ha_bufenchex(buf, hash, MD5_LEN);
-
- if(!ha_bufdata(buf))
- return NULL;
-
- /* New style 'auth' digest (RFC 2617) */
- md5_init(&md5);
- md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
- md5_update(&md5, ":", 1);
- md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */
- md5_update(&md5, ":", 1);
- md5_update(&md5, dg->nc, strlen(dg->nc)); /* nc */
- md5_update(&md5, ":", 1);
- md5_update(&md5, dg->cnonce, strlen(dg->cnonce)); /* cnonce */
- md5_update(&md5, ":", 1);
- md5_update(&md5, dg->qop, strlen(dg->qop)); /* qop */
- md5_update(&md5, ":", 1);
- md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */
- md5_final(hash, &md5);
-
- /* Encode the digest */
- t = ha_bufenchex(buf, hash, MD5_LEN);
-
- if(t == NULL)
- return NULL;
-
- ha_bufmcat(buf, "rspauth=\"", t, "\"",
- ", qop=", dg->qop,
- ", nc=", dg->nc,
- ", cnonce=\"", dg->cnonce, "\"", NULL);
-
- if(nextnonce)
- {
- ha_bufjoin(buf);
- ha_bufmcat(buf, ", nextnonce=\"", nextnonce, "\"", NULL);
- }
-
- return ha_bufdata(buf);
}
void digest_makeha1(unsigned char* digest, const char* user,
const char* realm, const char* password)
{
- md5_ctx_t md5;
+ md5_ctx_t md5;
- ASSERT(digest && user && realm && password);
+ ASSERT(digest && user && realm && password);
- md5_init(&md5);
- md5_update(&md5, user, strlen(user));
- md5_update(&md5, ":", 1);
- md5_update(&md5, realm, strlen(realm));
- md5_update(&md5, ":", 1);
- md5_update(&md5, password, strlen(password));
- md5_final(digest, &md5);
+ md5_init(&md5);
+ md5_update(&md5, user, strlen(user));
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, realm, strlen(realm));
+ md5_update(&md5, ":", 1);
+ md5_update(&md5, password, strlen(password));
+ md5_final(digest, &md5);
}