MT#56521 support legacy non-RFC OSRTP

Change-Id: I9ba7f1d36ea061c18f8451428f8856edce074436
pull/1614/head
Richard Fuchs 2 years ago
parent 614aa1a50a
commit f8fef89f5b

@ -51,6 +51,7 @@ the following additional features are available:
+ HMAC-SHA1 packet authentication
+ Bridging between RTP and SRTP user agents
+ Opportunistic SRTP (RFC 8643)
+ Legacy non-RFC (dual `m=` line) best-effort SRTP
+ AES-GCM Authenticated Encryption (AEAD) (RFC 7714)
+ `a=tls-id` as per RFC 8842
- Support for RTCP profile with feedback extensions (RTP/AVPF, RFC 4585 and 5124)
@ -990,11 +991,24 @@ Optionally included keys are:
When processing a non-OSRTP offer, convert it to an OSRTP offer. Will result
in RTP/SRTP transcoding if the OSRTP offer is accepted.
- `accept`
- `accept-RFC`
When processing a non-OSRTP answer in response to an OSRTP offer, accept the
OSRTP offer anyway. Results in RTP/SRTP transcoding.
- `accept-legacy`
Enables support for legacy, non-RFC "best effort" SRTP offers, which
consist of media sections being advertised twice, once as plain RTP and
once as SRTP. With this option set, *rtpengine* will treat such SDPs as
SRTP SDPs, removing the duplicated media sections. This flag must be
given for both offer and answer messages.
- `accept`
Short for both `accept-RFC` and `accept-legacy`. Can be used
unconditionally in all signalling if so desired.
* `ptime`
Contains an integer. If set, changes the `a=ptime` attribute's value in the outgoing

