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