Luca Altea's major HTTP Digest update

This commit is contained in:
Daniel Stenberg
2004-04-29 08:18:32 +00:00
parent 699ebe2f0b
commit b34c40dcf5
2 changed files with 195 additions and 55 deletions

View File

@@ -33,9 +33,10 @@
#include "urldata.h" #include "urldata.h"
#include "sendf.h" #include "sendf.h"
#include "strequal.h" #include "strequal.h"
#include "base64.h"
#include "md5.h" #include "md5.h"
#include "http_digest.h" #include "http_digest.h"
#include "strtok.h"
#include "url.h" /* for Curl_safefree() */ #include "url.h" /* for Curl_safefree() */
#define _MPRINTF_REPLACE /* use our functions only */ #define _MPRINTF_REPLACE /* use our functions only */
@@ -57,6 +58,10 @@ CURLdigest Curl_input_digest(struct connectdata *conn,
header */ header */
{ {
bool more = TRUE; bool more = TRUE;
char *token = NULL;
char *tmp = NULL;
bool foundAuth = FALSE;
bool foundAuthInt = FALSE;
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
bool before = FALSE; /* got a nonce before */ bool before = FALSE; /* got a nonce before */
struct digestdata *d = &data->state.digest; struct digestdata *d = &data->state.digest;
@@ -94,16 +99,43 @@ CURLdigest Curl_input_digest(struct connectdata *conn,
d->nonce = strdup(content); d->nonce = strdup(content);
} }
else if(strequal(value, "stale")) { else if(strequal(value, "stale")) {
if(strequal(content, "true")) if(strequal(content, "true")) {
d->stale = TRUE; d->stale = TRUE;
d->nc = 1; /* we make a new nonce now */
} }
else if(strequal(value, "cnonce")) {
d->cnonce = strdup(content);
} }
else if(strequal(value, "realm")) { else if(strequal(value, "realm")) {
d->realm = strdup(content); d->realm = strdup(content);
} }
else if(strequal(value, "opaque")) {
d->opaque = strdup(content);
}
else if(strequal(value, "qop")) {
char *tok_buf;
/* tokenize the list and choose auth if possible, use a temporary
clone of the buffer since strtok_r() ruins it */
tmp = strdup(content);
token = strtok_r(tmp, ",", &tok_buf);
while (token != NULL) {
if (strequal(token, "auth")) {
foundAuth = TRUE;
}
else if (strequal(token, "auth-int")) {
foundAuthInt = TRUE;
}
token = strtok (NULL, ",");
}
free(tmp);
/*select only auth o auth-int. Otherwise, ignore*/
if (foundAuth) {
d->qop = strdup("auth");
}
else if (foundAuthInt) {
d->qop = strdup("auth-int");
}
}
else if(strequal(value, "algorithm")) { else if(strequal(value, "algorithm")) {
d->algorithm = strdup(content);
if(strequal(content, "MD5-sess")) if(strequal(content, "MD5-sess"))
d->algo = CURLDIGESTALGO_MD5SESS; d->algo = CURLDIGESTALGO_MD5SESS;
else if(strequal(content, "MD5")) else if(strequal(content, "MD5"))
@@ -127,7 +159,6 @@ CURLdigest Curl_input_digest(struct connectdata *conn,
/* We had a nonce since before, and we got another one now without /* We had a nonce since before, and we got another one now without
'stale=true'. This means we provided bad credentials in the previous 'stale=true'. This means we provided bad credentials in the previous
request */ request */
if(before && !d->stale) if(before && !d->stale)
return CURLDIGEST_BAD; return CURLDIGEST_BAD;
@@ -159,14 +190,31 @@ CURLcode Curl_output_digest(struct connectdata *conn,
this sorted out, I must urge you dear friend to read up on the RFC2617 this sorted out, I must urge you dear friend to read up on the RFC2617
section 3.2.2, */ section 3.2.2, */
unsigned char md5buf[16]; /* 16 bytes/128 bits */ unsigned char md5buf[16]; /* 16 bytes/128 bits */
unsigned char ha1[33]; /* 32 digits and 1 zero byte */
unsigned char ha2[33];
unsigned char request_digest[33]; unsigned char request_digest[33];
unsigned char *md5this; unsigned char *md5this;
unsigned char *ha1;
unsigned char ha2[33];/* 32 digits and 1 zero byte */
char cnoncebuf[7];
char *cnonce;
char *tmp = NULL;
struct timeval now;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
struct digestdata *d = &data->state.digest; struct digestdata *d = &data->state.digest;
ha1 = (unsigned char *)malloc(33); /* 32 digits and 1 zero byte */
if(!d->nc)
d->nc = 1;
if(!d->cnonce) {
/* Generate a cnonce */
now = Curl_tvnow();
snprintf(cnoncebuf, sizeof(cnoncebuf), "%06d", now.tv_sec);
Curl_base64_encode(cnoncebuf, strlen(cnoncebuf), &cnonce);
d->cnonce = cnonce;
}
/* /*
if the algorithm is "MD5" or unspecified (which then defaults to MD5): if the algorithm is "MD5" or unspecified (which then defaults to MD5):
@@ -177,40 +225,61 @@ CURLcode Curl_output_digest(struct connectdata *conn,
A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
":" unq(nonce-value) ":" unq(cnonce-value) ":" unq(nonce-value) ":" unq(cnonce-value)
*/ */
if(d->algo == CURLDIGESTALGO_MD5SESS) {
md5this = (unsigned char *) md5this = (unsigned char *)
aprintf("%s:%s:%s:%s:%s", aprintf("%s:%s:%s", conn->user, d->realm, conn->passwd);
conn->user,
d->realm,
conn->passwd,
d->nonce,
d->cnonce);
}
else {
md5this = (unsigned char *)
aprintf("%s:%s:%s",
conn->user,
d->realm,
conn->passwd);
}
Curl_md5it(md5buf, md5this); Curl_md5it(md5buf, md5this);
free(md5this); /* free this again */ free(md5this); /* free this again */
md5_to_ascii(md5buf, ha1); md5_to_ascii(md5buf, ha1);
if(d->algo == CURLDIGESTALGO_MD5SESS) {
/* nonce and cnonce are OUTSIDE the hash */
tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
free(ha1);
ha1 = (unsigned char *)tmp;
}
/* /*
If the "qop" directive's value is "auth" or is unspecified, then A2 is:
A2 = Method ":" digest-uri-value A2 = Method ":" digest-uri-value
If the "qop" value is "auth-int", then A2 is:
A2 = Method ":" digest-uri-value ":" H(entity-body)
(The "Method" value is the HTTP request method as specified in section (The "Method" value is the HTTP request method as specified in section
5.1.1 of RFC 2616) 5.1.1 of RFC 2616)
*/ */
md5this = (unsigned char *)aprintf("%s:%s", request, uripath); md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
if (d->qop && strequal(d->qop, "auth-int")) {
/* We don't support auth-int at the moment. I can't see a easy way to get
entity-body here */
/* TODO: Append H(entity-body)*/
}
Curl_md5it(md5buf, md5this); Curl_md5it(md5buf, md5this);
free(md5this); /* free this again */ free(md5this); /* free this again */
md5_to_ascii(md5buf, ha2); md5_to_ascii(md5buf, ha2);
md5this = (unsigned char *)aprintf("%s:%s:%s", ha1, d->nonce, if (d->qop) {
md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
ha1,
d->nonce,
d->nc,
d->cnonce,
d->qop,
ha2); ha2);
}
else {
md5this = (unsigned char *)aprintf("%s:%s:%s",
ha1,
d->nonce,
ha2);
}
free(ha1);
Curl_md5it(md5buf, md5this); Curl_md5it(md5buf, md5this);
free(md5this); /* free this again */ free(md5this); /* free this again */
md5_to_ascii(md5buf, request_digest); md5_to_ascii(md5buf, request_digest);
@@ -222,18 +291,73 @@ CURLcode Curl_output_digest(struct connectdata *conn,
*/ */
Curl_safefree(conn->allocptr.userpwd); Curl_safefree(conn->allocptr.userpwd);
if (d->qop) {
conn->allocptr.userpwd = conn->allocptr.userpwd =
aprintf( "Authorization: Digest " aprintf( "Authorization: Digest "
"username=\"%s\", " "username=\"%s\", "
"realm=\"%s\", " "realm=\"%s\", "
"nonce=\"%s\", " "nonce=\"%s\", "
"uri=\"%s\", " "uri=\"%s\", "
"response=\"%s\"\r\n", "cnonce=\"%s\", "
"nc=\"%08x\", "
"qop=\"%s\", "
"response=\"%s\"",
conn->user,
d->realm,
d->nonce,
uripath, /* this is the PATH part of the URL */
d->cnonce,
d->nc,
d->qop,
request_digest);
if(strequal(d->qop, "auth"))
d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded
which tells to the server how many times you are using the
same nonce in the qop=auth mode. */
}
else {
conn->allocptr.userpwd =
aprintf( "Authorization: Digest "
"username=\"%s\", "
"realm=\"%s\", "
"nonce=\"%s\", "
"uri=\"%s\", "
"response=\"%s\"",
conn->user, conn->user,
d->realm, d->realm,
d->nonce, d->nonce,
uripath, /* this is the PATH part of the URL */ uripath, /* this is the PATH part of the URL */
request_digest); request_digest);
}
/* Add optional fields */
if(d->opaque) {
/* append opaque */
tmp = aprintf(", opaque=\"%s\"", d->opaque);
conn->allocptr.userpwd = (char*)
realloc(conn->allocptr.userpwd,
strlen(conn->allocptr.userpwd) + strlen(tmp) + 1);
strcat(conn->allocptr.userpwd, tmp);
free(tmp);
}
if(d->algorithm) {
/* append algorithm */
tmp = aprintf(", algorithm=\"%s\"", d->algorithm);
conn->allocptr.userpwd = (char*)
realloc(conn->allocptr.userpwd,
strlen(conn->allocptr.userpwd) + strlen(tmp) + 1);
strcat(conn->allocptr.userpwd, tmp);
free(tmp);
}
/* append CRLF to the userpwd header */
conn->allocptr.userpwd = (char*)
realloc(conn->allocptr.userpwd,
strlen(conn->allocptr.userpwd) + 3 + 1);
strcat(conn->allocptr.userpwd, "\r\n");
return CURLE_OK; return CURLE_OK;
} }
@@ -254,8 +378,20 @@ void Curl_digest_cleanup(struct SessionHandle *data)
free(d->realm); free(d->realm);
d->realm = NULL; d->realm = NULL;
d->algo = CURLDIGESTALGO_MD5; /* default algorithm */ if(d->opaque)
free(d->opaque);
d->opaque = NULL;
if(d->qop)
free(d->qop);
d->qop = NULL;
if(d->algorithm)
free(d->algorithm);
d->algorithm = NULL;
d->nc = 0;
d->algo = CURLDIGESTALGO_MD5; /* default algorithm */
d->stale = FALSE; /* default means normal, not stale */ d->stale = FALSE; /* default means normal, not stale */
} }

View File

@@ -171,6 +171,10 @@ struct digestdata {
char *realm; char *realm;
int algo; int algo;
bool stale; /* set true for re-negotiation */ bool stale; /* set true for re-negotiation */
char *opaque;
char *qop;
char *algorithm;
int nc; /* nounce count */
}; };
typedef enum { typedef enum {