@ -2513,7 +2513,7 @@ static void __update_media_protocol(struct call_media *media, struct call_media
&& media->protocol && media->protocol->osrtp)
{
// accept it?
if (flags->osrtp_accept)
if (flags->osrtp_accept_rfc)
;
else
media->protocol = NULL; // reject
@ -2912,7 +2912,7 @@ static int __media_init_from_flags(struct call_media *other_media, struct call_m
bf_copy_same(&other_media->media_flags, &sp->sp_flags,
SHARED_FLAG_RTCP_MUX | SHARED_FLAG_ASYMMETRIC | SHARED_FLAG_UNIDIRECTIONAL |
SHARED_FLAG_ICE | SHARED_FLAG_TRICKLE_ICE | SHARED_FLAG_ICE_LITE_PEER |
SHARED_FLAG_RTCP_FB);
SHARED_FLAG_RTCP_FB | SHARED_FLAG_LEGACY_OSRTP);
// duplicate the entire queue of offered crypto params
crypto_params_sdes_queue_clear(&other_media->sdes_in);

@ -580,8 +580,16 @@ INLINE void ng_sdes_option(struct sdp_ng_flags *out, str *s, void *dummy) {
INLINE void ng_osrtp_option(struct sdp_ng_flags *out, str *s, void *dummy) {
switch (__csh_lookup(s)) {
case CSH_LOOKUP("accept-rfc"):
case CSH_LOOKUP("accept-RFC"):
out->osrtp_accept_rfc = 1;
break;
case CSH_LOOKUP("accept-legacy"):
out->osrtp_accept_legacy = 1;
break;
case CSH_LOOKUP("accept"):
out->osrtp_accept = 1;
out->osrtp_accept_rfc = 1;
out->osrtp_accept_legacy = 1;
break;
case CSH_LOOKUP("offer"):
out->osrtp_offer = 1;

@ -80,6 +80,8 @@ struct sdp_media {
struct sdp_attributes attributes;
GQueue format_list; /* list of slice-alloc'd str objects */
enum media_type media_type_id;
unsigned int legacy_osrtp:1;
};
struct attribute_rtcp {
@ -1536,6 +1538,73 @@ static void __sdp_t38(struct stream_params *sp, struct sdp_media *media) {
}
static void sp_free(void *p) {
struct stream_params *s = p;
codec_store_cleanup(&s->codecs);
ice_candidates_free(&s->ice_candidates);
crypto_params_sdes_queue_clear(&s->sdes_params);
g_slice_free1(sizeof(*s), s);
}
// Check the list for a legacy non-RFC OSRTP offer:
// Given m= lines must be alternating between one RTP and one SRTP m= line, with matching
// types between each pair.
// If found, rewrite the list to pretend that only the SRTP m=line was given, and mark
// the session media accordingly.
// TODO: should be handled by monologue_offer_answer, without requiring OSRTP-accept to be
// set for re-invites. SDP rewriting and skipping media sections should be handled by
// associating offer/answer media sections directly with each other, instead of requiring
// the indexing to be in order and instead of requiring all sections between monologue and sdp_media
// lists to be matching.
static void legacy_osrtp_accept(struct stream_params *sp, GQueue *streams, GList *prev_media_link,
struct sdp_ng_flags *flags, unsigned int *num)
{
if (!streams->tail)
return;
if (!prev_media_link)
return;
struct stream_params *last = streams->tail->data;
if (!flags->osrtp_accept_legacy)
return;
// protocols must be known
if (!sp->protocol)
return;
if (!last->protocol)
return;
// types must match
if (sp->type_id != last->type_id)
return;
// we must be looking at a SRTP media section
if (!sp->protocol->rtp)
return;
if (!sp->protocol->srtp)
return;
// previous one must be a plain RTP section
if (!last->protocol->rtp)
return;
if (last->protocol->srtp)
return;
// is this a non-rejected SRTP section?
if (sp->rtp_endpoint.port) {
// looks ok. remove the previous one and only retain this one. mark it as such.
g_queue_pop_tail(streams);
sp_free(last);
SP_SET(sp, LEGACY_OSRTP);
struct sdp_media *prev_media = prev_media_link->data;
prev_media->legacy_osrtp = 1;
sp->index--;
(*num)--;
}
}
/* XXX split this function up */
int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *flags) {
struct sdp_session *session;
@ -1543,10 +1612,9 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl
struct stream_params *sp;
GList *l, *k;
const char *errstr;
int num;
unsigned int num = 0;
struct sdp_attribute *attr;
num = 0;
for (l = sessions->head; l; l = l->next) {
session = l->data;
@ -1662,6 +1730,8 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl
sp->protocol = &transport_protocols[sp->protocol->osrtp_proto];
}
legacy_osrtp_accept(sp, streams, k->prev, flags, &num);
// a=mid
attr = attr_get_by_id(&media->attributes, ATTR_MID);
if (attr)
@ -1707,14 +1777,6 @@ error:
return -1;
}
static void sp_free(void *p) {
struct stream_params *s = p;
codec_store_cleanup(&s->codecs);
ice_candidates_free(&s->ice_candidates);
crypto_params_sdes_queue_clear(&s->sdes_params);
g_slice_free1(sizeof(*s), s);
}
void sdp_streams_free(GQueue *q) {
g_queue_clear_full(q, sp_free);
}
@ -2797,6 +2859,13 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
for (k = session->media_streams.head; k; k = k->next) {
sdp_media = k->data;
// skip over received dummy SDP sections
if (sdp_media->legacy_osrtp) {
skip_over(chop, &sdp_media->s);
continue;
}
err = "no matching media";
if (!m)
goto error;
@ -2810,6 +2879,22 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call_monologu
goto error;
ps = rtp_ps_link->data;
// generate rejected m= line for accepted legacy OSRTP
if (MEDIA_ISSET(call_media, LEGACY_OSRTP)
&& call_media->protocol
&& call_media->protocol->srtp)
{
chopper_append_c(chop, "m=");
chopper_append_str(chop, &call_media->type);
const struct transport_protocol *prtp
= &transport_protocols[call_media->protocol->rtp_proto];
chopper_append_c(chop, " 0 ");
chopper_append_c(chop, prtp->name);
chopper_append_c(chop, " ");
chopper_append_str(chop, &call_media->format_str);
chopper_append_c(chop, "\r\n");
}
bool is_active = true;
if (flags->ice_option != ICE_FORCE_RELAY && call_media->type_id != MT_MESSAGE) {

@ -113,6 +113,7 @@ enum {
#define SHARED_FLAG_ICE_LITE_PEER 0x00000800
#define SHARED_FLAG_UNIDIRECTIONAL 0x00001000
#define SHARED_FLAG_RTCP_FB 0x00002000
#define SHARED_FLAG_LEGACY_OSRTP 0x00004000
/* struct stream_params */
#define SP_FLAG_NO_RTCP 0x00010000
@ -130,6 +131,7 @@ enum {
#define SP_FLAG_TRICKLE_ICE SHARED_FLAG_TRICKLE_ICE
#define SP_FLAG_ICE_LITE_PEER SHARED_FLAG_ICE_LITE_PEER
#define SP_FLAG_RTCP_FB SHARED_FLAG_RTCP_FB
#define SP_FLAG_LEGACY_OSRTP SHARED_FLAG_LEGACY_OSRTP
/* struct packet_stream */
#define PS_FLAG_RTP 0x00010000
@ -184,6 +186,7 @@ enum {
#define MEDIA_FLAG_ECHO 0x10000000
#define MEDIA_FLAG_BLACKHOLE 0x20000000
#define MEDIA_FLAG_REORDER_FORCED 0x40000000
#define MEDIA_FLAG_LEGACY_OSRTP SHARED_FLAG_LEGACY_OSRTP
/* access macros */
#define SP_ISSET(p, f) bf_isset(&(p)->sp_flags, SP_FLAG_ ## f)

@ -138,7 +138,8 @@ struct sdp_ng_flags {
media_handover:1,
dtls_passive:1,
dtls_reverse_passive:1,
osrtp_accept:1,
osrtp_accept_legacy:1,
osrtp_accept_rfc:1,
osrtp_offer:1,
reset:1,
egress:1,

@ -80,6 +80,185 @@ sub stun_succ {
new_call;
offer('legacy OSRTP offer, control',
{ flags => [ ] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.24
t=0 0
m=audio 6000 RTP/AVP 8
m=audio 6002 RTP/SAVP 8
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:QjnnaukLn7iwASAs0YLzPUplJkjOhTZK2dvOwo6c
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
m=audio PORT RTP/SAVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:QjnnaukLn7iwASAs0YLzPUplJkjOhTZK2dvOwo6c
a=crypto:2 AEAD_AES_256_GCM inline:CRYPTO256S
a=crypto:3 AEAD_AES_128_GCM inline:CRYPTO128S
a=crypto:4 AES_256_CM_HMAC_SHA1_80 inline:CRYPTO256
a=crypto:5 AES_256_CM_HMAC_SHA1_32 inline:CRYPTO256
a=crypto:6 AES_192_CM_HMAC_SHA1_80 inline:CRYPTO192
a=crypto:7 AES_192_CM_HMAC_SHA1_32 inline:CRYPTO192
a=crypto:8 AES_CM_128_HMAC_SHA1_32 inline:CRYPTO128
a=crypto:9 F8_128_HMAC_SHA1_80 inline:CRYPTO128
a=crypto:10 F8_128_HMAC_SHA1_32 inline:CRYPTO128
a=crypto:11 NULL_HMAC_SHA1_80 inline:CRYPTO128
a=crypto:12 NULL_HMAC_SHA1_32 inline:CRYPTO128
a=setup:actpass
a=fingerprint:sha-256 FINGERPRINT256
a=tls-id:TLS_ID
SDP
new_call;
offer('legacy OSRTP offer, accept',
{ flags => [ 'OSRTP-accept' ], 'transport-protocol' => 'RTP/AVP' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.24
t=0 0
m=audio 6004 RTP/AVP 8
m=audio 6006 RTP/SAVP 8
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:QjnnaukLn7iwASAs0YLzPUplJkjOhTZK2dvOwo6c
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
answer('legacy OSRTP offer, accept', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.24
t=0 0
m=audio 6012 RTP/AVP 8
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio 0 RTP/AVP 8
m=audio PORT RTP/SAVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:CRYPTO128
SDP
offer('legacy OSRTP offer, re-invite',
{ flags => [ 'OSRTP-accept' ] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.24
t=0 0
m=audio 0 RTP/AVP 8
m=audio 6006 RTP/SAVP 8
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:QjnnaukLn7iwASAs0YLzPUplJkjOhTZK2dvOwo6c
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
answer('legacy OSRTP offer, re-invite', { }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.24
t=0 0
m=audio 6012 RTP/AVP 8
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio 0 RTP/AVP 8
m=audio PORT RTP/SAVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:CRYPTO128
SDP
reverse_tags();
offer('legacy OSRTP offer, reverse re-invite', { SDES => 'nonew' }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.24
t=0 0
m=audio 6012 RTP/AVP 8
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio 0 RTP/AVP 8
m=audio PORT RTP/SAVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:CRYPTO128
SDP
answer('legacy OSRTP offer, reverse re-invite',
{ flags => [ 'OSRTP-accept' ] }, <<SDP);
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 198.51.100.24
t=0 0
m=audio 0 RTP/AVP 8
m=audio 6006 RTP/SAVP 8
a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:QjnnaukLn7iwASAs0YLzPUplJkjOhTZK2dvOwo6c
----------------------------------
v=0
o=- 1545997027 1 IN IP4 172.17.0.2
s=tester
c=IN IP4 203.0.113.1
t=0 0
m=audio PORT RTP/AVP 8
a=rtpmap:8 PCMA/8000
a=sendrecv
a=rtcp:PORT
SDP
if ($amr_tests) {
new_call;

Loading…
Cancel
Save