aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorFlorin <pfl@northq.com>2017-09-30 20:30:55 +0200
committerDaniel Stenberg <daniel@haxx.se>2017-10-28 16:32:43 +0200
commit2b5b37cb9109e7c2e6bfa5ebf54016aff8a1fb48 (patch)
tree500f6f5e953534c048c991d7d7432dd0e65de158 /lib
parent1d0c8dea95794dd0591bdbf742de32e542365a3a (diff)
auth: add support for RFC7616 - HTTP Digest access authentication
Signed-off-by: Florin <petriuc.florin@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.inc4
-rw-r--r--lib/curl_sha256.h32
-rw-r--r--lib/sha256.c262
-rw-r--r--lib/urldata.h1
-rw-r--r--lib/vauth/digest.c194
-rw-r--r--lib/vauth/digest.h6
6 files changed, 454 insertions, 45 deletions
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index 5c0b930cf..a9de05a9c 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -54,7 +54,7 @@ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \
curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c \
- mime.c
+ mime.c sha256.c
LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
@@ -73,7 +73,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \
curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
- curl_printf.h system_win32.h rand.h mime.h
+ curl_printf.h system_win32.h rand.h mime.h curl_sha256.h
LIB_RCFILES = libcurl.rc
diff --git a/lib/curl_sha256.h b/lib/curl_sha256.h
new file mode 100644
index 000000000..6db4b04db
--- /dev/null
+++ b/lib/curl_sha256.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_SHA256_H
+#define HEADER_CURL_SHA256_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Florin Petriuc, <petriuc.florin@gmail.com>
+ *
+ * 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 https://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.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+void Curl_sha256it(unsigned char *outbuffer,
+ const unsigned char *input);
+
+#endif
+
+#endif /* HEADER_CURL_SHA256_H */
diff --git a/lib/sha256.c b/lib/sha256.c
new file mode 100644
index 000000000..cd81c0254
--- /dev/null
+++ b/lib/sha256.c
@@ -0,0 +1,262 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Florin Petriuc, <petriuc.florin@gmail.com>
+ *
+ * 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 https://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.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include "warnless.h"
+#include "curl_sha256.h"
+
+#if defined(USE_OPENSSL)
+
+/* When OpenSSL is available we use the SHA256-function from OpenSSL */
+#include <openssl/sha.h>
+
+#else
+
+/* When no other crypto library is available we use this code segment */
+
+/* ===== start - public domain SHA256 implementation ===== */
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+#define WPA_GET_BE32(a) ((((unsigned long)(a)[0]) << 24) | \
+ (((unsigned long)(a)[1]) << 16) | \
+ (((unsigned long)(a)[2]) << 8) | \
+ ((unsigned long)(a)[3]))
+#define WPA_PUT_BE32(a, val) \
+do { \
+ (a)[0] = (unsigned char)((((unsigned long) (val)) >> 24) & 0xff); \
+ (a)[1] = (unsigned char)((((unsigned long) (val)) >> 16) & 0xff); \
+ (a)[2] = (unsigned char)((((unsigned long) (val)) >> 8) & 0xff); \
+ (a)[3] = (unsigned char)(((unsigned long) (val)) & 0xff); \
+} while(0)
+
+#ifdef HAVE_LONGLONG
+#define WPA_PUT_BE64(a, val) \
+do { \
+ (a)[0] = (unsigned char)(((unsigned long long)(val)) >> 56); \
+ (a)[1] = (unsigned char)(((unsigned long long)(val)) >> 48); \
+ (a)[2] = (unsigned char)(((unsigned long long)(val)) >> 40); \
+ (a)[3] = (unsigned char)(((unsigned long long)(val)) >> 32); \
+ (a)[4] = (unsigned char)(((unsigned long long)(val)) >> 24); \
+ (a)[5] = (unsigned char)(((unsigned long long)(val)) >> 16); \
+ (a)[6] = (unsigned char)(((unsigned long long)(val)) >> 8); \
+ (a)[7] = (unsigned char)(((unsigned long long)(val)) & 0xff); \
+} while(0)
+#else
+#define WPA_PUT_BE64(a, val) \
+do { \
+ (a)[0] = (unsigned char)(((unsigned __int64)(val)) >> 56); \
+ (a)[1] = (unsigned char)(((unsigned __int64)(val)) >> 48); \
+ (a)[2] = (unsigned char)(((unsigned __int64)(val)) >> 40); \
+ (a)[3] = (unsigned char)(((unsigned __int64)(val)) >> 32); \
+ (a)[4] = (unsigned char)(((unsigned __int64)(val)) >> 24); \
+ (a)[5] = (unsigned char)(((unsigned __int64)(val)) >> 16); \
+ (a)[6] = (unsigned char)(((unsigned __int64)(val)) >> 8); \
+ (a)[7] = (unsigned char)(((unsigned __int64)(val)) & 0xff); \
+} while(0)
+#endif
+
+typedef struct sha256_state {
+#ifdef HAVE_LONGLONG
+ unsigned long long length;
+#else
+ unsigned __int64 length;
+#endif
+ unsigned long state[8], curlen;
+ unsigned char buf[64];
+} SHA256_CTX;
+/* the K array */
+static const unsigned long K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+/* Various logical functions */
+#define RORc(x, y) \
+(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
+ ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x), (n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+/* compress 512-bits */
+static int sha256_compress(struct sha256_state *md,
+ unsigned char *buf)
+{
+ unsigned long S[8], W[64], t0, t1;
+ unsigned long t;
+ int i;
+ /* copy state into S */
+ for(i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+ /* copy the state into 512-bits into W[0..15] */
+ for(i = 0; i < 16; i++)
+ W[i] = WPA_GET_BE32(buf + (4 * i));
+ /* fill W[16..63] */
+ for(i = 16; i < 64; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+ W[i - 16];
+ }
+ /* Compress */
+#define RND(a,b,c,d,e,f,g,h,i) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+ for(i = 0; i < 64; ++i) {
+ RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+ }
+ /* feedback */
+ for(i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+ return 0;
+}
+/* Initialize the hash state */
+static void SHA256_Init(struct sha256_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = 0x6A09E667UL;
+ md->state[1] = 0xBB67AE85UL;
+ md->state[2] = 0x3C6EF372UL;
+ md->state[3] = 0xA54FF53AUL;
+ md->state[4] = 0x510E527FUL;
+ md->state[5] = 0x9B05688CUL;
+ md->state[6] = 0x1F83D9ABUL;
+ md->state[7] = 0x5BE0CD19UL;
+}
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+static int SHA256_Update(struct sha256_state *md,
+ const unsigned char *in,
+ unsigned long inlen)
+{
+ unsigned long n;
+#define block_size 64
+ if(md->curlen > sizeof(md->buf))
+ return -1;
+ while(inlen > 0) {
+ if(md->curlen == 0 && inlen >= block_size) {
+ if(sha256_compress(md, (unsigned char *)in) < 0)
+ return -1;
+ md->length += block_size * 8;
+ in += block_size;
+ inlen -= block_size;
+ }
+ else {
+ n = MIN(inlen, (block_size - md->curlen));
+ memcpy(md->buf + md->curlen, in, n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if(md->curlen == block_size) {
+ if(sha256_compress(md, md->buf) < 0)
+ return -1;
+ md->length += 8 * block_size;
+ md->curlen = 0;
+ }
+ }
+ }
+ return 0;
+}
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (32 bytes)
+ @return CRYPT_OK if successful
+*/
+static int SHA256_Final(unsigned char *out,
+ struct sha256_state *md)
+{
+ int i;
+ if(md->curlen >= sizeof(md->buf))
+ return -1;
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char)0x80;
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if(md->curlen > 56) {
+ while(md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ sha256_compress(md, md->buf);
+ md->curlen = 0;
+ }
+ /* pad upto 56 bytes of zeroes */
+ while(md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char)0;
+ }
+ /* store length */
+ WPA_PUT_BE64(md->buf + 56, md->length);
+ sha256_compress(md, md->buf);
+ /* copy output */
+ for(i = 0; i < 8; i++)
+ WPA_PUT_BE32(out + (4 * i), md->state[i]);
+ return 0;
+}
+/* ===== end - public domain SHA256 implementation ===== */
+
+#endif
+
+void Curl_sha256it(unsigned char *outbuffer, /* 32 unsigned chars */
+ const unsigned char *input)
+{
+ SHA256_CTX ctx;
+ SHA256_Init(&ctx);
+ SHA256_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
+ SHA256_Final(outbuffer, &ctx);
+}
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/lib/urldata.h b/lib/urldata.h
index 30e13a452..e5aae1430 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -286,6 +286,7 @@ struct digestdata {
char *qop;
char *algorithm;
int nc; /* nounce count */
+ bool userhash;
#endif
};
diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c
index 185098ed6..131d9da8c 100644
--- a/lib/vauth/digest.c
+++ b/lib/vauth/digest.c
@@ -19,6 +19,7 @@
* KIND, either express or implied.
*
* RFC2831 DIGEST-MD5 authentication
+ * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication
*
***************************************************************************/
@@ -34,6 +35,7 @@
#include "curl_base64.h"
#include "curl_hmac.h"
#include "curl_md5.h"
+#include "curl_sha256.h"
#include "vtls/vtls.h"
#include "warnless.h"
#include "strtok.h"
@@ -144,6 +146,15 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
}
+/* Convert sha256 chunk to RFC7616 -suitable ascii string*/
+static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
+ unsigned char *dest) /* 65 bytes */
+{
+ int i;
+ for(i = 0; i < 32; i++)
+ snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+}
+
/* Perform quoted-string escaping as described in RFC2616 and its errata */
static char *auth_digest_string_quoted(const char *source)
{
@@ -602,9 +613,22 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
digest->algo = CURLDIGESTALGO_MD5SESS;
else if(strcasecompare(content, "MD5"))
digest->algo = CURLDIGESTALGO_MD5;
+ else if(strcasecompare(content, "SHA-256"))
+ digest->algo = CURLDIGESTALGO_SHA256;
+ else if(strcasecompare(content, "SHA-256-SESS"))
+ digest->algo = CURLDIGESTALGO_SHA256SESS;
+ else if(strcasecompare(content, "SHA-512-256"))
+ digest->algo = CURLDIGESTALGO_SHA512_256;
+ else if(strcasecompare(content, "SHA-512-256-SESS"))
+ digest->algo = CURLDIGESTALGO_SHA512_256SESS;
else
return CURLE_BAD_CONTENT_ENCODING;
}
+ else if(strcasecompare(value, "userhash")) {
+ if(strcasecompare(content, "true")) {
+ digest->userhash = TRUE;
+ }
+ }
else {
/* Unknown specifier, ignore it! */
}
@@ -635,7 +659,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
}
/*
- * Curl_auth_create_digest_http_message()
+ * _Curl_auth_create_digest_http_message()
*
* This is used to generate a HTTP DIGEST response message ready for sending
* to the recipient.
@@ -654,20 +678,24 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
- const char *userp,
- const char *passwdp,
- const unsigned char *request,
- const unsigned char *uripath,
- struct digestdata *digest,
- char **outptr, size_t *outlen)
+static CURLcode _Curl_auth_create_digest_http_message(
+ struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const unsigned char *request,
+ const unsigned char *uripath,
+ struct digestdata *digest,
+ char **outptr, size_t *outlen,
+ void (*convert_to_ascii)(unsigned char *, unsigned char *),
+ void (*hash)(unsigned char *, const unsigned char *))
{
CURLcode result;
- unsigned char md5buf[16]; /* 16 bytes/128 bits */
- unsigned char request_digest[33];
- unsigned char *md5this;
- unsigned char ha1[33]; /* 32 digits and 1 zero byte */
- unsigned char ha2[33]; /* 32 digits and 1 zero byte */
+ unsigned char hashbuf[32]; /* 32 bytes/256 bits */
+ unsigned char request_digest[65];
+ unsigned char *hashthis;
+ unsigned char ha1[65]; /* 64 digits and 1 zero byte */
+ unsigned char ha2[65]; /* 64 digits and 1 zero byte */
+ char userh[65];
char cnoncebuf[33];
char *cnonce = NULL;
size_t cnonce_sz = 0;
@@ -692,6 +720,17 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
digest->cnonce = cnonce;
}
+ if(digest->userhash) {
+ hashthis = (unsigned char *) aprintf("%s:%s", userp, digest->realm);
+ if(!hashthis)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis);
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, (unsigned char *)userh);
+ }
+
/*
If the algorithm is "MD5" or unspecified (which then defaults to MD5):
@@ -703,26 +742,29 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
unq(nonce-value) ":" unq(cnonce-value)
*/
- md5this = (unsigned char *)
- aprintf("%s:%s:%s", userp, digest->realm, passwdp);
- if(!md5this)
+ hashthis = (unsigned char *)
+ aprintf("%s:%s:%s", digest->userhash ? userh : userp,
+ digest->realm, passwdp);
+ if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this);
- auth_digest_md5_to_ascii(md5buf, ha1);
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, ha1);
- if(digest->algo == CURLDIGESTALGO_MD5SESS) {
+ if(digest->algo == CURLDIGESTALGO_MD5SESS ||
+ digest->algo == CURLDIGESTALGO_SHA256SESS ||
+ digest->algo == CURLDIGESTALGO_SHA512_256SESS) {
/* nonce and cnonce are OUTSIDE the hash */
tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce);
if(!tmp)
return CURLE_OUT_OF_MEMORY;
CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */
- Curl_md5it(md5buf, (unsigned char *) tmp);
+ hash(hashbuf, (unsigned char *) tmp);
free(tmp);
- auth_digest_md5_to_ascii(md5buf, ha1);
+ convert_to_ascii(hashbuf, ha1);
}
/*
@@ -738,27 +780,32 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
5.1.1 of RFC 2616)
*/
- md5this = (unsigned char *) aprintf("%s:%s", request, uripath);
+ hashthis = (unsigned char *) aprintf("%s:%s", request, uripath);
if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
/* We don't support auth-int for PUT or POST at the moment.
- TODO: replace md5 of empty string with entity-body for PUT/POST */
- unsigned char *md5this2 = (unsigned char *)
- aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e");
- free(md5this);
- md5this = md5this2;
+ TODO: replace hash of empty string with entity-body for PUT/POST */
+ char hashed[65];
+ unsigned char *hashthis2;
+
+ hash(hashbuf, (const unsigned char *)"");
+ convert_to_ascii(hashbuf, (unsigned char *)hashed);
+
+ hashthis2 = (unsigned char *)aprintf("%s:%s", hashthis, hashed);
+ free(hashthis);
+ hashthis = hashthis2;
}
- if(!md5this)
+ if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this);
- auth_digest_md5_to_ascii(md5buf, ha2);
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, ha2);
if(digest->qop) {
- md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
+ hashthis = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
ha1,
digest->nonce,
digest->nc,
@@ -767,19 +814,19 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
ha2);
}
else {
- md5this = (unsigned char *) aprintf("%s:%s:%s",
+ hashthis = (unsigned char *) aprintf("%s:%s:%s",
ha1,
digest->nonce,
ha2);
}
- if(!md5this)
+ if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this);
- auth_digest_md5_to_ascii(md5buf, request_digest);
+ CURL_OUTPUT_DIGEST_CONV(data, hashthis); /* convert on non-ASCII machines */
+ hash(hashbuf, hashthis);
+ free(hashthis);
+ convert_to_ascii(hashbuf, request_digest);
/* For test case 64 (snooped from a Mozilla 1.3a request)
@@ -794,7 +841,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
characters. algorithm and qop with standard values only contain web-safe
characters.
*/
- userp_quoted = auth_digest_string_quoted(userp);
+ userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
if(!userp_quoted)
return CURLE_OUT_OF_MEMORY;
@@ -858,6 +905,16 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
response = tmp;
}
+ if(digest->userhash) {
+ /* Append the userhash */
+ tmp = aprintf("%s, userhash=true", response);
+ free(response);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+
+ response = tmp;
+ }
+
/* Return the output */
*outptr = response;
*outlen = strlen(response);
@@ -866,6 +923,58 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
}
/*
+ * Curl_auth_create_digest_http_message()
+ *
+ * This is used to generate a HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * request [in] - The HTTP request.
+ * uripath [in] - The path of the HTTP uri.
+ * digest [in/out] - The digest data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const unsigned char *request,
+ const unsigned char *uripath,
+ struct digestdata *digest,
+ char **outptr, size_t *outlen)
+{
+ switch(digest->algo) {
+ case CURLDIGESTALGO_MD5:
+ case CURLDIGESTALGO_MD5SESS:
+ return _Curl_auth_create_digest_http_message(data, userp, passwdp,
+ request, uripath, digest,
+ outptr, outlen,
+ auth_digest_md5_to_ascii,
+ Curl_md5it);
+
+ case CURLDIGESTALGO_SHA256:
+ case CURLDIGESTALGO_SHA256SESS:
+ case CURLDIGESTALGO_SHA512_256:
+ case CURLDIGESTALGO_SHA512_256SESS:
+ return _Curl_auth_create_digest_http_message(data, userp, passwdp,
+ request, uripath, digest,
+ outptr, outlen,
+ auth_digest_sha256_to_ascii,
+ Curl_sha256it);
+
+ default:
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+}
+
+/*
* Curl_auth_digest_cleanup()
*
* This is used to clean up the digest specific data.
@@ -887,6 +996,7 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
digest->nc = 0;
digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */
digest->stale = FALSE; /* default means normal, not stale */
+ digest->userhash = FALSE;
}
#endif /* !USE_WINDOWS_SSPI */
diff --git a/lib/vauth/digest.h b/lib/vauth/digest.h
index 5722dcece..8686c44a4 100644
--- a/lib/vauth/digest.h
+++ b/lib/vauth/digest.h
@@ -31,7 +31,11 @@
enum {
CURLDIGESTALGO_MD5,
- CURLDIGESTALGO_MD5SESS
+ CURLDIGESTALGO_MD5SESS,
+ CURLDIGESTALGO_SHA256,
+ CURLDIGESTALGO_SHA256SESS,
+ CURLDIGESTALGO_SHA512_256,
+ CURLDIGESTALGO_SHA512_256SESS
};
/* This is used to extract the realm from a challenge message */