123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- /***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, 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 CURLDEBUG
- #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");
- /* clear off any former leftovers and init to defaults */
- Curl_digest_cleanup(data);
- while(more) {
- char value[32];
- char content[128];
- size_t 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++;
- }
- if(!data->state.digest.nonce)
- return CURLDIGEST_BAD;
- }
- 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];
- unsigned 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 = (unsigned char *)
- aprintf("%s:%s:%s:%s:%s",
- conn->user,
- data->state.digest.realm,
- conn->passwd,
- data->state.digest.nonce,
- data->state.digest.cnonce);
- }
- else {
- md5this = (unsigned char *)
- aprintf("%s:%s:%s",
- conn->user,
- data->state.digest.realm,
- conn->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 = (unsigned char *)aprintf("%s:%s", request, uripath);
- Curl_md5it(md5buf, md5this);
- free(md5this); /* free this again */
- md5_to_ascii(md5buf, ha2);
-
- md5this = (unsigned char *)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",
- conn->user,
- data->state.digest.realm,
- data->state.digest.nonce,
- uripath, /* this is the PATH part of the URL */
- request_digest );
- return CURLE_OK;
- }
- void Curl_digest_cleanup(struct SessionHandle *data)
- {
- if(data->state.digest.nonce)
- free(data->state.digest.nonce);
- data->state.digest.nonce = NULL;
- if(data->state.digest.cnonce)
- free(data->state.digest.cnonce);
- data->state.digest.cnonce = NULL;
- if(data->state.digest.realm)
- free(data->state.digest.realm);
- data->state.digest.realm = NULL;
- data->state.digest.algo = CURLDIGESTALGO_MD5; /* default algorithm */
- }
- #endif
|