Skip to content

Commit ab0f5ba

Browse files
committed
Echo crypto suite tag of the offer SDP in the answer SDP
Currently, when Livekit generates an answer SDP, the crypto suite will have a tag value of whatever index was assigned to it by ``DefaultProfiles()``. This is a problem in case the offerer strictly validates that the tag in the answer is equal to the one in the offer. RFC 4568 section 5.1.3: ``` When the offerer receives the answer, the offerer MUST verify that one of the initially offered crypto suites and its accompanying tag were accepted and echoed in the answer ``` This patch should solve the last of the SDES-related compatibility issues with rtpengine that I encountered. Note that this does not address the fact that Livekit ignores the crypto suite tag when processing an answer SDP.
1 parent c86da91 commit ab0f5ba

2 files changed

Lines changed: 52 additions & 0 deletions

File tree

sdp/offer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,8 @@ func SelectCrypto(offer, answer []srtp.Profile, swap bool) (*srtp.Config, *srtp.
539539
prof := &off
540540
if swap {
541541
prof = &ans
542+
// Echo the cipher suite tag of the offer, in the answer
543+
prof.Index = off.Index
542544
}
543545
return c, prof, nil
544546
}

sdp/offer_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,3 +473,53 @@ a=rtcp-fb:* ccm tmmbr
473473
},
474474
v.CryptoProfiles)
475475
}
476+
477+
// TestSelectCryptoSuiteTag ensures that when selecting a crypto suite from an offer/answer pair,
478+
// the answer uses the same crypto suite tag as the offer, per RFC 4568 section 5.1.2 and 5.1.3.
479+
func TestSelectCryptoSuiteTag(t *testing.T) {
480+
answerProfiles := []srtp.Profile{
481+
{Index: 1, Profile: "AES_CM_128_HMAC_SHA1_80"},
482+
{Index: 2, Profile: "AES_CM_128_HMAC_SHA1_32"},
483+
{Index: 3, Profile: "AES_256_CM_HMAC_SHA1_80"},
484+
{Index: 4, Profile: "AES_256_CM_HMAC_SHA1_32"},
485+
}
486+
487+
cases := []struct {
488+
name string
489+
offer []srtp.Profile
490+
answer []srtp.Profile
491+
exp *srtp.Profile
492+
}{
493+
{
494+
name: "First",
495+
offer: []srtp.Profile{
496+
{Index: 1, Profile: "AES_CM_128_HMAC_SHA1_80"},
497+
{Index: 2, Profile: "AES_CM_128_HMAC_SHA1_32"},
498+
{Index: 3, Profile: "AES_256_CM_HMAC_SHA1_80"},
499+
{Index: 4, Profile: "AES_256_CM_HMAC_SHA1_32"},
500+
},
501+
answer: answerProfiles,
502+
exp: &srtp.Profile{Index: 1, Profile: "AES_CM_128_HMAC_SHA1_80"},
503+
},
504+
{
505+
name: "Fifth",
506+
offer: []srtp.Profile{
507+
{Index: 1, Profile: "AEAD_AES_256_GCM"},
508+
{Index: 2, Profile: "AEAD_AES_128_GCM"},
509+
{Index: 3, Profile: "AES_256_CM_HMAC_SHA1_80"},
510+
{Index: 4, Profile: "AES_256_CM_HMAC_SHA1_32"},
511+
{Index: 5, Profile: "AES_CM_128_HMAC_SHA1_80"},
512+
},
513+
answer: answerProfiles,
514+
exp: &srtp.Profile{Index: 5, Profile: "AES_CM_128_HMAC_SHA1_80"},
515+
},
516+
}
517+
518+
for _, c := range cases {
519+
t.Run(c.name, func(t *testing.T) {
520+
_, got, err := SelectCrypto(c.offer, c.answer, true)
521+
require.NoError(t, err)
522+
require.Equal(t, *c.exp, *got)
523+
})
524+
}
525+
}

0 commit comments

Comments
 (0)