This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch release/8.0
in repository ffmpeg.

commit d7b12b918a9614b69e6c9c3f042531115fe866d4
Author:     Omkhar Arasaratnam <[email protected]>
AuthorDate: Thu May 21 00:00:00 2026 +0000
Commit:     Michael Niedermayer <[email protected]>
CommitDate: Sun Jun 14 04:59:03 2026 +0200

    avformat/whip: require remote DTLS fingerprint in SDP answer
    
    WHIP relies on the SDP a=fingerprint to bind the peer identity to
    the SRTP keying material (RFC 8842 §§ 5.1, 5.3). parse_answer()
    walks the SDP body looking for `a=ice-lite`, `a=ice-ufrag:`,
    `a=ice-pwd:`, and `a=candidate:` lines and ignores everything else,
    including `a=fingerprint`. WHIP intentionally runs the OpenSSL DTLS
    backend with s->verify=0 (DTLS-SRTP uses self-signed certs by
    design, so a CA chain check would be meaningless); the peer cert is
    accepted regardless of identity. The spec's compensating identity
    control — verifying the DTLS peer cert against the SDP a=fingerprint
    hash — is missing, so the SRTP keys are derived from a session
    whose peer identity was never authenticated. Any on-path attacker,
    or a malicious WHIP server URL, can substitute their own DTLS
    material and the publisher's RTP stream will be encrypted to them.
    
    The full fix is a two-step process:
      (a) Require a=fingerprint to be present in the SDP answer
          (RFC 8842 § 5.3 MUST).
      (b) After DTLS handshake, compute the peer-cert hash and compare
          against the stored fingerprint (RFC 8842 § 5.1 MUST); tear
          down the session on mismatch.
    This patch implements step (a) only; step (b) requires plumbing
    the cert hash out of dtls_start() through the openssl TLS context
    and is left as a follow-up.
    
    Add a remote_fingerprint field to WHIPContext, extract the
    a=fingerprint value from the SDP answer in parse_answer(), and
    return AVERROR(EINVAL) when it is absent. This raises the bar from
    "no fingerprint required" to "any fingerprint required"; the
    follow-up patch will raise it again to "fingerprint MUST hash-match
    the DTLS peer cert."
    
    Found-by: Claude (Anthropic). Human-verified and reported by
    Omkhar Arasaratnam <[email protected]>.
    Signed-off-by: Omkhar Arasaratnam <[email protected]>
    (cherry picked from commit 7b46c6a2a33376dc438c75456371669b7ebd8e40)
    Signed-off-by: Michael Niedermayer <[email protected]>
---
 libavformat/whip.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/libavformat/whip.c b/libavformat/whip.c
index fcac19d1c2..bb32816c65 100644
--- a/libavformat/whip.c
+++ b/libavformat/whip.c
@@ -263,6 +263,8 @@ typedef struct WHIPContext {
     char key_buf[MAX_CERTIFICATE_SIZE];
     /* The fingerprint of certificate, used in SDP offer. */
     char *dtls_fingerprint;
+    /* remote DTLS cert fingerprint from SDP answer (sha-256). */
+    char *remote_fingerprint;
     /**
      * This represents the material used to build the SRTP master key. It is
      * generated by DTLS and has the following layout:
@@ -880,6 +882,17 @@ static int parse_answer(AVFormatContext *s)
                 ret = AVERROR(ENOMEM);
                 goto end;
             }
+        } else if (av_strstart(line, "a=fingerprint:", &ptr) && 
!whip->remote_fingerprint) {
+            /* SDP a=fingerprint format is "<algo> <hex:hex:...>". Skip
+             * the algo token, store the hex string for post-handshake 
compare. */
+            const char *space = strchr(ptr, ' ');
+            if (space) {
+                whip->remote_fingerprint = av_strdup(space + 1);
+                if (!whip->remote_fingerprint) {
+                    ret = AVERROR(ENOMEM);
+                    goto end;
+                }
+            }
         } else if (av_strstart(line, "a=candidate:", &ptr) && 
!whip->ice_protocol) {
             if (ptr && av_stristr(ptr, "host")) {
                 /* Refer to RFC 5245 15.1 */
@@ -929,6 +942,17 @@ static int parse_answer(AVFormatContext *s)
         goto end;
     }
 
+    /* per RFC 8829/8842, SDP answer MUST carry a=fingerprint and that
+     * fingerprint MUST match the DTLS peer certificate. Without it, an
+     * on-path attacker can complete DTLS with an arbitrary self-signed
+     * certificate and the resulting SRTP session is unauthenticated. */
+    if (!whip->remote_fingerprint || !strlen(whip->remote_fingerprint)) {
+        av_log(whip, AV_LOG_ERROR,
+               "No remote DTLS fingerprint in SDP answer; refusing 
unauthenticated session\n");
+        ret = AVERROR(EINVAL);
+        goto end;
+    }
+
     if (whip->state < WHIP_STATE_NEGOTIATED)
         whip->state = WHIP_STATE_NEGOTIATED;
     whip->whip_answer_time = av_gettime();
@@ -1876,6 +1900,7 @@ static av_cold void whip_deinit(AVFormatContext *s)
     ff_srtp_free(&whip->srtp_recv);
     ffurl_close(whip->dtls_uc);
     ffurl_closep(&whip->udp);
+    av_freep(&whip->remote_fingerprint);
 }
 
 static int whip_check_bitstream(AVFormatContext *s, AVStream *st, const 
AVPacket *pkt)

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to