1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
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.
13  *
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.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
26 
27 #include "urldata.h"
28 #include "strcase.h"
29 #include "vauth/vauth.h"
30 #include "http_digest.h"
31 
32 /* The last 3 #include files should be in this order */
33 #include "curl_printf.h"
34 #include "curl_memory.h"
35 #include "memdebug.h"
36 
37 /* Test example headers:
38 
39 WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
40 Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
41 
42 */
43 
Curl_input_digest(struct Curl_easy * data,bool proxy,const char * header)44 CURLcode Curl_input_digest(struct Curl_easy *data,
45                            bool proxy,
46                            const char *header) /* rest of the *-authenticate:
47                                                   header */
48 {
49   /* Point to the correct struct with this */
50   struct digestdata *digest;
51 
52   if(proxy) {
53     digest = &data->state.proxydigest;
54   }
55   else {
56     digest = &data->state.digest;
57   }
58 
59   if(!checkprefix("Digest", header) || !ISSPACE(header[6]))
60     return CURLE_BAD_CONTENT_ENCODING;
61 
62   header += strlen("Digest");
63   while(*header && ISSPACE(*header))
64     header++;
65 
66   return Curl_auth_decode_digest_http_message(header, digest);
67 }
68 
Curl_output_digest(struct Curl_easy * data,bool proxy,const unsigned char * request,const unsigned char * uripath)69 CURLcode Curl_output_digest(struct Curl_easy *data,
70                             bool proxy,
71                             const unsigned char *request,
72                             const unsigned char *uripath)
73 {
74   CURLcode result;
75   unsigned char *path = NULL;
76   char *tmp = NULL;
77   char *response;
78   size_t len;
79   bool have_chlg;
80 
81   /* Point to the address of the pointer that holds the string to send to the
82      server, which is for a plain host or for a HTTP proxy */
83   char **allocuserpwd;
84 
85   /* Point to the name and password for this */
86   const char *userp;
87   const char *passwdp;
88 
89   /* Point to the correct struct with this */
90   struct digestdata *digest;
91   struct auth *authp;
92 
93   if(proxy) {
94 #ifdef CURL_DISABLE_PROXY
95     return CURLE_NOT_BUILT_IN;
96 #else
97     digest = &data->state.proxydigest;
98     allocuserpwd = &data->state.aptr.proxyuserpwd;
99     userp = data->state.aptr.proxyuser;
100     passwdp = data->state.aptr.proxypasswd;
101     authp = &data->state.authproxy;
102 #endif
103   }
104   else {
105     digest = &data->state.digest;
106     allocuserpwd = &data->state.aptr.userpwd;
107     userp = data->state.aptr.user;
108     passwdp = data->state.aptr.passwd;
109     authp = &data->state.authhost;
110   }
111 
112   Curl_safefree(*allocuserpwd);
113 
114   /* not set means empty */
115   if(!userp)
116     userp = "";
117 
118   if(!passwdp)
119     passwdp = "";
120 
121 #if defined(USE_WINDOWS_SSPI)
122   have_chlg = digest->input_token ? TRUE : FALSE;
123 #else
124   have_chlg = digest->nonce ? TRUE : FALSE;
125 #endif
126 
127   if(!have_chlg) {
128     authp->done = FALSE;
129     return CURLE_OK;
130   }
131 
132   /* So IE browsers < v7 cut off the URI part at the query part when they
133      evaluate the MD5 and some (IIS?) servers work with them so we may need to
134      do the Digest IE-style. Note that the different ways cause different MD5
135      sums to get sent.
136 
137      Apache servers can be set to do the Digest IE-style automatically using
138      the BrowserMatch feature:
139      https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie
140 
141      Further details on Digest implementation differences:
142      http://www.fngtps.com/2006/09/http-authentication
143   */
144 
145   if(authp->iestyle) {
146     tmp = strchr((char *)uripath, '?');
147     if(tmp) {
148       size_t urilen = tmp - (char *)uripath;
149       /* typecast is fine here since the value is always less than 32 bits */
150       path = (unsigned char *) aprintf("%.*s", (int)urilen, uripath);
151     }
152   }
153   if(!tmp)
154     path = (unsigned char *) strdup((char *) uripath);
155 
156   if(!path)
157     return CURLE_OUT_OF_MEMORY;
158 
159   result = Curl_auth_create_digest_http_message(data, userp, passwdp, request,
160                                                 path, digest, &response, &len);
161   free(path);
162   if(result)
163     return result;
164 
165   *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n",
166                           proxy ? "Proxy-" : "",
167                           response);
168   free(response);
169   if(!*allocuserpwd)
170     return CURLE_OUT_OF_MEMORY;
171 
172   authp->done = TRUE;
173 
174   return CURLE_OK;
175 }
176 
Curl_http_auth_cleanup_digest(struct Curl_easy * data)177 void Curl_http_auth_cleanup_digest(struct Curl_easy *data)
178 {
179   Curl_auth_digest_cleanup(&data->state.digest);
180   Curl_auth_digest_cleanup(&data->state.proxydigest);
181 }
182 
183 #endif
184