PR #23408 opened by Thomas Devoogdt (ThomasDevoogdt) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23408 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23408.patch
Add a minimal MIKEY ([RFC 3830](https://www.rfc-editor.org/info/rfc3830/)) PSK-INIT decoder (`ff_mikey_parse`) that extracts SRTP master key, salt, SSRC and ROC from SDP `a=key-mgmt:mikey` attributes ([RFC 4567](https://www.rfc-editor.org/info/rfc4567/)). Only the subset required for RTSPS is implemented: PSK-INIT messages (data_type 0) with NULL encryption and NULL MAC inside the KEMAC payload, carrying a TEK or TEK+SALT key data sub-payload ([RFC 3830 Section 6.13](https://www.rfc-editor.org/info/rfc3830/#section-6.13)). Any unsupported variant returns AVERROR_PATCHWELCOME so unhandled configurations are never silently ignored. The SRTP CS ID map entry ([RFC 3830 Section 6.1.1](https://www.rfc-editor.org/info/rfc3830/#section-6.1.1)) carries a per-stream SSRC and Roll-Over Counter alongside the key material. Both are now extracted and applied after `ff_srtp_set_crypto()`: - `SRTPContext.roc` is initialised from the MIKEY ROC so that the HMAC index computation starts at the correct packet count rather than 0. Without this every SRTP HMAC verification fails when the server has already sent packets before the client connects. - `RTPDemuxContext.ssrc` is set from the MIKEY SSRC when non-zero and not already supplied by an SDP `a=ssrc:` attribute ([RFC 5576](https://www.rfc-editor.org/info/rfc5576/)). A MIKEY SSRC of 0 means the sender did not know the SSRC at key-exchange time ([RFC 3830 Section 6.1.1](https://www.rfc-editor.org/info/rfc3830/#section-6.1.1)) and is ignored. The decoded key material is fed into `ff_srtp_set_crypto()` via the existing crypto_suite/crypto_params fields on RTSPStream, following the same path as [RFC 4568](https://www.rfc-editor.org/info/rfc4568/) `a=crypto:`. Also fix the RTSPS handler unconditionally forcing lower_transport_mask to TCP. RTSPS secures only the RTSP signalling channel; the RTP/SRTP media transport is negotiated independently. Forcing TCP interleaved prevents UDP-based SRTP streams from being established. Leave lower_transport_mask untouched so the normal negotiation order applies and an explicit -rtsp_transport flag is honoured. Fixes: #10871 Signed-off-by: Thomas Devoogdt <[email protected]> >From af3ac827d4527ca03f1b4644e31a78c21cf95e90 Mon Sep 17 00:00:00 2001 From: Thomas Devoogdt <[email protected]> Date: Fri, 5 Jun 2026 23:28:22 +0200 Subject: [PATCH] avformat/rtsp: add MIKEY PSK-INIT key management for SRTP over RTSPS Add a minimal MIKEY (RFC 3830) PSK-INIT decoder (ff_mikey_parse) that extracts SRTP master key, salt, SSRC and ROC from SDP a=key-mgmt:mikey attributes (RFC 4567). Only the subset required for RTSPS is implemented: PSK-INIT messages (data_type 0) with NULL encryption and NULL MAC inside the KEMAC payload, carrying a TEK or TEK+SALT key data sub-payload (RFC 3830 Section 6.13). Any unsupported variant returns AVERROR_PATCHWELCOME so unhandled configurations are never silently ignored. The SRTP CS ID map entry (RFC 3830 Section 6.1.1) carries a per-stream SSRC and Roll-Over Counter alongside the key material. Both are now extracted and applied after ff_srtp_set_crypto(): - SRTPContext.roc is initialised from the MIKEY ROC so that the HMAC index computation starts at the correct packet count rather than 0. Without this every SRTP HMAC verification fails when the server has already sent packets before the client connects. - RTPDemuxContext.ssrc is set from the MIKEY SSRC when non-zero and not already supplied by an SDP a=ssrc: attribute (RFC 5576). A MIKEY SSRC of 0 means the sender did not know the SSRC at key-exchange time (RFC 3830 Section 6.1.1) and is ignored. The decoded key material is fed into ff_srtp_set_crypto() via the existing crypto_suite/crypto_params fields on RTSPStream, following the same path as RFC 4568 a=crypto:. Also fix the RTSPS handler unconditionally forcing lower_transport_mask to TCP. RTSPS secures only the RTSP signalling channel; the RTP/SRTP media transport is negotiated independently. Forcing TCP interleaved prevents UDP-based SRTP streams from being established. Leave lower_transport_mask untouched so the normal negotiation order applies and an explicit -rtsp_transport flag is honoured. Fixes: #10871 Signed-off-by: Thomas Devoogdt <[email protected]> --- libavformat/Makefile | 2 +- libavformat/mikey.c | 416 +++++++++++++++++++++++++++++++++++++++++++ libavformat/mikey.h | 49 +++++ libavformat/rtsp.c | 34 +++- libavformat/rtsp.h | 2 + 5 files changed, 498 insertions(+), 5 deletions(-) create mode 100644 libavformat/mikey.c create mode 100644 libavformat/mikey.h diff --git a/libavformat/Makefile b/libavformat/Makefile index 0db0c7c2a9..12da915688 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -546,7 +546,7 @@ OBJS-$(CONFIG_RTP_MUXER) += rtp.o \ rtpenc_vp8.o \ rtpenc_vp9.o \ rtpenc_xiph.o -OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o httpauth.o +OBJS-$(CONFIG_RTSP_DEMUXER) += rtsp.o rtspdec.o httpauth.o mikey.o OBJS-$(CONFIG_RTSP_MUXER) += rtsp.o rtspenc.o httpauth.o OBJS-$(CONFIG_S337M_DEMUXER) += s337m.o spdif.o OBJS-$(CONFIG_SAMI_DEMUXER) += samidec.o subtitles.o diff --git a/libavformat/mikey.c b/libavformat/mikey.c new file mode 100644 index 0000000000..32f65523ea --- /dev/null +++ b/libavformat/mikey.c @@ -0,0 +1,416 @@ +/* + * MIKEY (RFC 3830) PSK-INIT key management for SRTP + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * Minimal MIKEY PSK-INIT decoder (RFC 3830). + * + * Only the subset needed to extract SRTP master key and salt from a + * PSK-INIT message carried over RTSPS is implemented: + * - data_type 0 (PSK-INIT) + * - payload chain: HDR -> T -> RAND -> KEMAC + * - KEMAC encryption: NULL (ENC_NULL = 0) + * - KEMAC MAC: NULL (MAC_NULL = 0) + * - KEY_DATA type: TEK (2) or TEK+salt (3), KV = NULL (0) + * + * Any field value outside this subset is logged at AV_LOG_ERROR and + * causes the parser to return AVERROR_PATCHWELCOME so that unsupported + * configurations are never silently ignored. + * + * Wire format is byte-aligned (each logical field occupies one or more + * full octets). See the field layout notes beside each parse step. + */ + +#include <stdio.h> +#include <string.h> + +#include "libavutil/base64.h" +#include "libavutil/error.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/log.h" + +#include "mikey.h" + +/* RFC 3830 6.1 Table 6.1.b - next-payload type identifiers */ +#define MIKEY_PT_LAST 0 +#define MIKEY_PT_KEMAC 1 +#define MIKEY_PT_T 5 +#define MIKEY_PT_RAND 11 + +/* RFC 3830 6.1 Table 6.1.a - data_type values */ +#define MIKEY_TYPE_PSK_INIT 0 + +/* RFC 3830 6.1 Table 6.1.c - PRF function */ +#define MIKEY_PRF_MIKEY_1 0 + +/* RFC 3830 6.1 Table 6.1.d - CS ID map type */ +#define MIKEY_MAP_TYPE_SRTP 0 + +/* RFC 3830 6.2 Table 6.2.a - KEMAC encryption algorithm */ +#define MIKEY_ENC_NULL 0 + +/* RFC 3830 6.2 Table 6.2.b - KEMAC MAC algorithm */ +#define MIKEY_MAC_NULL 0 + +/* RFC 3830 6.6 Table 6.6 - timestamp type */ +#define MIKEY_TS_NTP_UTC 0 + +/* RFC 3830 6.13 Table 6.13.a - KEY_DATA Type (upper nibble of byte 1). + * TGK (0) and TGK+SALT (1) require TEK derivation (Section 4.1.3), + * which is not implemented. Only TEK (2) and TEK+SALT (3) are accepted. */ +#define MIKEY_KD_TEK 2 +#define MIKEY_KD_TEK_WITH_SALT 3 + +/* Fixed sizes */ +#define MIKEY_HDR_SIZE 10 /* common header without CS ID map */ +#define MIKEY_CS_SRTP_SIZE 9 /* per-CS SRTP map: policy(1)+SSRC(4)+ROC(4) */ +#define MIKEY_RAND_MIN_LEN 16 /* RFC 3830 6.11: RAND SHOULD be >= 16 bytes */ +#define MIKEY_T_NTP_SIZE 8 /* RFC 3830 6.6: NTP-UTC timestamp */ + +/* Maximum supported key/salt sizes (AES-128-CM) */ +#define MIKEY_MAX_KEY_LEN 16 +#define MIKEY_MAX_SALT_LEN 14 + +int ff_mikey_parse(const char *mikey_b64, + char *suite_out, int suite_size, + char *params_out, int params_size, + uint32_t *roc_out, uint32_t *ssrc_out, + void *logctx) +{ + uint8_t raw[512]; + uint8_t key[MIKEY_MAX_KEY_LEN]; + uint8_t salt[MIKEY_MAX_SALT_LEN]; + uint8_t combined[MIKEY_MAX_KEY_LEN + MIKEY_MAX_SALT_LEN]; + const uint8_t *d; + int raw_len, remaining, key_len, salt_len, n_cs, saw_t, saw_rand; + uint8_t next_payload; + + raw_len = av_base64_decode(raw, mikey_b64, sizeof(raw)); + if (raw_len < 0) { + av_log(logctx, AV_LOG_ERROR, "MIKEY: base64 decode failed\n"); + return AVERROR_INVALIDDATA; + } + + if (raw_len < MIKEY_HDR_SIZE) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: message too short (%d bytes)\n", raw_len); + return AVERROR_INVALIDDATA; + } + + d = raw; + remaining = raw_len; + key_len = 0; + salt_len = 0; + saw_t = 0; + saw_rand = 0; + + /* RFC 3830 6.1: common header + * [0] version (must be 1) + * [1] data_type (0 = PSK-INIT) + * [2] next_payload (type of first payload after header) + * [3] V(1b) | PRF_func(7b) + * [4-7] CSB_ID (32-bit big-endian, not needed for key extraction) + * [8] #CS (number of crypto sessions) + * [9] CS_ID_map_type + */ + if (d[0] != 1) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unsupported version %u\n", d[0]); + return AVERROR_INVALIDDATA; + } + + if (d[1] != MIKEY_TYPE_PSK_INIT) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unsupported data_type %u; only PSK-INIT (%u) supported\n", + d[1], MIKEY_TYPE_PSK_INIT); + return AVERROR_PATCHWELCOME; + } + + next_payload = d[2]; + + /* RFC 3830 6.1: V flag means the initiator expects a verification-response + * message. It has no bearing on key extraction; ignore it. */ + + if ((d[3] & 0x7F) != MIKEY_PRF_MIKEY_1) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unsupported PRF function %u\n", d[3] & 0x7F); + return AVERROR_PATCHWELCOME; + } + + n_cs = d[8]; + + if (d[9] != MIKEY_MAP_TYPE_SRTP) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unsupported CS ID map type %u\n", d[9]); + return AVERROR_PATCHWELCOME; + } + + if (n_cs != 1) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: only single-CS messages supported (got %d)\n", n_cs); + return AVERROR_PATCHWELCOME; + } + + if (remaining < MIKEY_HDR_SIZE + n_cs * MIKEY_CS_SRTP_SIZE) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: message truncated in CS ID map\n"); + return AVERROR_INVALIDDATA; + } + + /* + * RFC 3830 6.1.1: SRTP CS ID map entry (9 bytes per CS): + * [0] policy_no + * [1-4] SSRC (32-bit big-endian) + * [5-8] ROC (32-bit big-endian) + */ + *ssrc_out = AV_RB32(d + MIKEY_HDR_SIZE + 1); + *roc_out = AV_RB32(d + MIKEY_HDR_SIZE + 5); + + d += MIKEY_HDR_SIZE + n_cs * MIKEY_CS_SRTP_SIZE; + remaining -= MIKEY_HDR_SIZE + n_cs * MIKEY_CS_SRTP_SIZE; + + /* RFC 3830 5.3: walk the payload chain */ + while (next_payload != MIKEY_PT_LAST && remaining > 0) { + uint8_t pt = next_payload; + + switch (pt) { + + case MIKEY_PT_T: { + /* + * RFC 3830 6.6: timestamp payload + * [0] next_payload + * [1] TS_type (0 = NTP-UTC) + * [2-9] 8-byte NTP-UTC timestamp + */ + if (remaining < 2) + goto err_truncated; + next_payload = d[0]; + if (d[1] != MIKEY_TS_NTP_UTC) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unsupported timestamp type %u\n", d[1]); + return AVERROR_PATCHWELCOME; + } + if (remaining < 2 + MIKEY_T_NTP_SIZE) + goto err_truncated; + saw_t = 1; + d += 2 + MIKEY_T_NTP_SIZE; + remaining -= 2 + MIKEY_T_NTP_SIZE; + break; + } + + case MIKEY_PT_RAND: { + /* + * RFC 3830 6.11: RAND payload + * [0] next_payload + * [1] rand_len + * [2 .. 2+rand_len-1] random bytes + */ + uint8_t rand_len; + if (remaining < 2) + goto err_truncated; + next_payload = d[0]; + rand_len = d[1]; + if (rand_len < MIKEY_RAND_MIN_LEN) + av_log(logctx, AV_LOG_WARNING, + "MIKEY: RAND too short (%u < %u)\n", + rand_len, MIKEY_RAND_MIN_LEN); + if (remaining < 2 + (int)rand_len) + goto err_truncated; + saw_rand = 1; + d += 2 + rand_len; + remaining -= 2 + rand_len; + break; + } + + case MIKEY_PT_KEMAC: { + /* + * RFC 3830 6.2: KEMAC payload + * [0] next_payload (must be PT_LAST for PSK-INIT) + * [1] enc_alg (must be ENC_NULL) + * [2-3] enc_len (length of encrypted data, BE16) + * [4 .. 4+enc_len-1] encrypted key-data region + * [4+enc_len] mac_alg (must be MAC_NULL) + * + * RFC 3830 6.13: KEY_DATA sub-payload inside the encrypted region + * [0] Next payload (0 = last; only one sub-payload supported) + * [1] Type(4b) | KV(4b) + * [2-3] Key data len (BE16) + * [4 .. 4+key_len-1] Key data + * if type == MIKEY_KD_TEK_WITH_SALT: + * [4+key_len .. 4+key_len+1] salt_len (BE16) + * [4+key_len+2 .. ...] salt bytes + */ + const uint8_t *enc_data; + uint8_t enc_alg, mac_alg, sub_next, type_kv, kd_type, kv_type; + uint16_t enc_len, kd_key_len; + int has_salt, pos; + + if (remaining < 5) + goto err_truncated; + + /* RFC 3830 3.1: PSK-INIT ordering requires T and RAND before KEMAC */ + if (!saw_t || !saw_rand) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: T and RAND payloads must precede KEMAC\n"); + return AVERROR_INVALIDDATA; + } + + enc_alg = d[1]; + enc_len = AV_RB16(d + 2); + + /* RFC 3830 4.2.3: assert NULL encryption */ + if (enc_alg != MIKEY_ENC_NULL) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: KEMAC encryption alg %u not supported; " + "only NULL (%u) is accepted over RTSPS\n", + enc_alg, MIKEY_ENC_NULL); + return AVERROR_PATCHWELCOME; + } + + if (remaining < 5 + (int)enc_len) + goto err_truncated; + + mac_alg = d[4 + enc_len]; + + /* RFC 3830 4.2.4: assert NULL MAC */ + if (mac_alg != MIKEY_MAC_NULL) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: KEMAC MAC alg %u not supported; " + "only NULL (%u) is accepted over RTSPS\n", + mac_alg, MIKEY_MAC_NULL); + return AVERROR_PATCHWELCOME; + } + + if (d[0] != MIKEY_PT_LAST) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: additional payloads after KEMAC not supported\n"); + return AVERROR_PATCHWELCOME; + } + + /* Parse KEY_DATA sub-payload */ + enc_data = d + 4; + if (enc_len < 4) + goto err_truncated; + + sub_next = enc_data[0]; + if (sub_next != MIKEY_PT_LAST) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: multiple KEY_DATA sub-payloads not supported\n"); + return AVERROR_PATCHWELCOME; + } + + type_kv = enc_data[1]; + kd_type = (type_kv >> 4) & 0x0F; + kv_type = type_kv & 0x0F; + + if (kv_type != 0) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: KEY_DATA KV type %u not supported; " + "only NULL (0)\n", kv_type); + return AVERROR_PATCHWELCOME; + } + + if (kd_type != MIKEY_KD_TEK && kd_type != MIKEY_KD_TEK_WITH_SALT) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unsupported KEY_DATA type %u\n", kd_type); + return AVERROR_PATCHWELCOME; + } + + has_salt = (kd_type == MIKEY_KD_TEK_WITH_SALT); + kd_key_len = AV_RB16(enc_data + 2); + + if (!kd_key_len || (int)enc_len < 4 + (int)kd_key_len) + goto err_truncated; + + if (kd_key_len > MIKEY_MAX_KEY_LEN) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: key too large (%u > %d)\n", + kd_key_len, MIKEY_MAX_KEY_LEN); + return AVERROR_INVALIDDATA; + } + + key_len = kd_key_len; + memcpy(key, enc_data + 4, key_len); + pos = 4 + key_len; + + if (has_salt) { + uint16_t kd_salt_len; + if ((int)enc_len < pos + 2) + goto err_truncated; + kd_salt_len = AV_RB16(enc_data + pos); + pos += 2; + if (!kd_salt_len || (int)enc_len < pos + (int)kd_salt_len) + goto err_truncated; + if (kd_salt_len > MIKEY_MAX_SALT_LEN) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: salt too large (%u > %d)\n", + kd_salt_len, MIKEY_MAX_SALT_LEN); + return AVERROR_INVALIDDATA; + } + salt_len = kd_salt_len; + memcpy(salt, enc_data + pos, salt_len); + } else { + av_log(logctx, AV_LOG_WARNING, + "MIKEY: no salt in KEY_DATA, using zero salt\n"); + salt_len = MIKEY_MAX_SALT_LEN; + memset(salt, 0, salt_len); + } + + goto done; + } + + default: + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unknown payload type %u\n", pt); + return AVERROR_INVALIDDATA; + } + } + + av_log(logctx, AV_LOG_ERROR, "MIKEY: no KEMAC payload found\n"); + return AVERROR_INVALIDDATA; + +err_truncated: + av_log(logctx, AV_LOG_ERROR, "MIKEY: message truncated\n"); + return AVERROR_INVALIDDATA; + +done: + /* Derive SRTP suite name from key length */ + if (key_len == 16) { + snprintf(suite_out, suite_size, "AES_CM_128_HMAC_SHA1_80"); + } else { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: unsupported key length %d\n", key_len); + return AVERROR_PATCHWELCOME; + } + + /* + * ff_srtp_set_crypto() expects params as base64(master_key || master_salt), + * i.e. 16 + 14 = 30 raw bytes -> 40 base64 characters. + */ + memcpy(combined, key, key_len); + memcpy(combined + key_len, salt, salt_len); + + if (!av_base64_encode(params_out, params_size, combined, key_len + salt_len)) { + av_log(logctx, AV_LOG_ERROR, + "MIKEY: params output buffer too small\n"); + return AVERROR(EINVAL); + } + + return 0; +} diff --git a/libavformat/mikey.h b/libavformat/mikey.h new file mode 100644 index 0000000000..6b2df28c4e --- /dev/null +++ b/libavformat/mikey.h @@ -0,0 +1,49 @@ +/* + * MIKEY (RFC 3830) PSK-INIT key management for SRTP + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_MIKEY_H +#define AVFORMAT_MIKEY_H + +#include <stdint.h> + +/** + * Parse a base64-encoded MIKEY PSK-INIT message from an SDP a=key-mgmt:mikey + * attribute and extract SRTP key material for ff_srtp_set_crypto(). + * + * Supported: PSK-INIT (data_type 0), NULL encryption, NULL MAC (RFC 3830). + * Any other variant returns AVERROR_PATCHWELCOME. + * + * @param mikey_b64 NUL-terminated base64 MIKEY PDU. + * @param suite_out Output buffer for the SRTP suite name (e.g. "AES_CM_128_HMAC_SHA1_80"). + * @param suite_size Size of suite_out in bytes. + * @param params_out Output buffer for the base64-encoded key || salt string. + * @param params_size Size of params_out in bytes. + * @param roc_out Initial Roll-Over Counter from the MIKEY CS ID map. + * @param ssrc_out SSRC from the MIKEY CS ID map. + * @param logctx Logging context (may be NULL). + * @return 0 on success, negative AVERROR on failure. + */ +int ff_mikey_parse(const char *mikey_b64, + char *suite_out, int suite_size, + char *params_out, int params_size, + uint32_t *roc_out, uint32_t *ssrc_out, + void *logctx); + +#endif /* AVFORMAT_MIKEY_H */ diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 45b62c4188..2c2841958c 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -56,6 +56,7 @@ #include "tls.h" #include "rtpenc.h" #include "mpegts.h" +#include "mikey.h" #include "version.h" /* Default timeout values for read packet in seconds */ @@ -691,6 +692,27 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, p += strspn(p, SPACE_CHARS); if (av_strstart(p, "inline:", &p)) get_word(rtsp_st->crypto_params, sizeof(rtsp_st->crypto_params), &p); + } else if (av_strstart(p, "key-mgmt:", &p) && s->nb_streams > 0) { + // RFC 4567 + char keymgmt_b64[512]; + rtsp_st = rt->rtsp_streams[rt->nb_rtsp_streams - 1]; + p += strspn(p, SPACE_CHARS); + if (av_strstart(p, "mikey", &p)) { + p += strspn(p, SPACE_CHARS); + get_word(keymgmt_b64, sizeof(keymgmt_b64), &p); + if (ff_mikey_parse(keymgmt_b64, + rtsp_st->crypto_suite, + sizeof(rtsp_st->crypto_suite), + rtsp_st->crypto_params, + sizeof(rtsp_st->crypto_params), + &rtsp_st->crypto_roc, + &rtsp_st->crypto_ssrc, s) < 0) + av_log(s, AV_LOG_WARNING, + "Failed to parse MIKEY key-mgmt attribute\n"); + } else { + av_log(s, AV_LOG_WARNING, + "Unsupported key-mgmt protocol in SDP: %.20s\n", p); + } } else if (av_strstart(p, "source-filter:", &p)) { int exclude = 0; get_word(buf1, sizeof(buf1), &p); @@ -916,10 +938,15 @@ int ff_rtsp_open_transport_ctx(AVFormatContext *s, RTSPStream *rtsp_st) rtsp_st->dynamic_protocol_context, rtsp_st->dynamic_handler); } - if (rtsp_st->crypto_suite[0]) + if (rtsp_st->crypto_suite[0]) { ff_rtp_parse_set_crypto(rtsp_st->transport_priv, rtsp_st->crypto_suite, rtsp_st->crypto_params); + if (rtsp_st->crypto_roc) + rtpctx->srtp.roc = rtsp_st->crypto_roc; + if (rtsp_st->crypto_ssrc && !rtpctx->ssrc) + rtpctx->ssrc = rtsp_st->crypto_ssrc; + } } return 0; @@ -1914,9 +1941,8 @@ redirect: host, sizeof(host), &port, path, sizeof(path), s->url); if (!strcmp(proto, "rtsps")) { - lower_rtsp_proto = "tls"; - default_port = RTSPS_DEFAULT_PORT; - rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP; + lower_rtsp_proto = "tls"; + default_port = RTSPS_DEFAULT_PORT; } else if (!strcmp(proto, "satip")) { av_strlcpy(proto, "rtsp", sizeof(proto)); rt->server_type = RTSP_SERVER_SATIP; diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index 3c9c2c842d..f824c4e70c 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -516,6 +516,8 @@ typedef struct RTSPStream { char crypto_suite[40]; char crypto_params[100]; + uint32_t crypto_roc; + uint32_t crypto_ssrc; } RTSPStream; void ff_rtsp_parse_line(AVFormatContext *s, -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
