diff options
Diffstat (limited to 'lib/http_digest.c')
-rw-r--r-- | lib/http_digest.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/lib/http_digest.c b/lib/http_digest.c new file mode 100644 index 000000000..82ae1d2a8 --- /dev/null +++ b/lib/http_digest.c @@ -0,0 +1,210 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2003, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ +#include "setup.h" + +#ifndef CURL_DISABLE_HTTP +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> + +#include "urldata.h" +#include "sendf.h" +#include "strequal.h" + +#include "md5.h" +#include "http_digest.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#ifdef MALLOCDEBUG +#include "memdebug.h" +#endif + +/* Test example header: + +WWW-Authenticate: Digest realm="testrealm", nonce="1053604598" + +*/ + +CURLdigest Curl_input_digest(struct connectdata *conn, + char *header) /* rest of the www-authenticate: + header */ +{ + bool more = TRUE; + struct SessionHandle *data=conn->data; + + /* skip initial whitespaces */ + while(*header && isspace((int)*header)) + header++; + + if(checkprefix("Digest", header)) { + header += strlen("Digest"); + + data->state.digest.algo = CURLDIGESTALGO_MD5; /* default algorithm */ + + while(more) { + char value[32]; + char content[128]; + int totlen=0; + + while(*header && isspace((int)*header)) + header++; + + /* how big can these strings be? */ + if(2 == sscanf(header, "%31[^=]=\"%127[^\"]\"", + value, content)) { + if(strequal(value, "nonce")) { + data->state.digest.nonce = strdup(content); + } + else if(strequal(value, "cnonce")) { + data->state.digest.cnonce = strdup(content); + } + else if(strequal(value, "realm")) { + data->state.digest.realm = strdup(content); + } + else if(strequal(value, "algorithm")) { + if(strequal(content, "MD5-sess")) + data->state.digest.algo = CURLDIGESTALGO_MD5SESS; + /* else, remain using the default md5 */ + } + else { + /* unknown specifier, ignore it! */ + } + totlen = strlen(value)+strlen(content)+3; + } + else + break; /* we're done here */ + + header += totlen; + if(',' == *header) + /* allow the list to be comma-separated */ + header++; + } + } + else + /* else not a digest, get out */ + return CURLDIGEST_NONE; + + return CURLDIGEST_FINE; +} + +/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/ +static void md5_to_ascii(unsigned char *source, /* 16 bytes */ + unsigned char *dest) /* 33 bytes */ +{ + int i; + for(i=0; i<16; i++) + sprintf((char *)&dest[i*2], "%02x", source[i]); +} + +CURLcode Curl_output_digest(struct connectdata *conn, + unsigned char *request, + unsigned char *uripath) +{ + /* We have a Digest setup for this, use it! + Now, to get all the details for this sorted out, I must urge you dear friend + to read up on the RFC2617 section 3.2.2, */ + 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]; + char *md5this; + + struct SessionHandle *data = conn->data; + + /* + if the algorithm is "MD5" or unspecified (which then defaults to MD5): + + A1 = unq(username-value) ":" unq(realm-value) ":" passwd + + if the algorithm is "MD5-sess" then: + + A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd ) + ":" unq(nonce-value) ":" unq(cnonce-value) + */ + if(data->state.digest.algo == CURLDIGESTALGO_MD5SESS) { + md5this = aprintf("%s:%s:%s:%s:%s", + data->state.user, + data->state.digest.realm, + data->state.passwd, + data->state.digest.nonce, + data->state.digest.cnonce); + } + else { + md5this = aprintf("%s:%s:%s", + data->state.user, + data->state.digest.realm, + data->state.passwd); + } + Curl_md5it(md5buf, md5this); + free(md5this); /* free this again */ + md5_to_ascii(md5buf, ha1); + + /* + A2 = Method ":" digest-uri-value + + (The "Method" value is the HTTP request method as specified in section + 5.1.1 of RFC 2616) + */ + + md5this = aprintf("%s:%s", request, uripath); + Curl_md5it(md5buf, md5this); + free(md5this); /* free this again */ + md5_to_ascii(md5buf, ha2); + + md5this = aprintf("%s:%s:%s", + ha1, + data->state.digest.nonce, + ha2); + Curl_md5it(md5buf, md5this); + free(md5this); /* free this again */ + md5_to_ascii(md5buf, request_digest); + + /* for test case 64 (snooped from a Mozilla 1.3a request) + + Authorization: Digest username="testuser", realm="testrealm", \ + nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" + */ + + conn->allocptr.userpwd = + aprintf( "Authorization: Digest " + "username=\"%s\", " + "realm=\"%s\", " + "nonce=\"%s\", " + "uri=\"%s\", " + "response=\"%s\"\r\n", + data->state.user, + data->state.digest.realm, + data->state.digest.nonce, + uripath, /* this is the PATH part of the URL */ + request_digest ); + + return CURLE_OK; +} + +#endif |