xref: /aosp_15_r20/external/curl/lib/vauth/digest.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  * RFC2831 DIGEST-MD5 authentication
24*6236dae4SAndroid Build Coastguard Worker  * RFC7616 DIGEST-SHA256, DIGEST-SHA512-256 authentication
25*6236dae4SAndroid Build Coastguard Worker  *
26*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
27*6236dae4SAndroid Build Coastguard Worker 
28*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
29*6236dae4SAndroid Build Coastguard Worker 
30*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_DIGEST_AUTH
31*6236dae4SAndroid Build Coastguard Worker 
32*6236dae4SAndroid Build Coastguard Worker #include <curl/curl.h>
33*6236dae4SAndroid Build Coastguard Worker 
34*6236dae4SAndroid Build Coastguard Worker #include "vauth/vauth.h"
35*6236dae4SAndroid Build Coastguard Worker #include "vauth/digest.h"
36*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
37*6236dae4SAndroid Build Coastguard Worker #include "curl_base64.h"
38*6236dae4SAndroid Build Coastguard Worker #include "curl_hmac.h"
39*6236dae4SAndroid Build Coastguard Worker #include "curl_md5.h"
40*6236dae4SAndroid Build Coastguard Worker #include "curl_sha256.h"
41*6236dae4SAndroid Build Coastguard Worker #include "curl_sha512_256.h"
42*6236dae4SAndroid Build Coastguard Worker #include "vtls/vtls.h"
43*6236dae4SAndroid Build Coastguard Worker #include "warnless.h"
44*6236dae4SAndroid Build Coastguard Worker #include "strtok.h"
45*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
46*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
47*6236dae4SAndroid Build Coastguard Worker #include "rand.h"
48*6236dae4SAndroid Build Coastguard Worker 
49*6236dae4SAndroid Build Coastguard Worker /* The last #include files should be: */
50*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
51*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
52*6236dae4SAndroid Build Coastguard Worker 
53*6236dae4SAndroid Build Coastguard Worker #define SESSION_ALGO 1 /* for algos with this bit set */
54*6236dae4SAndroid Build Coastguard Worker 
55*6236dae4SAndroid Build Coastguard Worker #define ALGO_MD5 0
56*6236dae4SAndroid Build Coastguard Worker #define ALGO_MD5SESS (ALGO_MD5 | SESSION_ALGO)
57*6236dae4SAndroid Build Coastguard Worker #define ALGO_SHA256 2
58*6236dae4SAndroid Build Coastguard Worker #define ALGO_SHA256SESS (ALGO_SHA256 | SESSION_ALGO)
59*6236dae4SAndroid Build Coastguard Worker #define ALGO_SHA512_256 4
60*6236dae4SAndroid Build Coastguard Worker #define ALGO_SHA512_256SESS (ALGO_SHA512_256 | SESSION_ALGO)
61*6236dae4SAndroid Build Coastguard Worker 
62*6236dae4SAndroid Build Coastguard Worker #if !defined(USE_WINDOWS_SSPI)
63*6236dae4SAndroid Build Coastguard Worker #define DIGEST_QOP_VALUE_AUTH             (1 << 0)
64*6236dae4SAndroid Build Coastguard Worker #define DIGEST_QOP_VALUE_AUTH_INT         (1 << 1)
65*6236dae4SAndroid Build Coastguard Worker #define DIGEST_QOP_VALUE_AUTH_CONF        (1 << 2)
66*6236dae4SAndroid Build Coastguard Worker 
67*6236dae4SAndroid Build Coastguard Worker #define DIGEST_QOP_VALUE_STRING_AUTH      "auth"
68*6236dae4SAndroid Build Coastguard Worker #define DIGEST_QOP_VALUE_STRING_AUTH_INT  "auth-int"
69*6236dae4SAndroid Build Coastguard Worker #define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
70*6236dae4SAndroid Build Coastguard Worker #endif
71*6236dae4SAndroid Build Coastguard Worker 
Curl_auth_digest_get_pair(const char * str,char * value,char * content,const char ** endptr)72*6236dae4SAndroid Build Coastguard Worker bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
73*6236dae4SAndroid Build Coastguard Worker                                const char **endptr)
74*6236dae4SAndroid Build Coastguard Worker {
75*6236dae4SAndroid Build Coastguard Worker   int c;
76*6236dae4SAndroid Build Coastguard Worker   bool starts_with_quote = FALSE;
77*6236dae4SAndroid Build Coastguard Worker   bool escape = FALSE;
78*6236dae4SAndroid Build Coastguard Worker 
79*6236dae4SAndroid Build Coastguard Worker   for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);)
80*6236dae4SAndroid Build Coastguard Worker     *value++ = *str++;
81*6236dae4SAndroid Build Coastguard Worker   *value = 0;
82*6236dae4SAndroid Build Coastguard Worker 
83*6236dae4SAndroid Build Coastguard Worker   if('=' != *str++)
84*6236dae4SAndroid Build Coastguard Worker     /* eek, no match */
85*6236dae4SAndroid Build Coastguard Worker     return FALSE;
86*6236dae4SAndroid Build Coastguard Worker 
87*6236dae4SAndroid Build Coastguard Worker   if('\"' == *str) {
88*6236dae4SAndroid Build Coastguard Worker     /* This starts with a quote so it must end with one as well! */
89*6236dae4SAndroid Build Coastguard Worker     str++;
90*6236dae4SAndroid Build Coastguard Worker     starts_with_quote = TRUE;
91*6236dae4SAndroid Build Coastguard Worker   }
92*6236dae4SAndroid Build Coastguard Worker 
93*6236dae4SAndroid Build Coastguard Worker   for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) {
94*6236dae4SAndroid Build Coastguard Worker     if(!escape) {
95*6236dae4SAndroid Build Coastguard Worker       switch(*str) {
96*6236dae4SAndroid Build Coastguard Worker       case '\\':
97*6236dae4SAndroid Build Coastguard Worker         if(starts_with_quote) {
98*6236dae4SAndroid Build Coastguard Worker           /* the start of an escaped quote */
99*6236dae4SAndroid Build Coastguard Worker           escape = TRUE;
100*6236dae4SAndroid Build Coastguard Worker           continue;
101*6236dae4SAndroid Build Coastguard Worker         }
102*6236dae4SAndroid Build Coastguard Worker         break;
103*6236dae4SAndroid Build Coastguard Worker 
104*6236dae4SAndroid Build Coastguard Worker       case ',':
105*6236dae4SAndroid Build Coastguard Worker         if(!starts_with_quote) {
106*6236dae4SAndroid Build Coastguard Worker           /* This signals the end of the content if we did not get a starting
107*6236dae4SAndroid Build Coastguard Worker              quote and then we do "sloppy" parsing */
108*6236dae4SAndroid Build Coastguard Worker           c = 0; /* the end */
109*6236dae4SAndroid Build Coastguard Worker           continue;
110*6236dae4SAndroid Build Coastguard Worker         }
111*6236dae4SAndroid Build Coastguard Worker         break;
112*6236dae4SAndroid Build Coastguard Worker 
113*6236dae4SAndroid Build Coastguard Worker       case '\r':
114*6236dae4SAndroid Build Coastguard Worker       case '\n':
115*6236dae4SAndroid Build Coastguard Worker         /* end of string */
116*6236dae4SAndroid Build Coastguard Worker         if(starts_with_quote)
117*6236dae4SAndroid Build Coastguard Worker           return FALSE; /* No closing quote */
118*6236dae4SAndroid Build Coastguard Worker         c = 0;
119*6236dae4SAndroid Build Coastguard Worker         continue;
120*6236dae4SAndroid Build Coastguard Worker 
121*6236dae4SAndroid Build Coastguard Worker       case '\"':
122*6236dae4SAndroid Build Coastguard Worker         if(starts_with_quote) {
123*6236dae4SAndroid Build Coastguard Worker           /* end of string */
124*6236dae4SAndroid Build Coastguard Worker           c = 0;
125*6236dae4SAndroid Build Coastguard Worker           continue;
126*6236dae4SAndroid Build Coastguard Worker         }
127*6236dae4SAndroid Build Coastguard Worker         else
128*6236dae4SAndroid Build Coastguard Worker           return FALSE;
129*6236dae4SAndroid Build Coastguard Worker       }
130*6236dae4SAndroid Build Coastguard Worker     }
131*6236dae4SAndroid Build Coastguard Worker 
132*6236dae4SAndroid Build Coastguard Worker     escape = FALSE;
133*6236dae4SAndroid Build Coastguard Worker     *content++ = *str;
134*6236dae4SAndroid Build Coastguard Worker   }
135*6236dae4SAndroid Build Coastguard Worker   if(escape)
136*6236dae4SAndroid Build Coastguard Worker     return FALSE; /* No character after backslash */
137*6236dae4SAndroid Build Coastguard Worker 
138*6236dae4SAndroid Build Coastguard Worker   *content = 0;
139*6236dae4SAndroid Build Coastguard Worker   *endptr = str;
140*6236dae4SAndroid Build Coastguard Worker 
141*6236dae4SAndroid Build Coastguard Worker   return TRUE;
142*6236dae4SAndroid Build Coastguard Worker }
143*6236dae4SAndroid Build Coastguard Worker 
144*6236dae4SAndroid Build Coastguard Worker #if !defined(USE_WINDOWS_SSPI)
145*6236dae4SAndroid Build Coastguard Worker /* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ASCII string */
auth_digest_md5_to_ascii(unsigned char * source,unsigned char * dest)146*6236dae4SAndroid Build Coastguard Worker static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
147*6236dae4SAndroid Build Coastguard Worker                                      unsigned char *dest) /* 33 bytes */
148*6236dae4SAndroid Build Coastguard Worker {
149*6236dae4SAndroid Build Coastguard Worker   int i;
150*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < 16; i++)
151*6236dae4SAndroid Build Coastguard Worker     msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
152*6236dae4SAndroid Build Coastguard Worker }
153*6236dae4SAndroid Build Coastguard Worker 
154*6236dae4SAndroid Build Coastguard Worker /* Convert sha256 or SHA-512/256 chunk to RFC7616 -suitable ASCII string */
auth_digest_sha256_to_ascii(unsigned char * source,unsigned char * dest)155*6236dae4SAndroid Build Coastguard Worker static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
156*6236dae4SAndroid Build Coastguard Worker                                      unsigned char *dest) /* 65 bytes */
157*6236dae4SAndroid Build Coastguard Worker {
158*6236dae4SAndroid Build Coastguard Worker   int i;
159*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < 32; i++)
160*6236dae4SAndroid Build Coastguard Worker     msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
161*6236dae4SAndroid Build Coastguard Worker }
162*6236dae4SAndroid Build Coastguard Worker 
163*6236dae4SAndroid Build Coastguard Worker /* Perform quoted-string escaping as described in RFC2616 and its errata */
auth_digest_string_quoted(const char * source)164*6236dae4SAndroid Build Coastguard Worker static char *auth_digest_string_quoted(const char *source)
165*6236dae4SAndroid Build Coastguard Worker {
166*6236dae4SAndroid Build Coastguard Worker   char *dest;
167*6236dae4SAndroid Build Coastguard Worker   const char *s = source;
168*6236dae4SAndroid Build Coastguard Worker   size_t n = 1; /* null terminator */
169*6236dae4SAndroid Build Coastguard Worker 
170*6236dae4SAndroid Build Coastguard Worker   /* Calculate size needed */
171*6236dae4SAndroid Build Coastguard Worker   while(*s) {
172*6236dae4SAndroid Build Coastguard Worker     ++n;
173*6236dae4SAndroid Build Coastguard Worker     if(*s == '"' || *s == '\\') {
174*6236dae4SAndroid Build Coastguard Worker       ++n;
175*6236dae4SAndroid Build Coastguard Worker     }
176*6236dae4SAndroid Build Coastguard Worker     ++s;
177*6236dae4SAndroid Build Coastguard Worker   }
178*6236dae4SAndroid Build Coastguard Worker 
179*6236dae4SAndroid Build Coastguard Worker   dest = malloc(n);
180*6236dae4SAndroid Build Coastguard Worker   if(dest) {
181*6236dae4SAndroid Build Coastguard Worker     char *d = dest;
182*6236dae4SAndroid Build Coastguard Worker     s = source;
183*6236dae4SAndroid Build Coastguard Worker     while(*s) {
184*6236dae4SAndroid Build Coastguard Worker       if(*s == '"' || *s == '\\') {
185*6236dae4SAndroid Build Coastguard Worker         *d++ = '\\';
186*6236dae4SAndroid Build Coastguard Worker       }
187*6236dae4SAndroid Build Coastguard Worker       *d++ = *s++;
188*6236dae4SAndroid Build Coastguard Worker     }
189*6236dae4SAndroid Build Coastguard Worker     *d = '\0';
190*6236dae4SAndroid Build Coastguard Worker   }
191*6236dae4SAndroid Build Coastguard Worker 
192*6236dae4SAndroid Build Coastguard Worker   return dest;
193*6236dae4SAndroid Build Coastguard Worker }
194*6236dae4SAndroid Build Coastguard Worker 
195*6236dae4SAndroid Build Coastguard Worker /* Retrieves the value for a corresponding key from the challenge string
196*6236dae4SAndroid Build Coastguard Worker  * returns TRUE if the key could be found, FALSE if it does not exists
197*6236dae4SAndroid Build Coastguard Worker  */
auth_digest_get_key_value(const char * chlg,const char * key,char * value,size_t max_val_len,char end_char)198*6236dae4SAndroid Build Coastguard Worker static bool auth_digest_get_key_value(const char *chlg,
199*6236dae4SAndroid Build Coastguard Worker                                       const char *key,
200*6236dae4SAndroid Build Coastguard Worker                                       char *value,
201*6236dae4SAndroid Build Coastguard Worker                                       size_t max_val_len,
202*6236dae4SAndroid Build Coastguard Worker                                       char end_char)
203*6236dae4SAndroid Build Coastguard Worker {
204*6236dae4SAndroid Build Coastguard Worker   char *find_pos;
205*6236dae4SAndroid Build Coastguard Worker   size_t i;
206*6236dae4SAndroid Build Coastguard Worker 
207*6236dae4SAndroid Build Coastguard Worker   find_pos = strstr(chlg, key);
208*6236dae4SAndroid Build Coastguard Worker   if(!find_pos)
209*6236dae4SAndroid Build Coastguard Worker     return FALSE;
210*6236dae4SAndroid Build Coastguard Worker 
211*6236dae4SAndroid Build Coastguard Worker   find_pos += strlen(key);
212*6236dae4SAndroid Build Coastguard Worker 
213*6236dae4SAndroid Build Coastguard Worker   for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
214*6236dae4SAndroid Build Coastguard Worker     value[i] = *find_pos++;
215*6236dae4SAndroid Build Coastguard Worker   value[i] = '\0';
216*6236dae4SAndroid Build Coastguard Worker 
217*6236dae4SAndroid Build Coastguard Worker   return TRUE;
218*6236dae4SAndroid Build Coastguard Worker }
219*6236dae4SAndroid Build Coastguard Worker 
auth_digest_get_qop_values(const char * options,int * value)220*6236dae4SAndroid Build Coastguard Worker static CURLcode auth_digest_get_qop_values(const char *options, int *value)
221*6236dae4SAndroid Build Coastguard Worker {
222*6236dae4SAndroid Build Coastguard Worker   char *tmp;
223*6236dae4SAndroid Build Coastguard Worker   char *token;
224*6236dae4SAndroid Build Coastguard Worker   char *tok_buf = NULL;
225*6236dae4SAndroid Build Coastguard Worker 
226*6236dae4SAndroid Build Coastguard Worker   /* Initialise the output */
227*6236dae4SAndroid Build Coastguard Worker   *value = 0;
228*6236dae4SAndroid Build Coastguard Worker 
229*6236dae4SAndroid Build Coastguard Worker   /* Tokenise the list of qop values. Use a temporary clone of the buffer since
230*6236dae4SAndroid Build Coastguard Worker      strtok_r() ruins it. */
231*6236dae4SAndroid Build Coastguard Worker   tmp = strdup(options);
232*6236dae4SAndroid Build Coastguard Worker   if(!tmp)
233*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
234*6236dae4SAndroid Build Coastguard Worker 
235*6236dae4SAndroid Build Coastguard Worker   token = strtok_r(tmp, ",", &tok_buf);
236*6236dae4SAndroid Build Coastguard Worker   while(token) {
237*6236dae4SAndroid Build Coastguard Worker     if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
238*6236dae4SAndroid Build Coastguard Worker       *value |= DIGEST_QOP_VALUE_AUTH;
239*6236dae4SAndroid Build Coastguard Worker     else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
240*6236dae4SAndroid Build Coastguard Worker       *value |= DIGEST_QOP_VALUE_AUTH_INT;
241*6236dae4SAndroid Build Coastguard Worker     else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
242*6236dae4SAndroid Build Coastguard Worker       *value |= DIGEST_QOP_VALUE_AUTH_CONF;
243*6236dae4SAndroid Build Coastguard Worker 
244*6236dae4SAndroid Build Coastguard Worker     token = strtok_r(NULL, ",", &tok_buf);
245*6236dae4SAndroid Build Coastguard Worker   }
246*6236dae4SAndroid Build Coastguard Worker 
247*6236dae4SAndroid Build Coastguard Worker   free(tmp);
248*6236dae4SAndroid Build Coastguard Worker 
249*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
250*6236dae4SAndroid Build Coastguard Worker }
251*6236dae4SAndroid Build Coastguard Worker 
252*6236dae4SAndroid Build Coastguard Worker /*
253*6236dae4SAndroid Build Coastguard Worker  * auth_decode_digest_md5_message()
254*6236dae4SAndroid Build Coastguard Worker  *
255*6236dae4SAndroid Build Coastguard Worker  * This is used internally to decode an already encoded DIGEST-MD5 challenge
256*6236dae4SAndroid Build Coastguard Worker  * message into the separate attributes.
257*6236dae4SAndroid Build Coastguard Worker  *
258*6236dae4SAndroid Build Coastguard Worker  * Parameters:
259*6236dae4SAndroid Build Coastguard Worker  *
260*6236dae4SAndroid Build Coastguard Worker  * chlgref [in]     - The challenge message.
261*6236dae4SAndroid Build Coastguard Worker  * nonce   [in/out] - The buffer where the nonce will be stored.
262*6236dae4SAndroid Build Coastguard Worker  * nlen    [in]     - The length of the nonce buffer.
263*6236dae4SAndroid Build Coastguard Worker  * realm   [in/out] - The buffer where the realm will be stored.
264*6236dae4SAndroid Build Coastguard Worker  * rlen    [in]     - The length of the realm buffer.
265*6236dae4SAndroid Build Coastguard Worker  * alg     [in/out] - The buffer where the algorithm will be stored.
266*6236dae4SAndroid Build Coastguard Worker  * alen    [in]     - The length of the algorithm buffer.
267*6236dae4SAndroid Build Coastguard Worker  * qop     [in/out] - The buffer where the qop-options will be stored.
268*6236dae4SAndroid Build Coastguard Worker  * qlen    [in]     - The length of the qop buffer.
269*6236dae4SAndroid Build Coastguard Worker  *
270*6236dae4SAndroid Build Coastguard Worker  * Returns CURLE_OK on success.
271*6236dae4SAndroid Build Coastguard Worker  */
auth_decode_digest_md5_message(const struct bufref * chlgref,char * nonce,size_t nlen,char * realm,size_t rlen,char * alg,size_t alen,char * qop,size_t qlen)272*6236dae4SAndroid Build Coastguard Worker static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref,
273*6236dae4SAndroid Build Coastguard Worker                                                char *nonce, size_t nlen,
274*6236dae4SAndroid Build Coastguard Worker                                                char *realm, size_t rlen,
275*6236dae4SAndroid Build Coastguard Worker                                                char *alg, size_t alen,
276*6236dae4SAndroid Build Coastguard Worker                                                char *qop, size_t qlen)
277*6236dae4SAndroid Build Coastguard Worker {
278*6236dae4SAndroid Build Coastguard Worker   const char *chlg = (const char *) Curl_bufref_ptr(chlgref);
279*6236dae4SAndroid Build Coastguard Worker 
280*6236dae4SAndroid Build Coastguard Worker   /* Ensure we have a valid challenge message */
281*6236dae4SAndroid Build Coastguard Worker   if(!Curl_bufref_len(chlgref))
282*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
283*6236dae4SAndroid Build Coastguard Worker 
284*6236dae4SAndroid Build Coastguard Worker   /* Retrieve nonce string from the challenge */
285*6236dae4SAndroid Build Coastguard Worker   if(!auth_digest_get_key_value(chlg, "nonce=\"", nonce, nlen, '\"'))
286*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
287*6236dae4SAndroid Build Coastguard Worker 
288*6236dae4SAndroid Build Coastguard Worker   /* Retrieve realm string from the challenge */
289*6236dae4SAndroid Build Coastguard Worker   if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
290*6236dae4SAndroid Build Coastguard Worker     /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
291*6236dae4SAndroid Build Coastguard Worker     *realm = '\0';
292*6236dae4SAndroid Build Coastguard Worker   }
293*6236dae4SAndroid Build Coastguard Worker 
294*6236dae4SAndroid Build Coastguard Worker   /* Retrieve algorithm string from the challenge */
295*6236dae4SAndroid Build Coastguard Worker   if(!auth_digest_get_key_value(chlg, "algorithm=", alg, alen, ','))
296*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
297*6236dae4SAndroid Build Coastguard Worker 
298*6236dae4SAndroid Build Coastguard Worker   /* Retrieve qop-options string from the challenge */
299*6236dae4SAndroid Build Coastguard Worker   if(!auth_digest_get_key_value(chlg, "qop=\"", qop, qlen, '\"'))
300*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
301*6236dae4SAndroid Build Coastguard Worker 
302*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
303*6236dae4SAndroid Build Coastguard Worker }
304*6236dae4SAndroid Build Coastguard Worker 
305*6236dae4SAndroid Build Coastguard Worker /*
306*6236dae4SAndroid Build Coastguard Worker  * Curl_auth_is_digest_supported()
307*6236dae4SAndroid Build Coastguard Worker  *
308*6236dae4SAndroid Build Coastguard Worker  * This is used to evaluate if DIGEST is supported.
309*6236dae4SAndroid Build Coastguard Worker  *
310*6236dae4SAndroid Build Coastguard Worker  * Parameters: None
311*6236dae4SAndroid Build Coastguard Worker  *
312*6236dae4SAndroid Build Coastguard Worker  * Returns TRUE as DIGEST as handled by libcurl.
313*6236dae4SAndroid Build Coastguard Worker  */
Curl_auth_is_digest_supported(void)314*6236dae4SAndroid Build Coastguard Worker bool Curl_auth_is_digest_supported(void)
315*6236dae4SAndroid Build Coastguard Worker {
316*6236dae4SAndroid Build Coastguard Worker   return TRUE;
317*6236dae4SAndroid Build Coastguard Worker }
318*6236dae4SAndroid Build Coastguard Worker 
319*6236dae4SAndroid Build Coastguard Worker /*
320*6236dae4SAndroid Build Coastguard Worker  * Curl_auth_create_digest_md5_message()
321*6236dae4SAndroid Build Coastguard Worker  *
322*6236dae4SAndroid Build Coastguard Worker  * This is used to generate an already encoded DIGEST-MD5 response message
323*6236dae4SAndroid Build Coastguard Worker  * ready for sending to the recipient.
324*6236dae4SAndroid Build Coastguard Worker  *
325*6236dae4SAndroid Build Coastguard Worker  * Parameters:
326*6236dae4SAndroid Build Coastguard Worker  *
327*6236dae4SAndroid Build Coastguard Worker  * data    [in]     - The session handle.
328*6236dae4SAndroid Build Coastguard Worker  * chlg    [in]     - The challenge message.
329*6236dae4SAndroid Build Coastguard Worker  * userp   [in]     - The username.
330*6236dae4SAndroid Build Coastguard Worker  * passwdp [in]     - The user's password.
331*6236dae4SAndroid Build Coastguard Worker  * service [in]     - The service type such as http, smtp, pop or imap.
332*6236dae4SAndroid Build Coastguard Worker  * out     [out]    - The result storage.
333*6236dae4SAndroid Build Coastguard Worker  *
334*6236dae4SAndroid Build Coastguard Worker  * Returns CURLE_OK on success.
335*6236dae4SAndroid Build Coastguard Worker  */
Curl_auth_create_digest_md5_message(struct Curl_easy * data,const struct bufref * chlg,const char * userp,const char * passwdp,const char * service,struct bufref * out)336*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
337*6236dae4SAndroid Build Coastguard Worker                                              const struct bufref *chlg,
338*6236dae4SAndroid Build Coastguard Worker                                              const char *userp,
339*6236dae4SAndroid Build Coastguard Worker                                              const char *passwdp,
340*6236dae4SAndroid Build Coastguard Worker                                              const char *service,
341*6236dae4SAndroid Build Coastguard Worker                                              struct bufref *out)
342*6236dae4SAndroid Build Coastguard Worker {
343*6236dae4SAndroid Build Coastguard Worker   size_t i;
344*6236dae4SAndroid Build Coastguard Worker   struct MD5_context *ctxt;
345*6236dae4SAndroid Build Coastguard Worker   char *response = NULL;
346*6236dae4SAndroid Build Coastguard Worker   unsigned char digest[MD5_DIGEST_LEN];
347*6236dae4SAndroid Build Coastguard Worker   char HA1_hex[2 * MD5_DIGEST_LEN + 1];
348*6236dae4SAndroid Build Coastguard Worker   char HA2_hex[2 * MD5_DIGEST_LEN + 1];
349*6236dae4SAndroid Build Coastguard Worker   char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
350*6236dae4SAndroid Build Coastguard Worker   char nonce[64];
351*6236dae4SAndroid Build Coastguard Worker   char realm[128];
352*6236dae4SAndroid Build Coastguard Worker   char algorithm[64];
353*6236dae4SAndroid Build Coastguard Worker   char qop_options[64];
354*6236dae4SAndroid Build Coastguard Worker   int qop_values;
355*6236dae4SAndroid Build Coastguard Worker   char cnonce[33];
356*6236dae4SAndroid Build Coastguard Worker   char nonceCount[] = "00000001";
357*6236dae4SAndroid Build Coastguard Worker   char method[]     = "AUTHENTICATE";
358*6236dae4SAndroid Build Coastguard Worker   char qop[]        = DIGEST_QOP_VALUE_STRING_AUTH;
359*6236dae4SAndroid Build Coastguard Worker   char *spn         = NULL;
360*6236dae4SAndroid Build Coastguard Worker 
361*6236dae4SAndroid Build Coastguard Worker   /* Decode the challenge message */
362*6236dae4SAndroid Build Coastguard Worker   CURLcode result = auth_decode_digest_md5_message(chlg,
363*6236dae4SAndroid Build Coastguard Worker                                                    nonce, sizeof(nonce),
364*6236dae4SAndroid Build Coastguard Worker                                                    realm, sizeof(realm),
365*6236dae4SAndroid Build Coastguard Worker                                                    algorithm,
366*6236dae4SAndroid Build Coastguard Worker                                                    sizeof(algorithm),
367*6236dae4SAndroid Build Coastguard Worker                                                    qop_options,
368*6236dae4SAndroid Build Coastguard Worker                                                    sizeof(qop_options));
369*6236dae4SAndroid Build Coastguard Worker   if(result)
370*6236dae4SAndroid Build Coastguard Worker     return result;
371*6236dae4SAndroid Build Coastguard Worker 
372*6236dae4SAndroid Build Coastguard Worker   /* We only support md5 sessions */
373*6236dae4SAndroid Build Coastguard Worker   if(strcmp(algorithm, "md5-sess") != 0)
374*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
375*6236dae4SAndroid Build Coastguard Worker 
376*6236dae4SAndroid Build Coastguard Worker   /* Get the qop-values from the qop-options */
377*6236dae4SAndroid Build Coastguard Worker   result = auth_digest_get_qop_values(qop_options, &qop_values);
378*6236dae4SAndroid Build Coastguard Worker   if(result)
379*6236dae4SAndroid Build Coastguard Worker     return result;
380*6236dae4SAndroid Build Coastguard Worker 
381*6236dae4SAndroid Build Coastguard Worker   /* We only support auth quality-of-protection */
382*6236dae4SAndroid Build Coastguard Worker   if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
383*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
384*6236dae4SAndroid Build Coastguard Worker 
385*6236dae4SAndroid Build Coastguard Worker   /* Generate 32 random hex chars, 32 bytes + 1 null-termination */
386*6236dae4SAndroid Build Coastguard Worker   result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce));
387*6236dae4SAndroid Build Coastguard Worker   if(result)
388*6236dae4SAndroid Build Coastguard Worker     return result;
389*6236dae4SAndroid Build Coastguard Worker 
390*6236dae4SAndroid Build Coastguard Worker   /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
391*6236dae4SAndroid Build Coastguard Worker   ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
392*6236dae4SAndroid Build Coastguard Worker   if(!ctxt)
393*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
394*6236dae4SAndroid Build Coastguard Worker 
395*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) userp,
396*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(userp)));
397*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
398*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) realm,
399*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(realm)));
400*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
401*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
402*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(passwdp)));
403*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_final(ctxt, digest);
404*6236dae4SAndroid Build Coastguard Worker 
405*6236dae4SAndroid Build Coastguard Worker   ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
406*6236dae4SAndroid Build Coastguard Worker   if(!ctxt)
407*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
408*6236dae4SAndroid Build Coastguard Worker 
409*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
410*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
411*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) nonce,
412*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(nonce)));
413*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
414*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
415*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(cnonce)));
416*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_final(ctxt, digest);
417*6236dae4SAndroid Build Coastguard Worker 
418*6236dae4SAndroid Build Coastguard Worker   /* Convert calculated 16 octet hex into 32 bytes string */
419*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < MD5_DIGEST_LEN; i++)
420*6236dae4SAndroid Build Coastguard Worker     msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
421*6236dae4SAndroid Build Coastguard Worker 
422*6236dae4SAndroid Build Coastguard Worker   /* Generate our SPN */
423*6236dae4SAndroid Build Coastguard Worker   spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
424*6236dae4SAndroid Build Coastguard Worker   if(!spn)
425*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
426*6236dae4SAndroid Build Coastguard Worker 
427*6236dae4SAndroid Build Coastguard Worker   /* Calculate H(A2) */
428*6236dae4SAndroid Build Coastguard Worker   ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
429*6236dae4SAndroid Build Coastguard Worker   if(!ctxt) {
430*6236dae4SAndroid Build Coastguard Worker     free(spn);
431*6236dae4SAndroid Build Coastguard Worker 
432*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
433*6236dae4SAndroid Build Coastguard Worker   }
434*6236dae4SAndroid Build Coastguard Worker 
435*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) method,
436*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(method)));
437*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
438*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) spn,
439*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(spn)));
440*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_final(ctxt, digest);
441*6236dae4SAndroid Build Coastguard Worker 
442*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < MD5_DIGEST_LEN; i++)
443*6236dae4SAndroid Build Coastguard Worker     msnprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
444*6236dae4SAndroid Build Coastguard Worker 
445*6236dae4SAndroid Build Coastguard Worker   /* Now calculate the response hash */
446*6236dae4SAndroid Build Coastguard Worker   ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
447*6236dae4SAndroid Build Coastguard Worker   if(!ctxt) {
448*6236dae4SAndroid Build Coastguard Worker     free(spn);
449*6236dae4SAndroid Build Coastguard Worker 
450*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
451*6236dae4SAndroid Build Coastguard Worker   }
452*6236dae4SAndroid Build Coastguard Worker 
453*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
454*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
455*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) nonce,
456*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(nonce)));
457*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
458*6236dae4SAndroid Build Coastguard Worker 
459*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
460*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(nonceCount)));
461*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
462*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
463*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(cnonce)));
464*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
465*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) qop,
466*6236dae4SAndroid Build Coastguard Worker                   curlx_uztoui(strlen(qop)));
467*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
468*6236dae4SAndroid Build Coastguard Worker 
469*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
470*6236dae4SAndroid Build Coastguard Worker   Curl_MD5_final(ctxt, digest);
471*6236dae4SAndroid Build Coastguard Worker 
472*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < MD5_DIGEST_LEN; i++)
473*6236dae4SAndroid Build Coastguard Worker     msnprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
474*6236dae4SAndroid Build Coastguard Worker 
475*6236dae4SAndroid Build Coastguard Worker   /* Generate the response */
476*6236dae4SAndroid Build Coastguard Worker   response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
477*6236dae4SAndroid Build Coastguard Worker                      "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
478*6236dae4SAndroid Build Coastguard Worker                      "qop=%s",
479*6236dae4SAndroid Build Coastguard Worker                      userp, realm, nonce,
480*6236dae4SAndroid Build Coastguard Worker                      cnonce, nonceCount, spn, resp_hash_hex, qop);
481*6236dae4SAndroid Build Coastguard Worker   free(spn);
482*6236dae4SAndroid Build Coastguard Worker   if(!response)
483*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
484*6236dae4SAndroid Build Coastguard Worker 
485*6236dae4SAndroid Build Coastguard Worker   /* Return the response. */
486*6236dae4SAndroid Build Coastguard Worker   Curl_bufref_set(out, response, strlen(response), curl_free);
487*6236dae4SAndroid Build Coastguard Worker   return result;
488*6236dae4SAndroid Build Coastguard Worker }
489*6236dae4SAndroid Build Coastguard Worker 
490*6236dae4SAndroid Build Coastguard Worker /*
491*6236dae4SAndroid Build Coastguard Worker  * Curl_auth_decode_digest_http_message()
492*6236dae4SAndroid Build Coastguard Worker  *
493*6236dae4SAndroid Build Coastguard Worker  * This is used to decode an HTTP DIGEST challenge message into the separate
494*6236dae4SAndroid Build Coastguard Worker  * attributes.
495*6236dae4SAndroid Build Coastguard Worker  *
496*6236dae4SAndroid Build Coastguard Worker  * Parameters:
497*6236dae4SAndroid Build Coastguard Worker  *
498*6236dae4SAndroid Build Coastguard Worker  * chlg    [in]     - The challenge message.
499*6236dae4SAndroid Build Coastguard Worker  * digest  [in/out] - The digest data struct being used and modified.
500*6236dae4SAndroid Build Coastguard Worker  *
501*6236dae4SAndroid Build Coastguard Worker  * Returns CURLE_OK on success.
502*6236dae4SAndroid Build Coastguard Worker  */
Curl_auth_decode_digest_http_message(const char * chlg,struct digestdata * digest)503*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
504*6236dae4SAndroid Build Coastguard Worker                                               struct digestdata *digest)
505*6236dae4SAndroid Build Coastguard Worker {
506*6236dae4SAndroid Build Coastguard Worker   bool before = FALSE; /* got a nonce before */
507*6236dae4SAndroid Build Coastguard Worker   bool foundAuth = FALSE;
508*6236dae4SAndroid Build Coastguard Worker   bool foundAuthInt = FALSE;
509*6236dae4SAndroid Build Coastguard Worker   char *token = NULL;
510*6236dae4SAndroid Build Coastguard Worker   char *tmp = NULL;
511*6236dae4SAndroid Build Coastguard Worker 
512*6236dae4SAndroid Build Coastguard Worker   /* If we already have received a nonce, keep that in mind */
513*6236dae4SAndroid Build Coastguard Worker   if(digest->nonce)
514*6236dae4SAndroid Build Coastguard Worker     before = TRUE;
515*6236dae4SAndroid Build Coastguard Worker 
516*6236dae4SAndroid Build Coastguard Worker   /* Clean up any former leftovers and initialise to defaults */
517*6236dae4SAndroid Build Coastguard Worker   Curl_auth_digest_cleanup(digest);
518*6236dae4SAndroid Build Coastguard Worker 
519*6236dae4SAndroid Build Coastguard Worker   for(;;) {
520*6236dae4SAndroid Build Coastguard Worker     char value[DIGEST_MAX_VALUE_LENGTH];
521*6236dae4SAndroid Build Coastguard Worker     char content[DIGEST_MAX_CONTENT_LENGTH];
522*6236dae4SAndroid Build Coastguard Worker 
523*6236dae4SAndroid Build Coastguard Worker     /* Pass all additional spaces here */
524*6236dae4SAndroid Build Coastguard Worker     while(*chlg && ISBLANK(*chlg))
525*6236dae4SAndroid Build Coastguard Worker       chlg++;
526*6236dae4SAndroid Build Coastguard Worker 
527*6236dae4SAndroid Build Coastguard Worker     /* Extract a value=content pair */
528*6236dae4SAndroid Build Coastguard Worker     if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
529*6236dae4SAndroid Build Coastguard Worker       if(strcasecompare(value, "nonce")) {
530*6236dae4SAndroid Build Coastguard Worker         free(digest->nonce);
531*6236dae4SAndroid Build Coastguard Worker         digest->nonce = strdup(content);
532*6236dae4SAndroid Build Coastguard Worker         if(!digest->nonce)
533*6236dae4SAndroid Build Coastguard Worker           return CURLE_OUT_OF_MEMORY;
534*6236dae4SAndroid Build Coastguard Worker       }
535*6236dae4SAndroid Build Coastguard Worker       else if(strcasecompare(value, "stale")) {
536*6236dae4SAndroid Build Coastguard Worker         if(strcasecompare(content, "true")) {
537*6236dae4SAndroid Build Coastguard Worker           digest->stale = TRUE;
538*6236dae4SAndroid Build Coastguard Worker           digest->nc = 1; /* we make a new nonce now */
539*6236dae4SAndroid Build Coastguard Worker         }
540*6236dae4SAndroid Build Coastguard Worker       }
541*6236dae4SAndroid Build Coastguard Worker       else if(strcasecompare(value, "realm")) {
542*6236dae4SAndroid Build Coastguard Worker         free(digest->realm);
543*6236dae4SAndroid Build Coastguard Worker         digest->realm = strdup(content);
544*6236dae4SAndroid Build Coastguard Worker         if(!digest->realm)
545*6236dae4SAndroid Build Coastguard Worker           return CURLE_OUT_OF_MEMORY;
546*6236dae4SAndroid Build Coastguard Worker       }
547*6236dae4SAndroid Build Coastguard Worker       else if(strcasecompare(value, "opaque")) {
548*6236dae4SAndroid Build Coastguard Worker         free(digest->opaque);
549*6236dae4SAndroid Build Coastguard Worker         digest->opaque = strdup(content);
550*6236dae4SAndroid Build Coastguard Worker         if(!digest->opaque)
551*6236dae4SAndroid Build Coastguard Worker           return CURLE_OUT_OF_MEMORY;
552*6236dae4SAndroid Build Coastguard Worker       }
553*6236dae4SAndroid Build Coastguard Worker       else if(strcasecompare(value, "qop")) {
554*6236dae4SAndroid Build Coastguard Worker         char *tok_buf = NULL;
555*6236dae4SAndroid Build Coastguard Worker         /* Tokenize the list and choose auth if possible, use a temporary
556*6236dae4SAndroid Build Coastguard Worker            clone of the buffer since strtok_r() ruins it */
557*6236dae4SAndroid Build Coastguard Worker         tmp = strdup(content);
558*6236dae4SAndroid Build Coastguard Worker         if(!tmp)
559*6236dae4SAndroid Build Coastguard Worker           return CURLE_OUT_OF_MEMORY;
560*6236dae4SAndroid Build Coastguard Worker 
561*6236dae4SAndroid Build Coastguard Worker         token = strtok_r(tmp, ",", &tok_buf);
562*6236dae4SAndroid Build Coastguard Worker         while(token) {
563*6236dae4SAndroid Build Coastguard Worker           /* Pass additional spaces here */
564*6236dae4SAndroid Build Coastguard Worker           while(*token && ISBLANK(*token))
565*6236dae4SAndroid Build Coastguard Worker             token++;
566*6236dae4SAndroid Build Coastguard Worker           if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
567*6236dae4SAndroid Build Coastguard Worker             foundAuth = TRUE;
568*6236dae4SAndroid Build Coastguard Worker           }
569*6236dae4SAndroid Build Coastguard Worker           else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
570*6236dae4SAndroid Build Coastguard Worker             foundAuthInt = TRUE;
571*6236dae4SAndroid Build Coastguard Worker           }
572*6236dae4SAndroid Build Coastguard Worker           token = strtok_r(NULL, ",", &tok_buf);
573*6236dae4SAndroid Build Coastguard Worker         }
574*6236dae4SAndroid Build Coastguard Worker 
575*6236dae4SAndroid Build Coastguard Worker         free(tmp);
576*6236dae4SAndroid Build Coastguard Worker 
577*6236dae4SAndroid Build Coastguard Worker         /* Select only auth or auth-int. Otherwise, ignore */
578*6236dae4SAndroid Build Coastguard Worker         if(foundAuth) {
579*6236dae4SAndroid Build Coastguard Worker           free(digest->qop);
580*6236dae4SAndroid Build Coastguard Worker           digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH);
581*6236dae4SAndroid Build Coastguard Worker           if(!digest->qop)
582*6236dae4SAndroid Build Coastguard Worker             return CURLE_OUT_OF_MEMORY;
583*6236dae4SAndroid Build Coastguard Worker         }
584*6236dae4SAndroid Build Coastguard Worker         else if(foundAuthInt) {
585*6236dae4SAndroid Build Coastguard Worker           free(digest->qop);
586*6236dae4SAndroid Build Coastguard Worker           digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT);
587*6236dae4SAndroid Build Coastguard Worker           if(!digest->qop)
588*6236dae4SAndroid Build Coastguard Worker             return CURLE_OUT_OF_MEMORY;
589*6236dae4SAndroid Build Coastguard Worker         }
590*6236dae4SAndroid Build Coastguard Worker       }
591*6236dae4SAndroid Build Coastguard Worker       else if(strcasecompare(value, "algorithm")) {
592*6236dae4SAndroid Build Coastguard Worker         free(digest->algorithm);
593*6236dae4SAndroid Build Coastguard Worker         digest->algorithm = strdup(content);
594*6236dae4SAndroid Build Coastguard Worker         if(!digest->algorithm)
595*6236dae4SAndroid Build Coastguard Worker           return CURLE_OUT_OF_MEMORY;
596*6236dae4SAndroid Build Coastguard Worker 
597*6236dae4SAndroid Build Coastguard Worker         if(strcasecompare(content, "MD5-sess"))
598*6236dae4SAndroid Build Coastguard Worker           digest->algo = ALGO_MD5SESS;
599*6236dae4SAndroid Build Coastguard Worker         else if(strcasecompare(content, "MD5"))
600*6236dae4SAndroid Build Coastguard Worker           digest->algo = ALGO_MD5;
601*6236dae4SAndroid Build Coastguard Worker         else if(strcasecompare(content, "SHA-256"))
602*6236dae4SAndroid Build Coastguard Worker           digest->algo = ALGO_SHA256;
603*6236dae4SAndroid Build Coastguard Worker         else if(strcasecompare(content, "SHA-256-SESS"))
604*6236dae4SAndroid Build Coastguard Worker           digest->algo = ALGO_SHA256SESS;
605*6236dae4SAndroid Build Coastguard Worker         else if(strcasecompare(content, "SHA-512-256")) {
606*6236dae4SAndroid Build Coastguard Worker #ifdef CURL_HAVE_SHA512_256
607*6236dae4SAndroid Build Coastguard Worker           digest->algo = ALGO_SHA512_256;
608*6236dae4SAndroid Build Coastguard Worker #else  /* ! CURL_HAVE_SHA512_256 */
609*6236dae4SAndroid Build Coastguard Worker           return CURLE_NOT_BUILT_IN;
610*6236dae4SAndroid Build Coastguard Worker #endif /* ! CURL_HAVE_SHA512_256 */
611*6236dae4SAndroid Build Coastguard Worker         }
612*6236dae4SAndroid Build Coastguard Worker         else if(strcasecompare(content, "SHA-512-256-SESS")) {
613*6236dae4SAndroid Build Coastguard Worker #ifdef CURL_HAVE_SHA512_256
614*6236dae4SAndroid Build Coastguard Worker           digest->algo = ALGO_SHA512_256SESS;
615*6236dae4SAndroid Build Coastguard Worker #else  /* ! CURL_HAVE_SHA512_256 */
616*6236dae4SAndroid Build Coastguard Worker           return CURLE_NOT_BUILT_IN;
617*6236dae4SAndroid Build Coastguard Worker #endif /* ! CURL_HAVE_SHA512_256 */
618*6236dae4SAndroid Build Coastguard Worker         }
619*6236dae4SAndroid Build Coastguard Worker         else
620*6236dae4SAndroid Build Coastguard Worker           return CURLE_BAD_CONTENT_ENCODING;
621*6236dae4SAndroid Build Coastguard Worker       }
622*6236dae4SAndroid Build Coastguard Worker       else if(strcasecompare(value, "userhash")) {
623*6236dae4SAndroid Build Coastguard Worker         if(strcasecompare(content, "true")) {
624*6236dae4SAndroid Build Coastguard Worker           digest->userhash = TRUE;
625*6236dae4SAndroid Build Coastguard Worker         }
626*6236dae4SAndroid Build Coastguard Worker       }
627*6236dae4SAndroid Build Coastguard Worker       else {
628*6236dae4SAndroid Build Coastguard Worker         /* Unknown specifier, ignore it! */
629*6236dae4SAndroid Build Coastguard Worker       }
630*6236dae4SAndroid Build Coastguard Worker     }
631*6236dae4SAndroid Build Coastguard Worker     else
632*6236dae4SAndroid Build Coastguard Worker       break; /* We are done here */
633*6236dae4SAndroid Build Coastguard Worker 
634*6236dae4SAndroid Build Coastguard Worker     /* Pass all additional spaces here */
635*6236dae4SAndroid Build Coastguard Worker     while(*chlg && ISBLANK(*chlg))
636*6236dae4SAndroid Build Coastguard Worker       chlg++;
637*6236dae4SAndroid Build Coastguard Worker 
638*6236dae4SAndroid Build Coastguard Worker     /* Allow the list to be comma-separated */
639*6236dae4SAndroid Build Coastguard Worker     if(',' == *chlg)
640*6236dae4SAndroid Build Coastguard Worker       chlg++;
641*6236dae4SAndroid Build Coastguard Worker   }
642*6236dae4SAndroid Build Coastguard Worker 
643*6236dae4SAndroid Build Coastguard Worker   /* We had a nonce since before, and we got another one now without
644*6236dae4SAndroid Build Coastguard Worker      'stale=true'. This means we provided bad credentials in the previous
645*6236dae4SAndroid Build Coastguard Worker      request */
646*6236dae4SAndroid Build Coastguard Worker   if(before && !digest->stale)
647*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
648*6236dae4SAndroid Build Coastguard Worker 
649*6236dae4SAndroid Build Coastguard Worker   /* We got this header without a nonce, that is a bad Digest line! */
650*6236dae4SAndroid Build Coastguard Worker   if(!digest->nonce)
651*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
652*6236dae4SAndroid Build Coastguard Worker 
653*6236dae4SAndroid Build Coastguard Worker   /* "<algo>-sess" protocol versions require "auth" or "auth-int" qop */
654*6236dae4SAndroid Build Coastguard Worker   if(!digest->qop && (digest->algo & SESSION_ALGO))
655*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
656*6236dae4SAndroid Build Coastguard Worker 
657*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
658*6236dae4SAndroid Build Coastguard Worker }
659*6236dae4SAndroid Build Coastguard Worker 
660*6236dae4SAndroid Build Coastguard Worker /*
661*6236dae4SAndroid Build Coastguard Worker  * auth_create_digest_http_message()
662*6236dae4SAndroid Build Coastguard Worker  *
663*6236dae4SAndroid Build Coastguard Worker  * This is used to generate an HTTP DIGEST response message ready for sending
664*6236dae4SAndroid Build Coastguard Worker  * to the recipient.
665*6236dae4SAndroid Build Coastguard Worker  *
666*6236dae4SAndroid Build Coastguard Worker  * Parameters:
667*6236dae4SAndroid Build Coastguard Worker  *
668*6236dae4SAndroid Build Coastguard Worker  * data    [in]     - The session handle.
669*6236dae4SAndroid Build Coastguard Worker  * userp   [in]     - The username.
670*6236dae4SAndroid Build Coastguard Worker  * passwdp [in]     - The user's password.
671*6236dae4SAndroid Build Coastguard Worker  * request [in]     - The HTTP request.
672*6236dae4SAndroid Build Coastguard Worker  * uripath [in]     - The path of the HTTP uri.
673*6236dae4SAndroid Build Coastguard Worker  * digest  [in/out] - The digest data struct being used and modified.
674*6236dae4SAndroid Build Coastguard Worker  * outptr  [in/out] - The address where a pointer to newly allocated memory
675*6236dae4SAndroid Build Coastguard Worker  *                    holding the result will be stored upon completion.
676*6236dae4SAndroid Build Coastguard Worker  * outlen  [out]    - The length of the output message.
677*6236dae4SAndroid Build Coastguard Worker  *
678*6236dae4SAndroid Build Coastguard Worker  * Returns CURLE_OK on success.
679*6236dae4SAndroid Build Coastguard Worker  */
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 *),CURLcode (* hash)(unsigned char *,const unsigned char *,const size_t))680*6236dae4SAndroid Build Coastguard Worker static CURLcode auth_create_digest_http_message(
681*6236dae4SAndroid Build Coastguard Worker                   struct Curl_easy *data,
682*6236dae4SAndroid Build Coastguard Worker                   const char *userp,
683*6236dae4SAndroid Build Coastguard Worker                   const char *passwdp,
684*6236dae4SAndroid Build Coastguard Worker                   const unsigned char *request,
685*6236dae4SAndroid Build Coastguard Worker                   const unsigned char *uripath,
686*6236dae4SAndroid Build Coastguard Worker                   struct digestdata *digest,
687*6236dae4SAndroid Build Coastguard Worker                   char **outptr, size_t *outlen,
688*6236dae4SAndroid Build Coastguard Worker                   void (*convert_to_ascii)(unsigned char *, unsigned char *),
689*6236dae4SAndroid Build Coastguard Worker                   CURLcode (*hash)(unsigned char *, const unsigned char *,
690*6236dae4SAndroid Build Coastguard Worker                                    const size_t))
691*6236dae4SAndroid Build Coastguard Worker {
692*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
693*6236dae4SAndroid Build Coastguard Worker   unsigned char hashbuf[32]; /* 32 bytes/256 bits */
694*6236dae4SAndroid Build Coastguard Worker   unsigned char request_digest[65];
695*6236dae4SAndroid Build Coastguard Worker   unsigned char ha1[65];    /* 64 digits and 1 zero byte */
696*6236dae4SAndroid Build Coastguard Worker   unsigned char ha2[65];    /* 64 digits and 1 zero byte */
697*6236dae4SAndroid Build Coastguard Worker   char userh[65];
698*6236dae4SAndroid Build Coastguard Worker   char *cnonce = NULL;
699*6236dae4SAndroid Build Coastguard Worker   size_t cnonce_sz = 0;
700*6236dae4SAndroid Build Coastguard Worker   char *userp_quoted;
701*6236dae4SAndroid Build Coastguard Worker   char *realm_quoted;
702*6236dae4SAndroid Build Coastguard Worker   char *nonce_quoted;
703*6236dae4SAndroid Build Coastguard Worker   char *response = NULL;
704*6236dae4SAndroid Build Coastguard Worker   char *hashthis = NULL;
705*6236dae4SAndroid Build Coastguard Worker   char *tmp = NULL;
706*6236dae4SAndroid Build Coastguard Worker 
707*6236dae4SAndroid Build Coastguard Worker   memset(hashbuf, 0, sizeof(hashbuf));
708*6236dae4SAndroid Build Coastguard Worker   if(!digest->nc)
709*6236dae4SAndroid Build Coastguard Worker     digest->nc = 1;
710*6236dae4SAndroid Build Coastguard Worker 
711*6236dae4SAndroid Build Coastguard Worker   if(!digest->cnonce) {
712*6236dae4SAndroid Build Coastguard Worker     char cnoncebuf[33];
713*6236dae4SAndroid Build Coastguard Worker     result = Curl_rand_hex(data, (unsigned char *)cnoncebuf,
714*6236dae4SAndroid Build Coastguard Worker                            sizeof(cnoncebuf));
715*6236dae4SAndroid Build Coastguard Worker     if(result)
716*6236dae4SAndroid Build Coastguard Worker       return result;
717*6236dae4SAndroid Build Coastguard Worker 
718*6236dae4SAndroid Build Coastguard Worker     result = Curl_base64_encode(cnoncebuf, strlen(cnoncebuf),
719*6236dae4SAndroid Build Coastguard Worker                                 &cnonce, &cnonce_sz);
720*6236dae4SAndroid Build Coastguard Worker     if(result)
721*6236dae4SAndroid Build Coastguard Worker       return result;
722*6236dae4SAndroid Build Coastguard Worker 
723*6236dae4SAndroid Build Coastguard Worker     digest->cnonce = cnonce;
724*6236dae4SAndroid Build Coastguard Worker   }
725*6236dae4SAndroid Build Coastguard Worker 
726*6236dae4SAndroid Build Coastguard Worker   if(digest->userhash) {
727*6236dae4SAndroid Build Coastguard Worker     hashthis = aprintf("%s:%s", userp, digest->realm ? digest->realm : "");
728*6236dae4SAndroid Build Coastguard Worker     if(!hashthis)
729*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
730*6236dae4SAndroid Build Coastguard Worker 
731*6236dae4SAndroid Build Coastguard Worker     result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
732*6236dae4SAndroid Build Coastguard Worker     free(hashthis);
733*6236dae4SAndroid Build Coastguard Worker     if(result)
734*6236dae4SAndroid Build Coastguard Worker       return result;
735*6236dae4SAndroid Build Coastguard Worker     convert_to_ascii(hashbuf, (unsigned char *)userh);
736*6236dae4SAndroid Build Coastguard Worker   }
737*6236dae4SAndroid Build Coastguard Worker 
738*6236dae4SAndroid Build Coastguard Worker   /*
739*6236dae4SAndroid Build Coastguard Worker     If the algorithm is "MD5" or unspecified (which then defaults to MD5):
740*6236dae4SAndroid Build Coastguard Worker 
741*6236dae4SAndroid Build Coastguard Worker       A1 = unq(username-value) ":" unq(realm-value) ":" passwd
742*6236dae4SAndroid Build Coastguard Worker 
743*6236dae4SAndroid Build Coastguard Worker     If the algorithm is "MD5-sess" then:
744*6236dae4SAndroid Build Coastguard Worker 
745*6236dae4SAndroid Build Coastguard Worker       A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":"
746*6236dae4SAndroid Build Coastguard Worker            unq(nonce-value) ":" unq(cnonce-value)
747*6236dae4SAndroid Build Coastguard Worker   */
748*6236dae4SAndroid Build Coastguard Worker 
749*6236dae4SAndroid Build Coastguard Worker   hashthis = aprintf("%s:%s:%s", userp, digest->realm ? digest->realm : "",
750*6236dae4SAndroid Build Coastguard Worker                      passwdp);
751*6236dae4SAndroid Build Coastguard Worker   if(!hashthis)
752*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
753*6236dae4SAndroid Build Coastguard Worker 
754*6236dae4SAndroid Build Coastguard Worker   result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
755*6236dae4SAndroid Build Coastguard Worker   free(hashthis);
756*6236dae4SAndroid Build Coastguard Worker   if(result)
757*6236dae4SAndroid Build Coastguard Worker     return result;
758*6236dae4SAndroid Build Coastguard Worker   convert_to_ascii(hashbuf, ha1);
759*6236dae4SAndroid Build Coastguard Worker 
760*6236dae4SAndroid Build Coastguard Worker   if(digest->algo & SESSION_ALGO) {
761*6236dae4SAndroid Build Coastguard Worker     /* nonce and cnonce are OUTSIDE the hash */
762*6236dae4SAndroid Build Coastguard Worker     tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce);
763*6236dae4SAndroid Build Coastguard Worker     if(!tmp)
764*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
765*6236dae4SAndroid Build Coastguard Worker 
766*6236dae4SAndroid Build Coastguard Worker     result = hash(hashbuf, (unsigned char *) tmp, strlen(tmp));
767*6236dae4SAndroid Build Coastguard Worker     free(tmp);
768*6236dae4SAndroid Build Coastguard Worker     if(result)
769*6236dae4SAndroid Build Coastguard Worker       return result;
770*6236dae4SAndroid Build Coastguard Worker     convert_to_ascii(hashbuf, ha1);
771*6236dae4SAndroid Build Coastguard Worker   }
772*6236dae4SAndroid Build Coastguard Worker 
773*6236dae4SAndroid Build Coastguard Worker   /*
774*6236dae4SAndroid Build Coastguard Worker     If the "qop" directive's value is "auth" or is unspecified, then A2 is:
775*6236dae4SAndroid Build Coastguard Worker 
776*6236dae4SAndroid Build Coastguard Worker       A2 = Method ":" digest-uri-value
777*6236dae4SAndroid Build Coastguard Worker 
778*6236dae4SAndroid Build Coastguard Worker     If the "qop" value is "auth-int", then A2 is:
779*6236dae4SAndroid Build Coastguard Worker 
780*6236dae4SAndroid Build Coastguard Worker       A2 = Method ":" digest-uri-value ":" H(entity-body)
781*6236dae4SAndroid Build Coastguard Worker 
782*6236dae4SAndroid Build Coastguard Worker     (The "Method" value is the HTTP request method as specified in section
783*6236dae4SAndroid Build Coastguard Worker     5.1.1 of RFC 2616)
784*6236dae4SAndroid Build Coastguard Worker   */
785*6236dae4SAndroid Build Coastguard Worker 
786*6236dae4SAndroid Build Coastguard Worker   hashthis = aprintf("%s:%s", request, uripath);
787*6236dae4SAndroid Build Coastguard Worker   if(!hashthis)
788*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
789*6236dae4SAndroid Build Coastguard Worker 
790*6236dae4SAndroid Build Coastguard Worker   if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
791*6236dae4SAndroid Build Coastguard Worker     /* We do not support auth-int for PUT or POST */
792*6236dae4SAndroid Build Coastguard Worker     char hashed[65];
793*6236dae4SAndroid Build Coastguard Worker     char *hashthis2;
794*6236dae4SAndroid Build Coastguard Worker 
795*6236dae4SAndroid Build Coastguard Worker     result = hash(hashbuf, (const unsigned char *)"", 0);
796*6236dae4SAndroid Build Coastguard Worker     if(result) {
797*6236dae4SAndroid Build Coastguard Worker       free(hashthis);
798*6236dae4SAndroid Build Coastguard Worker       return result;
799*6236dae4SAndroid Build Coastguard Worker     }
800*6236dae4SAndroid Build Coastguard Worker     convert_to_ascii(hashbuf, (unsigned char *)hashed);
801*6236dae4SAndroid Build Coastguard Worker 
802*6236dae4SAndroid Build Coastguard Worker     hashthis2 = aprintf("%s:%s", hashthis, hashed);
803*6236dae4SAndroid Build Coastguard Worker     free(hashthis);
804*6236dae4SAndroid Build Coastguard Worker     hashthis = hashthis2;
805*6236dae4SAndroid Build Coastguard Worker   }
806*6236dae4SAndroid Build Coastguard Worker 
807*6236dae4SAndroid Build Coastguard Worker   if(!hashthis)
808*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
809*6236dae4SAndroid Build Coastguard Worker 
810*6236dae4SAndroid Build Coastguard Worker   result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
811*6236dae4SAndroid Build Coastguard Worker   free(hashthis);
812*6236dae4SAndroid Build Coastguard Worker   if(result)
813*6236dae4SAndroid Build Coastguard Worker     return result;
814*6236dae4SAndroid Build Coastguard Worker   convert_to_ascii(hashbuf, ha2);
815*6236dae4SAndroid Build Coastguard Worker 
816*6236dae4SAndroid Build Coastguard Worker   if(digest->qop) {
817*6236dae4SAndroid Build Coastguard Worker     hashthis = aprintf("%s:%s:%08x:%s:%s:%s", ha1, digest->nonce, digest->nc,
818*6236dae4SAndroid Build Coastguard Worker                        digest->cnonce, digest->qop, ha2);
819*6236dae4SAndroid Build Coastguard Worker   }
820*6236dae4SAndroid Build Coastguard Worker   else {
821*6236dae4SAndroid Build Coastguard Worker     hashthis = aprintf("%s:%s:%s", ha1, digest->nonce, ha2);
822*6236dae4SAndroid Build Coastguard Worker   }
823*6236dae4SAndroid Build Coastguard Worker 
824*6236dae4SAndroid Build Coastguard Worker   if(!hashthis)
825*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
826*6236dae4SAndroid Build Coastguard Worker 
827*6236dae4SAndroid Build Coastguard Worker   result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
828*6236dae4SAndroid Build Coastguard Worker   free(hashthis);
829*6236dae4SAndroid Build Coastguard Worker   if(result)
830*6236dae4SAndroid Build Coastguard Worker     return result;
831*6236dae4SAndroid Build Coastguard Worker   convert_to_ascii(hashbuf, request_digest);
832*6236dae4SAndroid Build Coastguard Worker 
833*6236dae4SAndroid Build Coastguard Worker   /* For test case 64 (snooped from a Mozilla 1.3a request)
834*6236dae4SAndroid Build Coastguard Worker 
835*6236dae4SAndroid Build Coastguard Worker      Authorization: Digest username="testuser", realm="testrealm", \
836*6236dae4SAndroid Build Coastguard Worker      nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
837*6236dae4SAndroid Build Coastguard Worker 
838*6236dae4SAndroid Build Coastguard Worker      Digest parameters are all quoted strings. Username which is provided by
839*6236dae4SAndroid Build Coastguard Worker      the user will need double quotes and backslashes within it escaped.
840*6236dae4SAndroid Build Coastguard Worker      realm, nonce, and opaque will need backslashes as well as they were
841*6236dae4SAndroid Build Coastguard Worker      de-escaped when copied from request header. cnonce is generated with
842*6236dae4SAndroid Build Coastguard Worker      web-safe characters. uri is already percent encoded. nc is 8 hex
843*6236dae4SAndroid Build Coastguard Worker      characters. algorithm and qop with standard values only contain web-safe
844*6236dae4SAndroid Build Coastguard Worker      characters.
845*6236dae4SAndroid Build Coastguard Worker   */
846*6236dae4SAndroid Build Coastguard Worker   userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
847*6236dae4SAndroid Build Coastguard Worker   if(!userp_quoted)
848*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
849*6236dae4SAndroid Build Coastguard Worker   if(digest->realm)
850*6236dae4SAndroid Build Coastguard Worker     realm_quoted = auth_digest_string_quoted(digest->realm);
851*6236dae4SAndroid Build Coastguard Worker   else {
852*6236dae4SAndroid Build Coastguard Worker     realm_quoted = malloc(1);
853*6236dae4SAndroid Build Coastguard Worker     if(realm_quoted)
854*6236dae4SAndroid Build Coastguard Worker       realm_quoted[0] = 0;
855*6236dae4SAndroid Build Coastguard Worker   }
856*6236dae4SAndroid Build Coastguard Worker   if(!realm_quoted) {
857*6236dae4SAndroid Build Coastguard Worker     free(userp_quoted);
858*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
859*6236dae4SAndroid Build Coastguard Worker   }
860*6236dae4SAndroid Build Coastguard Worker   nonce_quoted = auth_digest_string_quoted(digest->nonce);
861*6236dae4SAndroid Build Coastguard Worker   if(!nonce_quoted) {
862*6236dae4SAndroid Build Coastguard Worker     free(realm_quoted);
863*6236dae4SAndroid Build Coastguard Worker     free(userp_quoted);
864*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
865*6236dae4SAndroid Build Coastguard Worker   }
866*6236dae4SAndroid Build Coastguard Worker 
867*6236dae4SAndroid Build Coastguard Worker   if(digest->qop) {
868*6236dae4SAndroid Build Coastguard Worker     response = aprintf("username=\"%s\", "
869*6236dae4SAndroid Build Coastguard Worker                        "realm=\"%s\", "
870*6236dae4SAndroid Build Coastguard Worker                        "nonce=\"%s\", "
871*6236dae4SAndroid Build Coastguard Worker                        "uri=\"%s\", "
872*6236dae4SAndroid Build Coastguard Worker                        "cnonce=\"%s\", "
873*6236dae4SAndroid Build Coastguard Worker                        "nc=%08x, "
874*6236dae4SAndroid Build Coastguard Worker                        "qop=%s, "
875*6236dae4SAndroid Build Coastguard Worker                        "response=\"%s\"",
876*6236dae4SAndroid Build Coastguard Worker                        userp_quoted,
877*6236dae4SAndroid Build Coastguard Worker                        realm_quoted,
878*6236dae4SAndroid Build Coastguard Worker                        nonce_quoted,
879*6236dae4SAndroid Build Coastguard Worker                        uripath,
880*6236dae4SAndroid Build Coastguard Worker                        digest->cnonce,
881*6236dae4SAndroid Build Coastguard Worker                        digest->nc,
882*6236dae4SAndroid Build Coastguard Worker                        digest->qop,
883*6236dae4SAndroid Build Coastguard Worker                        request_digest);
884*6236dae4SAndroid Build Coastguard Worker 
885*6236dae4SAndroid Build Coastguard Worker     /* Increment nonce-count to use another nc value for the next request */
886*6236dae4SAndroid Build Coastguard Worker     digest->nc++;
887*6236dae4SAndroid Build Coastguard Worker   }
888*6236dae4SAndroid Build Coastguard Worker   else {
889*6236dae4SAndroid Build Coastguard Worker     response = aprintf("username=\"%s\", "
890*6236dae4SAndroid Build Coastguard Worker                        "realm=\"%s\", "
891*6236dae4SAndroid Build Coastguard Worker                        "nonce=\"%s\", "
892*6236dae4SAndroid Build Coastguard Worker                        "uri=\"%s\", "
893*6236dae4SAndroid Build Coastguard Worker                        "response=\"%s\"",
894*6236dae4SAndroid Build Coastguard Worker                        userp_quoted,
895*6236dae4SAndroid Build Coastguard Worker                        realm_quoted,
896*6236dae4SAndroid Build Coastguard Worker                        nonce_quoted,
897*6236dae4SAndroid Build Coastguard Worker                        uripath,
898*6236dae4SAndroid Build Coastguard Worker                        request_digest);
899*6236dae4SAndroid Build Coastguard Worker   }
900*6236dae4SAndroid Build Coastguard Worker   free(nonce_quoted);
901*6236dae4SAndroid Build Coastguard Worker   free(realm_quoted);
902*6236dae4SAndroid Build Coastguard Worker   free(userp_quoted);
903*6236dae4SAndroid Build Coastguard Worker   if(!response)
904*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
905*6236dae4SAndroid Build Coastguard Worker 
906*6236dae4SAndroid Build Coastguard Worker   /* Add the optional fields */
907*6236dae4SAndroid Build Coastguard Worker   if(digest->opaque) {
908*6236dae4SAndroid Build Coastguard Worker     char *opaque_quoted;
909*6236dae4SAndroid Build Coastguard Worker     /* Append the opaque */
910*6236dae4SAndroid Build Coastguard Worker     opaque_quoted = auth_digest_string_quoted(digest->opaque);
911*6236dae4SAndroid Build Coastguard Worker     if(!opaque_quoted) {
912*6236dae4SAndroid Build Coastguard Worker       free(response);
913*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
914*6236dae4SAndroid Build Coastguard Worker     }
915*6236dae4SAndroid Build Coastguard Worker     tmp = aprintf("%s, opaque=\"%s\"", response, opaque_quoted);
916*6236dae4SAndroid Build Coastguard Worker     free(response);
917*6236dae4SAndroid Build Coastguard Worker     free(opaque_quoted);
918*6236dae4SAndroid Build Coastguard Worker     if(!tmp)
919*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
920*6236dae4SAndroid Build Coastguard Worker 
921*6236dae4SAndroid Build Coastguard Worker     response = tmp;
922*6236dae4SAndroid Build Coastguard Worker   }
923*6236dae4SAndroid Build Coastguard Worker 
924*6236dae4SAndroid Build Coastguard Worker   if(digest->algorithm) {
925*6236dae4SAndroid Build Coastguard Worker     /* Append the algorithm */
926*6236dae4SAndroid Build Coastguard Worker     tmp = aprintf("%s, algorithm=%s", response, digest->algorithm);
927*6236dae4SAndroid Build Coastguard Worker     free(response);
928*6236dae4SAndroid Build Coastguard Worker     if(!tmp)
929*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
930*6236dae4SAndroid Build Coastguard Worker 
931*6236dae4SAndroid Build Coastguard Worker     response = tmp;
932*6236dae4SAndroid Build Coastguard Worker   }
933*6236dae4SAndroid Build Coastguard Worker 
934*6236dae4SAndroid Build Coastguard Worker   if(digest->userhash) {
935*6236dae4SAndroid Build Coastguard Worker     /* Append the userhash */
936*6236dae4SAndroid Build Coastguard Worker     tmp = aprintf("%s, userhash=true", response);
937*6236dae4SAndroid Build Coastguard Worker     free(response);
938*6236dae4SAndroid Build Coastguard Worker     if(!tmp)
939*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
940*6236dae4SAndroid Build Coastguard Worker 
941*6236dae4SAndroid Build Coastguard Worker     response = tmp;
942*6236dae4SAndroid Build Coastguard Worker   }
943*6236dae4SAndroid Build Coastguard Worker 
944*6236dae4SAndroid Build Coastguard Worker   /* Return the output */
945*6236dae4SAndroid Build Coastguard Worker   *outptr = response;
946*6236dae4SAndroid Build Coastguard Worker   *outlen = strlen(response);
947*6236dae4SAndroid Build Coastguard Worker 
948*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
949*6236dae4SAndroid Build Coastguard Worker }
950*6236dae4SAndroid Build Coastguard Worker 
951*6236dae4SAndroid Build Coastguard Worker /*
952*6236dae4SAndroid Build Coastguard Worker  * Curl_auth_create_digest_http_message()
953*6236dae4SAndroid Build Coastguard Worker  *
954*6236dae4SAndroid Build Coastguard Worker  * This is used to generate an HTTP DIGEST response message ready for sending
955*6236dae4SAndroid Build Coastguard Worker  * to the recipient.
956*6236dae4SAndroid Build Coastguard Worker  *
957*6236dae4SAndroid Build Coastguard Worker  * Parameters:
958*6236dae4SAndroid Build Coastguard Worker  *
959*6236dae4SAndroid Build Coastguard Worker  * data    [in]     - The session handle.
960*6236dae4SAndroid Build Coastguard Worker  * userp   [in]     - The username.
961*6236dae4SAndroid Build Coastguard Worker  * passwdp [in]     - The user's password.
962*6236dae4SAndroid Build Coastguard Worker  * request [in]     - The HTTP request.
963*6236dae4SAndroid Build Coastguard Worker  * uripath [in]     - The path of the HTTP uri.
964*6236dae4SAndroid Build Coastguard Worker  * digest  [in/out] - The digest data struct being used and modified.
965*6236dae4SAndroid Build Coastguard Worker  * outptr  [in/out] - The address where a pointer to newly allocated memory
966*6236dae4SAndroid Build Coastguard Worker  *                    holding the result will be stored upon completion.
967*6236dae4SAndroid Build Coastguard Worker  * outlen  [out]    - The length of the output message.
968*6236dae4SAndroid Build Coastguard Worker  *
969*6236dae4SAndroid Build Coastguard Worker  * Returns CURLE_OK on success.
970*6236dae4SAndroid Build Coastguard Worker  */
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)971*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
972*6236dae4SAndroid Build Coastguard Worker                                               const char *userp,
973*6236dae4SAndroid Build Coastguard Worker                                               const char *passwdp,
974*6236dae4SAndroid Build Coastguard Worker                                               const unsigned char *request,
975*6236dae4SAndroid Build Coastguard Worker                                               const unsigned char *uripath,
976*6236dae4SAndroid Build Coastguard Worker                                               struct digestdata *digest,
977*6236dae4SAndroid Build Coastguard Worker                                               char **outptr, size_t *outlen)
978*6236dae4SAndroid Build Coastguard Worker {
979*6236dae4SAndroid Build Coastguard Worker   if(digest->algo <= ALGO_MD5SESS)
980*6236dae4SAndroid Build Coastguard Worker     return auth_create_digest_http_message(data, userp, passwdp,
981*6236dae4SAndroid Build Coastguard Worker                                            request, uripath, digest,
982*6236dae4SAndroid Build Coastguard Worker                                            outptr, outlen,
983*6236dae4SAndroid Build Coastguard Worker                                            auth_digest_md5_to_ascii,
984*6236dae4SAndroid Build Coastguard Worker                                            Curl_md5it);
985*6236dae4SAndroid Build Coastguard Worker 
986*6236dae4SAndroid Build Coastguard Worker   if(digest->algo <= ALGO_SHA256SESS)
987*6236dae4SAndroid Build Coastguard Worker     return auth_create_digest_http_message(data, userp, passwdp,
988*6236dae4SAndroid Build Coastguard Worker                                            request, uripath, digest,
989*6236dae4SAndroid Build Coastguard Worker                                            outptr, outlen,
990*6236dae4SAndroid Build Coastguard Worker                                            auth_digest_sha256_to_ascii,
991*6236dae4SAndroid Build Coastguard Worker                                            Curl_sha256it);
992*6236dae4SAndroid Build Coastguard Worker #ifdef CURL_HAVE_SHA512_256
993*6236dae4SAndroid Build Coastguard Worker   if(digest->algo <= ALGO_SHA512_256SESS)
994*6236dae4SAndroid Build Coastguard Worker     return auth_create_digest_http_message(data, userp, passwdp,
995*6236dae4SAndroid Build Coastguard Worker                                            request, uripath, digest,
996*6236dae4SAndroid Build Coastguard Worker                                            outptr, outlen,
997*6236dae4SAndroid Build Coastguard Worker                                            auth_digest_sha256_to_ascii,
998*6236dae4SAndroid Build Coastguard Worker                                            Curl_sha512_256it);
999*6236dae4SAndroid Build Coastguard Worker #endif /* CURL_HAVE_SHA512_256 */
1000*6236dae4SAndroid Build Coastguard Worker 
1001*6236dae4SAndroid Build Coastguard Worker   /* Should be unreachable */
1002*6236dae4SAndroid Build Coastguard Worker   return CURLE_BAD_CONTENT_ENCODING;
1003*6236dae4SAndroid Build Coastguard Worker }
1004*6236dae4SAndroid Build Coastguard Worker 
1005*6236dae4SAndroid Build Coastguard Worker /*
1006*6236dae4SAndroid Build Coastguard Worker  * Curl_auth_digest_cleanup()
1007*6236dae4SAndroid Build Coastguard Worker  *
1008*6236dae4SAndroid Build Coastguard Worker  * This is used to clean up the digest specific data.
1009*6236dae4SAndroid Build Coastguard Worker  *
1010*6236dae4SAndroid Build Coastguard Worker  * Parameters:
1011*6236dae4SAndroid Build Coastguard Worker  *
1012*6236dae4SAndroid Build Coastguard Worker  * digest    [in/out] - The digest data struct being cleaned up.
1013*6236dae4SAndroid Build Coastguard Worker  *
1014*6236dae4SAndroid Build Coastguard Worker  */
Curl_auth_digest_cleanup(struct digestdata * digest)1015*6236dae4SAndroid Build Coastguard Worker void Curl_auth_digest_cleanup(struct digestdata *digest)
1016*6236dae4SAndroid Build Coastguard Worker {
1017*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(digest->nonce);
1018*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(digest->cnonce);
1019*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(digest->realm);
1020*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(digest->opaque);
1021*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(digest->qop);
1022*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(digest->algorithm);
1023*6236dae4SAndroid Build Coastguard Worker 
1024*6236dae4SAndroid Build Coastguard Worker   digest->nc = 0;
1025*6236dae4SAndroid Build Coastguard Worker   digest->algo = ALGO_MD5; /* default algorithm */
1026*6236dae4SAndroid Build Coastguard Worker   digest->stale = FALSE; /* default means normal, not stale */
1027*6236dae4SAndroid Build Coastguard Worker   digest->userhash = FALSE;
1028*6236dae4SAndroid Build Coastguard Worker }
1029*6236dae4SAndroid Build Coastguard Worker #endif  /* !USE_WINDOWS_SSPI */
1030*6236dae4SAndroid Build Coastguard Worker 
1031*6236dae4SAndroid Build Coastguard Worker #endif  /* !CURL_DISABLE_DIGEST_AUTH */
1032