1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * RFC2831 DIGEST-MD5 authentication
22 * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication
24 ***************************************************************************/
26 #include "curl_setup.h"
28 #if !defined(CURL_DISABLE_CRYPTO_AUTH)
30 #include <curl/curl.h>
32 #include "vauth/vauth.h"
33 #include "vauth/digest.h"
35 #include "curl_base64.h"
36 #include "curl_hmac.h"
38 #include "curl_sha256.h"
39 #include "vtls/vtls.h"
43 #include "curl_printf.h"
46 /* The last #include files should be: */
47 #include "curl_memory.h"
50 #if !defined(USE_WINDOWS_SSPI)
51 #define DIGEST_QOP_VALUE_AUTH (1 << 0)
52 #define DIGEST_QOP_VALUE_AUTH_INT (1 << 1)
53 #define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2)
55 #define DIGEST_QOP_VALUE_STRING_AUTH "auth"
56 #define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int"
57 #define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
60 bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
64 bool starts_with_quote = FALSE;
67 for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);)
76 /* This starts with a quote so it must end with one as well! */
78 starts_with_quote = TRUE;
81 for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) {
85 /* possibly the start of an escaped quote */
87 *content++ = '\\'; /* Even though this is an escape character, we still
88 store it as-is in the target buffer */
94 if(!starts_with_quote) {
95 /* This signals the end of the content if we didn't get a starting
96 quote and then we do "sloppy" parsing */
109 if(!escape && starts_with_quote) {
127 #if !defined(USE_WINDOWS_SSPI)
128 /* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
129 static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
130 unsigned char *dest) /* 33 bytes */
133 for(i = 0; i < 16; i++)
134 msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
137 /* Convert sha256 chunk to RFC7616 -suitable ascii string*/
138 static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
139 unsigned char *dest) /* 65 bytes */
142 for(i = 0; i < 32; i++)
143 msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
146 /* Perform quoted-string escaping as described in RFC2616 and its errata */
147 static char *auth_digest_string_quoted(const char *source)
150 const char *s = source;
151 size_t n = 1; /* null terminator */
153 /* Calculate size needed */
156 if(*s == '"' || *s == '\\') {
167 if(*s == '"' || *s == '\\') {
178 /* Retrieves the value for a corresponding key from the challenge string
179 * returns TRUE if the key could be found, FALSE if it does not exists
181 static bool auth_digest_get_key_value(const char *chlg,
190 find_pos = strstr(chlg, key);
194 find_pos += strlen(key);
196 for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
197 value[i] = *find_pos++;
203 static CURLcode auth_digest_get_qop_values(const char *options, int *value)
207 char *tok_buf = NULL;
209 /* Initialise the output */
212 /* Tokenise the list of qop values. Use a temporary clone of the buffer since
213 strtok_r() ruins it. */
214 tmp = strdup(options);
216 return CURLE_OUT_OF_MEMORY;
218 token = strtok_r(tmp, ",", &tok_buf);
220 if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
221 *value |= DIGEST_QOP_VALUE_AUTH;
222 else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
223 *value |= DIGEST_QOP_VALUE_AUTH_INT;
224 else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
225 *value |= DIGEST_QOP_VALUE_AUTH_CONF;
227 token = strtok_r(NULL, ",", &tok_buf);
236 * auth_decode_digest_md5_message()
238 * This is used internally to decode an already encoded DIGEST-MD5 challenge
239 * message into the separate attributes.
243 * chlgref [in] - The challenge message.
244 * nonce [in/out] - The buffer where the nonce will be stored.
245 * nlen [in] - The length of the nonce buffer.
246 * realm [in/out] - The buffer where the realm will be stored.
247 * rlen [in] - The length of the realm buffer.
248 * alg [in/out] - The buffer where the algorithm will be stored.
249 * alen [in] - The length of the algorithm buffer.
250 * qop [in/out] - The buffer where the qop-options will be stored.
251 * qlen [in] - The length of the qop buffer.
253 * Returns CURLE_OK on success.
255 static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref,
256 char *nonce, size_t nlen,
257 char *realm, size_t rlen,
258 char *alg, size_t alen,
259 char *qop, size_t qlen)
261 const char *chlg = (const char *) Curl_bufref_ptr(chlgref);
263 /* Ensure we have a valid challenge message */
264 if(!Curl_bufref_len(chlgref))
265 return CURLE_BAD_CONTENT_ENCODING;
267 /* Retrieve nonce string from the challenge */
268 if(!auth_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"'))
269 return CURLE_BAD_CONTENT_ENCODING;
271 /* Retrieve realm string from the challenge */
272 if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
273 /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
277 /* Retrieve algorithm string from the challenge */
278 if(!auth_digest_get_key_value(chlg, "algorithm=", alg, alen, ','))
279 return CURLE_BAD_CONTENT_ENCODING;
281 /* Retrieve qop-options string from the challenge */
282 if(!auth_digest_get_key_value(chlg, "qop=\"", qop, qlen, '\"'))
283 return CURLE_BAD_CONTENT_ENCODING;
289 * Curl_auth_is_digest_supported()
291 * This is used to evaluate if DIGEST is supported.
295 * Returns TRUE as DIGEST as handled by libcurl.
297 bool Curl_auth_is_digest_supported(void)
303 * Curl_auth_create_digest_md5_message()
305 * This is used to generate an already encoded DIGEST-MD5 response message
306 * ready for sending to the recipient.
310 * data [in] - The session handle.
311 * chlg [in] - The challenge message.
312 * userp [in] - The user name.
313 * passwdp [in] - The user's password.
314 * service [in] - The service type such as http, smtp, pop or imap.
315 * out [out] - The result storage.
317 * Returns CURLE_OK on success.
319 CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
320 const struct bufref *chlg,
327 struct MD5_context *ctxt;
328 char *response = NULL;
329 unsigned char digest[MD5_DIGEST_LEN];
330 char HA1_hex[2 * MD5_DIGEST_LEN + 1];
331 char HA2_hex[2 * MD5_DIGEST_LEN + 1];
332 char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
336 char qop_options[64];
339 char nonceCount[] = "00000001";
340 char method[] = "AUTHENTICATE";
341 char qop[] = DIGEST_QOP_VALUE_STRING_AUTH;
344 /* Decode the challenge message */
345 CURLcode result = auth_decode_digest_md5_message(chlg,
346 nonce, sizeof(nonce),
347 realm, sizeof(realm),
351 sizeof(qop_options));
355 /* We only support md5 sessions */
356 if(strcmp(algorithm, "md5-sess") != 0)
357 return CURLE_BAD_CONTENT_ENCODING;
359 /* Get the qop-values from the qop-options */
360 result = auth_digest_get_qop_values(qop_options, &qop_values);
364 /* We only support auth quality-of-protection */
365 if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
366 return CURLE_BAD_CONTENT_ENCODING;
368 /* Generate 32 random hex chars, 32 bytes + 1 zero termination */
369 result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce));
373 /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
374 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
376 return CURLE_OUT_OF_MEMORY;
378 Curl_MD5_update(ctxt, (const unsigned char *) userp,
379 curlx_uztoui(strlen(userp)));
380 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
381 Curl_MD5_update(ctxt, (const unsigned char *) realm,
382 curlx_uztoui(strlen(realm)));
383 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
384 Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
385 curlx_uztoui(strlen(passwdp)));
386 Curl_MD5_final(ctxt, digest);
388 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
390 return CURLE_OUT_OF_MEMORY;
392 Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
393 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
394 Curl_MD5_update(ctxt, (const unsigned char *) nonce,
395 curlx_uztoui(strlen(nonce)));
396 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
397 Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
398 curlx_uztoui(strlen(cnonce)));
399 Curl_MD5_final(ctxt, digest);
401 /* Convert calculated 16 octet hex into 32 bytes string */
402 for(i = 0; i < MD5_DIGEST_LEN; i++)
403 msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
405 /* Generate our SPN */
406 spn = Curl_auth_build_spn(service, realm, NULL);
408 return CURLE_OUT_OF_MEMORY;
410 /* Calculate H(A2) */
411 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
415 return CURLE_OUT_OF_MEMORY;
418 Curl_MD5_update(ctxt, (const unsigned char *) method,
419 curlx_uztoui(strlen(method)));
420 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
421 Curl_MD5_update(ctxt, (const unsigned char *) spn,
422 curlx_uztoui(strlen(spn)));
423 Curl_MD5_final(ctxt, digest);
425 for(i = 0; i < MD5_DIGEST_LEN; i++)
426 msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
428 /* Now calculate the response hash */
429 ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
433 return CURLE_OUT_OF_MEMORY;
436 Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
437 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
438 Curl_MD5_update(ctxt, (const unsigned char *) nonce,
439 curlx_uztoui(strlen(nonce)));
440 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
442 Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
443 curlx_uztoui(strlen(nonceCount)));
444 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
445 Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
446 curlx_uztoui(strlen(cnonce)));
447 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
448 Curl_MD5_update(ctxt, (const unsigned char *) qop,
449 curlx_uztoui(strlen(qop)));
450 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
452 Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
453 Curl_MD5_final(ctxt, digest);
455 for(i = 0; i < MD5_DIGEST_LEN; i++)
456 msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
458 /* Generate the response */
459 response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
460 "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
463 cnonce, nonceCount, spn, resp_hash_hex, qop);
466 return CURLE_OUT_OF_MEMORY;
468 /* Return the response. */
469 Curl_bufref_set(out, response, strlen(response), curl_free);
474 * Curl_auth_decode_digest_http_message()
476 * This is used to decode a HTTP DIGEST challenge message into the separate
481 * chlg [in] - The challenge message.
482 * digest [in/out] - The digest data struct being used and modified.
484 * Returns CURLE_OK on success.
486 CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
487 struct digestdata *digest)
489 bool before = FALSE; /* got a nonce before */
490 bool foundAuth = FALSE;
491 bool foundAuthInt = FALSE;
495 /* If we already have received a nonce, keep that in mind */
499 /* Clean up any former leftovers and initialise to defaults */
500 Curl_auth_digest_cleanup(digest);
503 char value[DIGEST_MAX_VALUE_LENGTH];
504 char content[DIGEST_MAX_CONTENT_LENGTH];
506 /* Pass all additional spaces here */
507 while(*chlg && ISSPACE(*chlg))
510 /* Extract a value=content pair */
511 if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
512 if(strcasecompare(value, "nonce")) {
514 digest->nonce = strdup(content);
516 return CURLE_OUT_OF_MEMORY;
518 else if(strcasecompare(value, "stale")) {
519 if(strcasecompare(content, "true")) {
520 digest->stale = TRUE;
521 digest->nc = 1; /* we make a new nonce now */
524 else if(strcasecompare(value, "realm")) {
526 digest->realm = strdup(content);
528 return CURLE_OUT_OF_MEMORY;
530 else if(strcasecompare(value, "opaque")) {
531 free(digest->opaque);
532 digest->opaque = strdup(content);
534 return CURLE_OUT_OF_MEMORY;
536 else if(strcasecompare(value, "qop")) {
537 char *tok_buf = NULL;
538 /* Tokenize the list and choose auth if possible, use a temporary
539 clone of the buffer since strtok_r() ruins it */
540 tmp = strdup(content);
542 return CURLE_OUT_OF_MEMORY;
544 token = strtok_r(tmp, ",", &tok_buf);
546 if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
549 else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
552 token = strtok_r(NULL, ",", &tok_buf);
557 /* Select only auth or auth-int. Otherwise, ignore */
560 digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH);
562 return CURLE_OUT_OF_MEMORY;
564 else if(foundAuthInt) {
566 digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT);
568 return CURLE_OUT_OF_MEMORY;
571 else if(strcasecompare(value, "algorithm")) {
572 free(digest->algorithm);
573 digest->algorithm = strdup(content);
574 if(!digest->algorithm)
575 return CURLE_OUT_OF_MEMORY;
577 if(strcasecompare(content, "MD5-sess"))
578 digest->algo = CURLDIGESTALGO_MD5SESS;
579 else if(strcasecompare(content, "MD5"))
580 digest->algo = CURLDIGESTALGO_MD5;
581 else if(strcasecompare(content, "SHA-256"))
582 digest->algo = CURLDIGESTALGO_SHA256;
583 else if(strcasecompare(content, "SHA-256-SESS"))
584 digest->algo = CURLDIGESTALGO_SHA256SESS;
585 else if(strcasecompare(content, "SHA-512-256"))
586 digest->algo = CURLDIGESTALGO_SHA512_256;
587 else if(strcasecompare(content, "SHA-512-256-SESS"))
588 digest->algo = CURLDIGESTALGO_SHA512_256SESS;
590 return CURLE_BAD_CONTENT_ENCODING;
592 else if(strcasecompare(value, "userhash")) {
593 if(strcasecompare(content, "true")) {
594 digest->userhash = TRUE;
598 /* Unknown specifier, ignore it! */
602 break; /* We're done here */
604 /* Pass all additional spaces here */
605 while(*chlg && ISSPACE(*chlg))
608 /* Allow the list to be comma-separated */
613 /* We had a nonce since before, and we got another one now without
614 'stale=true'. This means we provided bad credentials in the previous
616 if(before && !digest->stale)
617 return CURLE_BAD_CONTENT_ENCODING;
619 /* We got this header without a nonce, that's a bad Digest line! */
621 return CURLE_BAD_CONTENT_ENCODING;
627 * auth_create_digest_http_message()
629 * This is used to generate a HTTP DIGEST response message ready for sending
634 * data [in] - The session handle.
635 * userp [in] - The user name.
636 * passwdp [in] - The user's password.
637 * request [in] - The HTTP request.
638 * uripath [in] - The path of the HTTP uri.
639 * digest [in/out] - The digest data struct being used and modified.
640 * outptr [in/out] - The address where a pointer to newly allocated memory
641 * holding the result will be stored upon completion.
642 * outlen [out] - The length of the output message.
644 * Returns CURLE_OK on success.
646 static CURLcode auth_create_digest_http_message(
647 struct Curl_easy *data,
650 const unsigned char *request,
651 const unsigned char *uripath,
652 struct digestdata *digest,
653 char **outptr, size_t *outlen,
654 void (*convert_to_ascii)(unsigned char *, unsigned char *),
655 CURLcode (*hash)(unsigned char *, const unsigned char *,
659 unsigned char hashbuf[32]; /* 32 bytes/256 bits */
660 unsigned char request_digest[65];
661 unsigned char ha1[65]; /* 64 digits and 1 zero byte */
662 unsigned char ha2[65]; /* 64 digits and 1 zero byte */
665 size_t cnonce_sz = 0;
667 char *response = NULL;
668 char *hashthis = NULL;
674 if(!digest->cnonce) {
676 result = Curl_rand_hex(data, (unsigned char *)cnoncebuf,
681 result = Curl_base64_encode(cnoncebuf, strlen(cnoncebuf),
682 &cnonce, &cnonce_sz);
686 digest->cnonce = cnonce;
689 if(digest->userhash) {
690 hashthis = aprintf("%s:%s", userp, digest->realm);
692 return CURLE_OUT_OF_MEMORY;
694 hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
696 convert_to_ascii(hashbuf, (unsigned char *)userh);
700 If the algorithm is "MD5" or unspecified (which then defaults to MD5):
702 A1 = unq(username-value) ":" unq(realm-value) ":" passwd
704 If the algorithm is "MD5-sess" then:
706 A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":"
707 unq(nonce-value) ":" unq(cnonce-value)
710 hashthis = aprintf("%s:%s:%s", userp, digest->realm, passwdp);
712 return CURLE_OUT_OF_MEMORY;
714 hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
716 convert_to_ascii(hashbuf, ha1);
718 if(digest->algo == CURLDIGESTALGO_MD5SESS ||
719 digest->algo == CURLDIGESTALGO_SHA256SESS ||
720 digest->algo == CURLDIGESTALGO_SHA512_256SESS) {
721 /* nonce and cnonce are OUTSIDE the hash */
722 tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce);
724 return CURLE_OUT_OF_MEMORY;
726 hash(hashbuf, (unsigned char *) tmp, strlen(tmp));
728 convert_to_ascii(hashbuf, ha1);
732 If the "qop" directive's value is "auth" or is unspecified, then A2 is:
734 A2 = Method ":" digest-uri-value
736 If the "qop" value is "auth-int", then A2 is:
738 A2 = Method ":" digest-uri-value ":" H(entity-body)
740 (The "Method" value is the HTTP request method as specified in section
744 hashthis = aprintf("%s:%s", request, uripath);
746 return CURLE_OUT_OF_MEMORY;
748 if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
749 /* We don't support auth-int for PUT or POST */
753 hash(hashbuf, (const unsigned char *)"", 0);
754 convert_to_ascii(hashbuf, (unsigned char *)hashed);
756 hashthis2 = aprintf("%s:%s", hashthis, hashed);
758 hashthis = hashthis2;
762 return CURLE_OUT_OF_MEMORY;
764 hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
766 convert_to_ascii(hashbuf, ha2);
769 hashthis = aprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, digest->nc,
770 digest->cnonce, digest->qop, ha2);
773 hashthis = aprintf("%s:%s:%s", ha1, digest->nonce, ha2);
777 return CURLE_OUT_OF_MEMORY;
779 hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
781 convert_to_ascii(hashbuf, request_digest);
783 /* For test case 64 (snooped from a Mozilla 1.3a request)
785 Authorization: Digest username="testuser", realm="testrealm", \
786 nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
788 Digest parameters are all quoted strings. Username which is provided by
789 the user will need double quotes and backslashes within it escaped. For
790 the other fields, this shouldn't be an issue. realm, nonce, and opaque
791 are copied as is from the server, escapes and all. cnonce is generated
792 with web-safe characters. uri is already percent encoded. nc is 8 hex
793 characters. algorithm and qop with standard values only contain web-safe
796 userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
798 return CURLE_OUT_OF_MEMORY;
801 response = aprintf("username=\"%s\", "
818 if(strcasecompare(digest->qop, "auth"))
819 digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0
820 padded which tells to the server how many times you are
821 using the same nonce in the qop=auth mode */
824 response = aprintf("username=\"%s\", "
837 return CURLE_OUT_OF_MEMORY;
839 /* Add the optional fields */
841 /* Append the opaque */
842 tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque);
845 return CURLE_OUT_OF_MEMORY;
850 if(digest->algorithm) {
851 /* Append the algorithm */
852 tmp = aprintf("%s, algorithm=%s", response, digest->algorithm);
855 return CURLE_OUT_OF_MEMORY;
860 if(digest->userhash) {
861 /* Append the userhash */
862 tmp = aprintf("%s, userhash=true", response);
865 return CURLE_OUT_OF_MEMORY;
870 /* Return the output */
872 *outlen = strlen(response);
878 * Curl_auth_create_digest_http_message()
880 * This is used to generate a HTTP DIGEST response message ready for sending
885 * data [in] - The session handle.
886 * userp [in] - The user name.
887 * passwdp [in] - The user's password.
888 * request [in] - The HTTP request.
889 * uripath [in] - The path of the HTTP uri.
890 * digest [in/out] - The digest data struct being used and modified.
891 * outptr [in/out] - The address where a pointer to newly allocated memory
892 * holding the result will be stored upon completion.
893 * outlen [out] - The length of the output message.
895 * Returns CURLE_OK on success.
897 CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
900 const unsigned char *request,
901 const unsigned char *uripath,
902 struct digestdata *digest,
903 char **outptr, size_t *outlen)
905 switch(digest->algo) {
906 case CURLDIGESTALGO_MD5:
907 case CURLDIGESTALGO_MD5SESS:
908 return auth_create_digest_http_message(data, userp, passwdp,
909 request, uripath, digest,
911 auth_digest_md5_to_ascii,
914 case CURLDIGESTALGO_SHA256:
915 case CURLDIGESTALGO_SHA256SESS:
916 case CURLDIGESTALGO_SHA512_256:
917 case CURLDIGESTALGO_SHA512_256SESS:
918 return auth_create_digest_http_message(data, userp, passwdp,
919 request, uripath, digest,
921 auth_digest_sha256_to_ascii,
925 return CURLE_UNSUPPORTED_PROTOCOL;
930 * Curl_auth_digest_cleanup()
932 * This is used to clean up the digest specific data.
936 * digest [in/out] - The digest data struct being cleaned up.
939 void Curl_auth_digest_cleanup(struct digestdata *digest)
941 Curl_safefree(digest->nonce);
942 Curl_safefree(digest->cnonce);
943 Curl_safefree(digest->realm);
944 Curl_safefree(digest->opaque);
945 Curl_safefree(digest->qop);
946 Curl_safefree(digest->algorithm);
949 digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */
950 digest->stale = FALSE; /* default means normal, not stale */
951 digest->userhash = FALSE;
953 #endif /* !USE_WINDOWS_SSPI */
955 #endif /* CURL_DISABLE_CRYPTO_AUTH */