Some RTSP servers return multiple WWW-Authenticate: Digest headers
containing both MD5 and SHA-256 challenges (example below). FFmpeg previously
parsed
only the last header, causing authentication failure. This patch adds
support for parsing all Digest headers and selecting a valid algorithm.
Real Time Streaming Protocol
Response: RTSP/1.0 401 Unauthorized\r\n
CSeq: 2\r\n
Date: Thu, Dec 11 2025 05:36:10 GMT\r\n
WWW-Authenticate: Digest realm="RtspServerLibrary",
nonce="pJMYo4EfZcpH5ly0eJunZr8F9s1AY1c9", algorithm="MD5"\r\n
WWW-Authenticate: Digest realm="RtspServerLibrary",
nonce="pJMYo4EfZcpH5ly0eJunZr8F9s1AY1c9", algorithm="SHA-256"\r\n
\r\n
Signed-off-by: Zhigong Liu <[email protected]>
---
libavformat/httpauth.c | 41 +++++++++++++++++++++++++++++++----------
1 file changed, 31 insertions(+), 10 deletions(-)
diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c
index 9048362509..2f9c600842 100644
--- a/libavformat/httpauth.c
+++ b/libavformat/httpauth.c
@@ -101,16 +101,34 @@ void ff_http_auth_handle_header(HTTPAuthState *state,
const char *key,
state);
} else if (av_stristart(value, "Digest ", &p) &&
state->auth_type <= HTTP_AUTH_DIGEST) {
- state->auth_type = HTTP_AUTH_DIGEST;
- memset(&state->digest_params, 0, sizeof(DigestParams));
- state->realm[0] = 0;
- state->stale = 0;
- ff_parse_key_value(p, (ff_parse_key_val_cb) handle_digest_params,
- state);
- choose_qop(state->digest_params.qop,
- sizeof(state->digest_params.qop));
- if (!av_strcasecmp(state->digest_params.stale, "true"))
- state->stale = 1;
+ /* Handle multiple Digest authentication headers by preferring MD5
over SHA-256
+ * or updating if we haven't set digest auth yet */
+ const char *alg_start = strstr(p, "algorithm=");
+ int is_md5 = 1; /* Default to MD5 if no algorithm specified */
+
+ if (alg_start) {
+ alg_start += 10; /* Skip "algorithm=" */
+ if (av_strncasecmp(alg_start, "\"MD5\"", 5) == 0 ||
av_strncasecmp(alg_start, "MD5", 3) == 0) {
+ is_md5 = 1;
+ } else if (av_strncasecmp(alg_start, "\"SHA-256\"", 9) == 0 ||
av_strncasecmp(alg_start, "SHA-256", 7) == 0) {
+ is_md5 = 0;
+ }
+ }
+
+ /* Prefer MD5 over SHA-256, or set if not already set */
+ if (state->auth_type < HTTP_AUTH_DIGEST ||
+ (is_md5 && av_strcasecmp(state->digest_params.algorithm,
"MD5") != 0)) {
+ state->auth_type = HTTP_AUTH_DIGEST;
+ memset(&state->digest_params, 0, sizeof(DigestParams));
+ state->realm[0] = 0;
+ state->stale = 0;
+ ff_parse_key_value(p, (ff_parse_key_val_cb)
handle_digest_params,
+ state);
+ choose_qop(state->digest_params.qop,
+ sizeof(state->digest_params.qop));
+ if (!av_strcasecmp(state->digest_params.stale, "true"))
+ state->stale = 1;
+ }
}
} else if (!av_strcasecmp(key, "Authentication-Info")) {
ff_parse_key_value(value, (ff_parse_key_val_cb) handle_digest_update,
@@ -221,8 +239,11 @@ static char *make_digest_auth(HTTPAuthState *state, const
char *username,
av_strlcatf(authstr, len, ", response=\"%s\"", response);
// we are violating the RFC and use "" because all others seem to do that
too.
+ // Always include algorithm for better compatibility
if (digest->algorithm[0])
av_strlcatf(authstr, len, ", algorithm=\"%s\"", digest->algorithm);
+ else
+ av_strlcatf(authstr, len, ", algorithm=\"MD5\"");
if (digest->opaque[0])
av_strlcatf(authstr, len, ", opaque=\"%s\"", digest->opaque);
--
2.49.0.windows.1
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]