diff --git a/libavformat/whip.c b/libavformat/whip.c index 47b80e9960ba0..edd9136d3ee6c 100644 --- a/libavformat/whip.c +++ b/libavformat/whip.c @@ -290,6 +290,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: @@ -921,6 +923,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 " ". 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 */ @@ -970,6 +983,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_relative(); @@ -2130,6 +2154,7 @@ static av_cold void whip_deinit(AVFormatContext *s) ffurl_closep(&whip->dtls_uc); ffurl_closep(&whip->udp); av_freep(&whip->dtls_fingerprint); + av_freep(&whip->remote_fingerprint); } static int whip_check_bitstream(AVFormatContext *s, AVStream *st, const AVPacket *pkt)