FFmpeg
httpauth.c
Go to the documentation of this file.
1 /*
2  * HTTP authentication
3  * Copyright (c) 2010 Martin Storsjo
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "httpauth.h"
23 #include "libavutil/base64.h"
24 #include "libavutil/avstring.h"
25 #include "libavutil/mem.h"
26 #include "internal.h"
27 #include "libavutil/random_seed.h"
28 #include "libavutil/md5.h"
29 #include "urldecode.h"
30 
31 static void handle_basic_params(void *context, const char *key,
32  int key_len, char **dest, int *dest_len)
33 {
35  if (!strncmp(key, "realm=", key_len)) {
36  *dest = state->realm;
37  *dest_len = sizeof(state->realm);
38  }
39 }
40 
41 static void handle_digest_params(void *context, const char *key,
42  int key_len, char **dest, int *dest_len)
43 {
45  DigestParams *digest = &state->digest_params;
46 
47  if (!strncmp(key, "realm=", key_len)) {
48  *dest = state->realm;
49  *dest_len = sizeof(state->realm);
50  } else if (!strncmp(key, "nonce=", key_len)) {
51  *dest = digest->nonce;
52  *dest_len = sizeof(digest->nonce);
53  } else if (!strncmp(key, "opaque=", key_len)) {
54  *dest = digest->opaque;
55  *dest_len = sizeof(digest->opaque);
56  } else if (!strncmp(key, "algorithm=", key_len)) {
57  *dest = digest->algorithm;
58  *dest_len = sizeof(digest->algorithm);
59  } else if (!strncmp(key, "qop=", key_len)) {
60  *dest = digest->qop;
61  *dest_len = sizeof(digest->qop);
62  } else if (!strncmp(key, "stale=", key_len)) {
63  *dest = digest->stale;
64  *dest_len = sizeof(digest->stale);
65  }
66 }
67 
68 static void handle_digest_update(void *context, const char *key,
69  int key_len, char **dest, int *dest_len)
70 {
72  DigestParams *digest = &state->digest_params;
73 
74  if (!strncmp(key, "nextnonce=", key_len)) {
75  *dest = digest->nonce;
76  *dest_len = sizeof(digest->nonce);
77  }
78 }
79 
80 static void choose_qop(char *qop, int size)
81 {
82  char *ptr = strstr(qop, "auth");
83  char *end = ptr + strlen("auth");
84 
85  if (ptr && (!*end || av_isspace(*end) || *end == ',') &&
86  (ptr == qop || av_isspace(ptr[-1]) || ptr[-1] == ',')) {
87  av_strlcpy(qop, "auth", size);
88  } else {
89  qop[0] = 0;
90  }
91 }
92 
94  const char *value)
95 {
96  if (!av_strcasecmp(key, "WWW-Authenticate") || !av_strcasecmp(key, "Proxy-Authenticate")) {
97  const char *p;
98  if (av_stristart(value, "Basic ", &p) &&
99  state->auth_type <= HTTP_AUTH_BASIC) {
100  state->auth_type = HTTP_AUTH_BASIC;
101  state->realm[0] = 0;
102  state->stale = 0;
104  } else if (av_stristart(value, "Digest ", &p) &&
105  state->auth_type <= HTTP_AUTH_DIGEST) {
106  state->auth_type = HTTP_AUTH_DIGEST;
107  memset(&state->digest_params, 0, sizeof(DigestParams));
108  state->realm[0] = 0;
109  state->stale = 0;
111  choose_qop(state->digest_params.qop,
112  sizeof(state->digest_params.qop));
113  if (!av_strcasecmp(state->digest_params.stale, "true"))
114  state->stale = 1;
115  }
116  } else if (!av_strcasecmp(key, "Authentication-Info")) {
118  }
119 }
120 
121 
122 static void update_md5_strings(struct AVMD5 *md5ctx, ...)
123 {
124  va_list vl;
125 
126  va_start(vl, md5ctx);
127  while (1) {
128  const char* str = va_arg(vl, const char*);
129  if (!str)
130  break;
131  av_md5_update(md5ctx, str, strlen(str));
132  }
133  va_end(vl);
134 }
135 
136 /* Generate a digest reply, according to RFC 2617. */
137 static char *make_digest_auth(HTTPAuthState *state, const char *username,
138  const char *password, const char *uri,
139  const char *method)
140 {
141  DigestParams *digest = &state->digest_params;
142  int len;
143  uint32_t cnonce_buf[2];
144  char cnonce[17];
145  char nc[9];
146  int i;
147  char A1hash[33], A2hash[33], response[33];
148  struct AVMD5 *md5ctx;
149  uint8_t hash[16];
150  char *authstr;
151 
152  digest->nc++;
153  snprintf(nc, sizeof(nc), "%08x", digest->nc);
154 
155  /* Generate a client nonce. */
156  for (i = 0; i < 2; i++)
157  cnonce_buf[i] = av_get_random_seed();
158  ff_data_to_hex(cnonce, (const uint8_t*) cnonce_buf, sizeof(cnonce_buf), 1);
159 
160  md5ctx = av_md5_alloc();
161  if (!md5ctx)
162  return NULL;
163 
164  av_md5_init(md5ctx);
165  update_md5_strings(md5ctx, username, ":", state->realm, ":", password, NULL);
166  av_md5_final(md5ctx, hash);
167  ff_data_to_hex(A1hash, hash, 16, 1);
168 
169  if (!strcmp(digest->algorithm, "") || !strcmp(digest->algorithm, "MD5")) {
170  } else if (!strcmp(digest->algorithm, "MD5-sess")) {
171  av_md5_init(md5ctx);
172  update_md5_strings(md5ctx, A1hash, ":", digest->nonce, ":", cnonce, NULL);
173  av_md5_final(md5ctx, hash);
174  ff_data_to_hex(A1hash, hash, 16, 1);
175  } else {
176  /* Unsupported algorithm */
177  av_free(md5ctx);
178  return NULL;
179  }
180 
181  av_md5_init(md5ctx);
182  update_md5_strings(md5ctx, method, ":", uri, NULL);
183  av_md5_final(md5ctx, hash);
184  ff_data_to_hex(A2hash, hash, 16, 1);
185 
186  av_md5_init(md5ctx);
187  update_md5_strings(md5ctx, A1hash, ":", digest->nonce, NULL);
188  if (!strcmp(digest->qop, "auth") || !strcmp(digest->qop, "auth-int")) {
189  update_md5_strings(md5ctx, ":", nc, ":", cnonce, ":", digest->qop, NULL);
190  }
191  update_md5_strings(md5ctx, ":", A2hash, NULL);
192  av_md5_final(md5ctx, hash);
193  ff_data_to_hex(response, hash, 16, 1);
194 
195  av_free(md5ctx);
196 
197  if (!strcmp(digest->qop, "") || !strcmp(digest->qop, "auth")) {
198  } else if (!strcmp(digest->qop, "auth-int")) {
199  /* qop=auth-int not supported */
200  return NULL;
201  } else {
202  /* Unsupported qop value. */
203  return NULL;
204  }
205 
206  len = strlen(username) + strlen(state->realm) + strlen(digest->nonce) +
207  strlen(uri) + strlen(response) + strlen(digest->algorithm) +
208  strlen(digest->opaque) + strlen(digest->qop) + strlen(cnonce) +
209  strlen(nc) + 150;
210 
211  authstr = av_malloc(len);
212  if (!authstr)
213  return NULL;
214  snprintf(authstr, len, "Authorization: Digest ");
215 
216  /* TODO: Escape the quoted strings properly. */
217  av_strlcatf(authstr, len, "username=\"%s\"", username);
218  av_strlcatf(authstr, len, ", realm=\"%s\"", state->realm);
219  av_strlcatf(authstr, len, ", nonce=\"%s\"", digest->nonce);
220  av_strlcatf(authstr, len, ", uri=\"%s\"", uri);
221  av_strlcatf(authstr, len, ", response=\"%s\"", response);
222 
223  // we are violating the RFC and use "" because all others seem to do that too.
224  if (digest->algorithm[0])
225  av_strlcatf(authstr, len, ", algorithm=\"%s\"", digest->algorithm);
226 
227  if (digest->opaque[0])
228  av_strlcatf(authstr, len, ", opaque=\"%s\"", digest->opaque);
229  if (digest->qop[0]) {
230  av_strlcatf(authstr, len, ", qop=\"%s\"", digest->qop);
231  av_strlcatf(authstr, len, ", cnonce=\"%s\"", cnonce);
232  av_strlcatf(authstr, len, ", nc=%s", nc);
233  }
234 
235  av_strlcatf(authstr, len, "\r\n");
236 
237  return authstr;
238 }
239 
241  const char *path, const char *method)
242 {
243  char *authstr = NULL;
244 
245  /* Clear the stale flag, we assume the auth is ok now. It is reset
246  * by the server headers if there's a new issue. */
247  state->stale = 0;
248  if (!auth || !strchr(auth, ':'))
249  return NULL;
250 
251  if (state->auth_type == HTTP_AUTH_BASIC) {
252  int auth_b64_len, len;
253  char *ptr, *decoded_auth = ff_urldecode(auth, 0);
254 
255  if (!decoded_auth)
256  return NULL;
257 
258  auth_b64_len = AV_BASE64_SIZE(strlen(decoded_auth));
259  len = auth_b64_len + 30;
260 
261  authstr = av_malloc(len);
262  if (!authstr) {
263  av_free(decoded_auth);
264  return NULL;
265  }
266 
267  snprintf(authstr, len, "Authorization: Basic ");
268  ptr = authstr + strlen(authstr);
269  av_base64_encode(ptr, auth_b64_len, decoded_auth, strlen(decoded_auth));
270  av_strlcat(ptr, "\r\n", len - (ptr - authstr));
271  av_free(decoded_auth);
272  } else if (state->auth_type == HTTP_AUTH_DIGEST) {
273  char *username = ff_urldecode(auth, 0), *password;
274 
275  if (!username)
276  return NULL;
277 
278  if ((password = strchr(username, ':'))) {
279  *password++ = 0;
280  authstr = make_digest_auth(state, username, password, path, method);
281  }
282  av_free(username);
283  }
284  return authstr;
285 }
HTTP_AUTH_BASIC
@ HTTP_AUTH_BASIC
HTTP 1.0 Basic auth from RFC 1945 (also in RFC 2617)
Definition: httpauth.h:30
av_strcasecmp
int av_strcasecmp(const char *a, const char *b)
Locale-independent case-insensitive compare.
Definition: avstring.c:208
av_isspace
static av_const int av_isspace(int c)
Locale-independent conversion of ASCII isspace.
Definition: avstring.h:218
make_digest_auth
static char * make_digest_auth(HTTPAuthState *state, const char *username, const char *password, const char *uri, const char *method)
Definition: httpauth.c:137
update_md5_strings
static void update_md5_strings(struct AVMD5 *md5ctx,...)
Definition: httpauth.c:122
ff_http_auth_create_response
char * ff_http_auth_create_response(HTTPAuthState *state, const char *auth, const char *path, const char *method)
Definition: httpauth.c:240
hash
static uint8_t hash[HASH_SIZE]
Definition: movenc.c:58
av_strlcatf
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition: avstring.c:103
av_get_random_seed
uint32_t av_get_random_seed(void)
Get a seed to use in conjunction with random functions.
Definition: random_seed.c:196
ff_urldecode
char * ff_urldecode(const char *url, int decode_plus_sign)
Decodes an URL from its percent-encoded form back into normal representation.
Definition: urldecode.c:80
ff_data_to_hex
char * ff_data_to_hex(char *buf, const uint8_t *src, int size, int lowercase)
Write hexadecimal string corresponding to given binary data.
Definition: utils.c:458
AVMD5
Definition: md5.c:42
DigestParams::qop
char qop[30]
Quality of protection, containing the one that we've chosen to use, from the alternatives that the se...
Definition: httpauth.h:38
HTTP_AUTH_DIGEST
@ HTTP_AUTH_DIGEST
HTTP 1.1 Digest auth from RFC 2617.
Definition: httpauth.h:32
av_stristart
int av_stristart(const char *str, const char *pfx, const char **ptr)
Return non-zero if pfx is a prefix of str independent of case.
Definition: avstring.c:47
key
const char * key
Definition: hwcontext_opencl.c:189
ff_http_auth_handle_header
void ff_http_auth_handle_header(HTTPAuthState *state, const char *key, const char *value)
Definition: httpauth.c:93
context
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option keep it simple and lowercase description are in without and describe what they for example set the foo of the bar offset is the offset of the field in your context
Definition: writing_filters.txt:91
internal.h
NULL
#define NULL
Definition: coverity.c:32
DigestParams::nonce
char nonce[300]
Server specified nonce.
Definition: httpauth.h:36
handle_digest_update
static void handle_digest_update(void *context, const char *key, int key_len, char **dest, int *dest_len)
Definition: httpauth.c:68
choose_qop
static void choose_qop(char *qop, int size)
Definition: httpauth.c:80
base64.h
HTTPAuthState
HTTP Authentication state structure.
Definition: httpauth.h:55
DigestParams::stale
char stale[10]
The server indicated that the auth was ok, but needs to be redone with a new, non-stale nonce.
Definition: httpauth.h:44
i
#define i(width, name, range_min, range_max)
Definition: cbs_h264.c:63
size
int size
Definition: twinvq_data.h:10344
state
static struct @583 state
av_md5_init
void av_md5_init(AVMD5 *ctx)
Initialize MD5 hashing.
Definition: md5.c:143
httpauth.h
AV_BASE64_SIZE
#define AV_BASE64_SIZE(x)
Calculate the output size needed to base64-encode x bytes to a null-terminated string.
Definition: base64.h:66
av_malloc
#define av_malloc(s)
Definition: ops_asmgen.c:44
DigestParams::opaque
char opaque[300]
A server-specified string that should be included in authentication responses, not included in the ac...
Definition: httpauth.h:41
md5.h
value
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
Definition: writing_filters.txt:86
DigestParams
Definition: httpauth.h:35
len
int len
Definition: vorbis_enc_data.h:426
av_md5_final
void av_md5_final(AVMD5 *ctx, uint8_t *dst)
Finish hashing and output digest value.
Definition: md5.c:188
av_strlcat
size_t av_strlcat(char *dst, const char *src, size_t size)
Append the string src to the string dst, but to a total length of no more than size - 1 bytes,...
Definition: avstring.c:95
DigestParams::nc
int nc
Nonce count, the number of earlier replies where this particular nonce has been used.
Definition: httpauth.h:47
random_seed.h
urldecode.h
av_md5_alloc
struct AVMD5 * av_md5_alloc(void)
Allocate an AVMD5 context.
Definition: md5.c:50
av_base64_encode
char * av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
Encode data to base64 and null-terminate.
Definition: base64.c:147
Windows::Graphics::DirectX::Direct3D11::p
IDirect3DDxgiInterfaceAccess _COM_Outptr_ void ** p
Definition: vsrc_gfxcapture_winrt.hpp:53
av_md5_update
void av_md5_update(AVMD5 *ctx, const uint8_t *src, size_t len)
Update hash value.
Definition: md5.c:153
DigestParams::algorithm
char algorithm[10]
Server specified digest algorithm.
Definition: httpauth.h:37
mem.h
handle_digest_params
static void handle_digest_params(void *context, const char *key, int key_len, char **dest, int *dest_len)
Definition: httpauth.c:41
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
av_strlcpy
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:85
avstring.h
handle_basic_params
static void handle_basic_params(void *context, const char *key, int key_len, char **dest, int *dest_len)
Definition: httpauth.c:31
snprintf
#define snprintf
Definition: snprintf.h:34
ff_parse_key_value
void ff_parse_key_value(const char *str, ff_parse_key_val_cb callback_get_buf, void *context)
Parse a string with comma-separated key=value pairs.
Definition: utils.c:507