summaryrefslogtreecommitdiff
path: root/daemon/digest.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/digest.c')
-rw-r--r--daemon/digest.c202
1 files changed, 98 insertions, 104 deletions
diff --git a/daemon/digest.c b/daemon/digest.c
index 099bf31..bce588e 100644
--- a/daemon/digest.c
+++ b/daemon/digest.c
@@ -69,25 +69,6 @@ int digest_checknonce(unsigned char* nonce, unsigned char* secret, time_t* tm)
return HA_FALSE;
}
-digest_record_t* digest_makerec(unsigned char* nonce, const char* user)
-{
- digest_record_t* rec = (digest_record_t*)malloc(sizeof(*rec));
-
- ASSERT(nonce && user);
-
- if(!rec)
- {
- ha_messagex(NULL, LOG_CRIT, "out of memory");
- return NULL;
- }
-
- memset(rec, 0, sizeof(*rec));
- memcpy(rec->nonce, nonce, DIGEST_NONCE_LEN);
-
- 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)
{
@@ -127,16 +108,16 @@ const char* digest_challenge(ha_buffer_t* buf, const char* nonce_str,
* limitations under the License.
*/
-int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec,
- unsigned char* nonce)
+int digest_parse(const char* head, ha_buffer_t* buf, digest_header_t* rec)
{
char next;
char* key;
char* value;
+ char* header;
- ASSERT(header && buf && rec);
+ ASSERT(head && buf && rec);
- header = ha_bufcpy(buf, header);
+ header = ha_bufcpy(buf, head);
if(!header)
return HA_CRITERROR;
@@ -230,93 +211,78 @@ int digest_parse(char* header, ha_buffer_t* buf, digest_header_t* rec,
}
}
- if(nonce)
- {
- memset(nonce, 0, DIGEST_NONCE_LEN);
+ return HA_OK;
+}
- if(rec->nonce)
- {
- size_t len = DIGEST_NONCE_LEN;
- void* d = ha_bufdechex(buf, rec->nonce, &len);
+int digest_check(digest_context_t* dg, const ha_context_t* opts, ha_buffer_t* buf)
+{
+ int r;
- if(d && len == DIGEST_NONCE_LEN)
- memcpy(nonce, d, DIGEST_NONCE_LEN);
- }
- }
+ r = digest_pre_check(dg, opts, buf);
+ if(r == HA_OK)
+ r = digest_complete_check(dg, buf);
- return HA_OK;
+ return r;
}
-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)
+int digest_pre_check(digest_context_t* dg, const ha_context_t* opts, ha_buffer_t* buf)
{
- unsigned char hash[MD5_LEN];
- md5_ctx_t md5;
- const char* digest;
- const char* t;
-
- ASSERT(ctx && method && buf && dg && rec);
+ ASSERT(buf && buf && dg);
/* TODO: This stuff should probably go into bd.c */
/* Check for digest */
- if(!dg->digest || !dg->digest[0])
+ if(!dg->client.digest || !dg->client.digest[0])
{
ha_messagex(NULL, LOG_WARNING, "digest response missing digest");
return HA_BADREQ;
}
/* Username */
- if(!dg->username || !dg->username[0])
+ if(!dg->client.username || !dg->client.username[0])
{
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;
- }
-
/* The realm */
- if(!dg->realm)
+ if(!dg->client.realm)
{
ha_messagex(NULL, LOG_WARNING, "digest response contains missing realm");
return HA_BADREQ;
}
- if(strcmp(dg->realm, ctx->realm) != 0)
+ if(strcmp(dg->client.realm, opts->realm) != 0)
{
- ha_messagex(NULL, LOG_ERR, "digest response contains invalid realm: %s", dg->realm);
+ ha_messagex(NULL, LOG_ERR, "digest response contains invalid realm: %s", dg->client.realm);
return HA_FALSE;
}
/* Components in the new RFC */
- if(dg->qop)
+ if(dg->client.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)
+ if(strcmp(dg->client.qop, "auth") != 0)
{
ha_messagex(NULL, LOG_WARNING, "digest response contains unknown or unsupported qop: '%s'",
- dg->qop ? dg->qop : "");
+ dg->client.qop ? dg->client.qop : "");
return HA_BADREQ;
}
/* The cnonce */
- if(!dg->cnonce || !dg->cnonce[0])
+ if(!dg->client.cnonce || !dg->client.cnonce[0])
{
ha_messagex(NULL, LOG_WARNING, "digest response is missing cnonce value");
return HA_BADREQ;
}
- if(!ctx->digest_ignorenc)
+ if(!opts->digest_ignorenc)
{
/* The nonce count */
- if(!dg->nc || !dg->nc[0])
+ if(!dg->client.nc || !dg->client.nc[0])
{
ha_messagex(NULL, LOG_WARNING, "digest response is missing nc value");
return HA_BADREQ;
@@ -326,22 +292,22 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t*
else
{
char* e;
- long nc = strtol(dg->nc, &e, 16);
+ long nc = strtol(dg->client.nc, &e, 16);
if(*e)
{
- ha_messagex(NULL, LOG_ERR, "digest response has invalid nc value: %s", dg->nc);
+ ha_messagex(NULL, LOG_ERR, "digest response has invalid nc value: %s", dg->client.nc);
return HA_BADREQ;
}
/* If we didn't a nc then save it away */
- if(!*e && rec->nc == 0)
- rec->nc = nc;
+ if(!*e && dg->server_nc == 0)
+ dg->server_nc = nc;
- if(*e || nc != rec->nc)
+ if(*e || nc != dg->server_nc)
{
ha_messagex(NULL, LOG_WARNING, "digest response has wrong nc value. "
- "possible replay attack: %s", dg->nc);
+ "possible replay attack: %s", dg->client.nc);
return HA_FALSE;
}
}
@@ -349,47 +315,49 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t*
}
/* The algorithm */
- if(dg->algorithm && strcasecmp(dg->algorithm, "MD5") != 0)
+ if(dg->client.algorithm && strcasecmp(dg->client.algorithm, "MD5") != 0)
{
ha_messagex(NULL, LOG_WARNING, "digest response contains unknown or unsupported algorithm: '%s'",
- dg->algorithm ? dg->algorithm : "");
+ dg->client.algorithm ? dg->client.algorithm : "");
return HA_BADREQ;
}
/* Request URI */
- if(!dg->uri)
+ if(!dg->client.uri)
{
ha_messagex(NULL, LOG_WARNING, "digest response is missing uri");
return HA_BADREQ;
}
- if(!ctx->digest_ignoreuri && strcmp(dg->uri, uri) != 0)
+ if(!opts->digest_ignoreuri && strcmp(dg->client.uri, dg->server_uri) != 0)
{
ha_uri_t d_uri;
ha_uri_t s_uri;
- if(ha_uriparse(buf, dg->uri, &d_uri) < 0)
+ if(ha_uriparse(buf, dg->client.uri, &d_uri) < 0)
{
if(ha_buferr(buf))
return HA_CRITERROR;
- ha_messagex(NULL, LOG_WARNING, "digest response constains invalid uri: %s", dg->uri);
+ ha_messagex(NULL, LOG_WARNING, "digest response constains invalid uri: %s", dg->client.uri);
return HA_BADREQ;
}
- if(ha_uriparse(buf, uri, &s_uri) < 0)
+ ASSERT(dg->server_uri);
+
+ if(ha_uriparse(buf, dg->server_uri, &s_uri) < 0)
{
if(ha_buferr(buf))
return HA_CRITERROR;
- ha_messagex(NULL, LOG_ERR, "server sent us an invalid uri");
+ ha_messagex(NULL, LOG_ERR, "server sent us an invalid uri: %s", dg->server_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);
+ "(should be %s)", dg->client.uri, dg->server_uri);
return HA_FALSE;
}
}
@@ -402,21 +370,36 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t*
* if it's used there.
*/
+ return HA_OK;
+}
+
+
+int digest_complete_check(digest_context_t* dg, ha_buffer_t* buf)
+{
+ unsigned char hash[MD5_LEN];
+ md5_ctx_t md5;
+ const char* t;
+ const char* digest;
+
+ ASSERT(dg && buf);
+
/*
* Now we validate the digest response
*/
/* Encode ha1 */
- t = ha_bufenchex(buf, rec->ha1, MD5_LEN);
+ t = ha_bufenchex(buf, dg->ha1, MD5_LEN);
if(t == NULL)
return HA_CRITERROR;
+ ASSERT(dg->server_method);
+
/* Encode ha2 */
md5_init(&md5);
- md5_update(&md5, method, strlen(method));
+ md5_update(&md5, dg->server_method, strlen(dg->server_method));
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->uri, strlen(dg->uri));
+ md5_update(&md5, dg->client.uri, strlen(dg->client.uri));
md5_final(hash, &md5);
ha_bufenchex(buf, hash, MD5_LEN);
@@ -424,14 +407,15 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t*
if(!ha_bufdata(buf))
return HA_CRITERROR;
+ ASSERT(dg->client.nonce);
/* Old style digest (RFC 2069) */
- if(!dg->qop)
+ if(!dg->client.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, dg->client.nonce, strlen(dg->client.nonce)); /* nonce */
md5_update(&md5, ":", 1);
md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha1 */
md5_final(hash, &md5);
@@ -440,16 +424,20 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t*
/* New style 'auth' digest (RFC 2617) */
else
{
+ ASSERT(dg->client.nc);
+ ASSERT(dg->client.cnonce);
+ ASSERT(dg->client.qop);
+
md5_init(&md5);
- md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
+ md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */
+ md5_update(&md5, dg->client.nonce, strlen(dg->client.nonce)); /* nonce */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->nc, strlen(dg->nc)); /* nc */
+ md5_update(&md5, dg->client.nc, strlen(dg->client.nc)); /* nc */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->cnonce, strlen(dg->cnonce)); /* cnonce */
+ md5_update(&md5, dg->client.cnonce, strlen(dg->client.cnonce)); /* cnonce */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->qop, strlen(dg->qop)); /* qop */
+ md5_update(&md5, dg->client.qop, strlen(dg->client.qop)); /* qop */
md5_update(&md5, ":", 1);
md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */
md5_final(hash, &md5);
@@ -461,24 +449,23 @@ int digest_check(digest_header_t* dg, digest_record_t* rec, const ha_context_t*
if(digest == NULL)
return HA_CRITERROR;
- if(strcasecmp(dg->digest, digest) != 0)
- {
- ha_messagex(NULL, LOG_WARNING, "digest authentication failed for user: %s", dg->username);
+ ASSERT(dg->client.digest);
+
+ if(strcasecmp(dg->client.digest, digest) != 0)
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)
+const char* digest_respond(digest_context_t* dg, ha_buffer_t* buf,
+ unsigned char* next)
{
unsigned char hash[MD5_LEN];
md5_ctx_t md5;
const char* nextnonce = NULL;
const char* t;
- ASSERT(buf && dg && rec);
+ ASSERT(buf && dg);
/* This makes a new buffer */
ha_bufcpy(buf, "");
@@ -492,7 +479,7 @@ const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
}
/* For older clients RFC 2069 */
- if(!dg->qop)
+ if(!dg->client.qop)
{
if(nextnonce)
ha_bufmcat(buf, "nextnonce=\"", nextnonce, "\"", NULL);
@@ -503,15 +490,17 @@ const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
/* Otherwise we do the whole song and dance */
/* Encode ha1 */
- t = ha_bufenchex(buf, rec->ha1, MD5_LEN);
+ t = ha_bufenchex(buf, dg->ha1, MD5_LEN);
if(t == NULL)
return NULL;
+ ASSERT(dg->client.uri);
+
/* Encode ha2 */
md5_init(&md5);
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->uri, strlen(dg->uri));
+ md5_update(&md5, dg->client.uri, strlen(dg->client.uri));
md5_final(hash, &md5);
ha_bufenchex(buf, hash, MD5_LEN);
@@ -519,19 +508,24 @@ const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
if(!ha_bufdata(buf))
return NULL;
+ ASSERT(dg->client.nonce);
+ ASSERT(dg->client.nc);
+ ASSERT(dg->client.cnonce);
+ ASSERT(dg->client.qop);
+
/* New style 'auth' digest (RFC 2617) */
md5_init(&md5);
- md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
+ md5_update(&md5, t, MD5_LEN * 2); /* ha1 */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->nonce, strlen(dg->nonce)); /* nonce */
+ md5_update(&md5, dg->client.nonce, strlen(dg->client.nonce)); /* nonce */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->nc, strlen(dg->nc)); /* nc */
+ md5_update(&md5, dg->client.nc, strlen(dg->client.nc)); /* nc */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->cnonce, strlen(dg->cnonce)); /* cnonce */
+ md5_update(&md5, dg->client.cnonce, strlen(dg->client.cnonce)); /* cnonce */
md5_update(&md5, ":", 1);
- md5_update(&md5, dg->qop, strlen(dg->qop)); /* qop */
+ md5_update(&md5, dg->client.qop, strlen(dg->client.qop)); /* qop */
md5_update(&md5, ":", 1);
- md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */
+ md5_update(&md5, ha_bufdata(buf), MD5_LEN * 2); /* ha2 */
md5_final(hash, &md5);
/* Encode the digest */
@@ -541,9 +535,9 @@ const char* digest_respond(ha_buffer_t* buf, digest_header_t* dg,
return NULL;
ha_bufmcat(buf, "rspauth=\"", t, "\"",
- ", qop=", dg->qop,
- ", nc=", dg->nc,
- ", cnonce=\"", dg->cnonce, "\"", NULL);
+ ", qop=", dg->client.qop,
+ ", nc=", dg->client.nc,
+ ", cnonce=\"", dg->client.cnonce, "\"", NULL);
if(nextnonce)
{