Skip to content

Conversation

@amubiera
Copy link
Contributor

@amubiera amubiera commented Oct 26, 2025

This PR attempts to allow multiple keying methods to be offered by a caller that has both SDES and DTLS keying methods enabled.

The purpose is to have a PJSIP-based client that can call an endpoint that only supports one keying method.
i.e. Caller enables keying[SDES, DTLS] and attempts to call a client that only accepts DTLS. The SDP line should include both crypto and fingerprint and not just crypto.

This prevents having to agree ahead of time on what key exchange method to use between clients.

For example:

...
m=audio 61813 UDP/TLS/RTP/SAVP 9 120
a=crypto:1 AES_256_CM_HMAC_SHA1_80 inline:LBNmzgnWiJiRYuNsEzUJJDbPhCbv89EFyjJHf9wXIpAiweS3JjEBeDJCDqCbvw==
a=crypto:2 AES_256_CM_HMAC_SHA1_32 inline:rs43/wcKQvpx/rW7BE+Z3Kw9ctXl8d+uLNv/yVPCwtqhoHS+7bbBiAkx6ZM0Sw==
a=crypto:3 AES_CM_128_HMAC_SHA1_80 inline:URF7iv+U7XFsqiWMmPYMPOuIqz3qjQjmLW/qP5+x
a=crypto:4 AES_CM_128_HMAC_SHA1_32 inline:08xQbX6lbROmI6H2wKmrLPi0oAURF0eRftsfzgEv
a=fingerprint:SHA-256 7A:89:37:BC:1E:DF:7A:81:86:71:E7:D9:10:6D:AD:2C:26:12:63:FF:00:31:81:52:82:E0:63:2A:23:47:A4:05

The main change is to remove the offerer_side check in transport_media_create that forces selection of the first keying method. This allows both keying methods to be added during the SDP creation.

} else if (srtp->offerer_side) {
    /* Currently we can send one keying only in outgoing offer */
    srtp->keying[0] = srtp->keying[i];
    srtp->keying_cnt = 1;
    break;
}

This works for the caller. However, if PJSIP is the callee, transport_srtp_sdes will exclude itself because the media line is the full UDP/TLS/RTP/SAVP and not exactly RTP/SAVP. So the second change is to 'drop' the UDP/TLS flags from the remote protocol line when checking the SDP in the callee in a few places.

/* Drop DTLS proto if crypto is present */
if (pjmedia_sdp_media_find_attr(m, &ID_CRYPTO, NULL) != NULL)
    PJMEDIA_TP_PROTO_TRIM_FLAG(rem_proto, PJMEDIA_TP_PROTO_DTLS);

^^^ this allows transport_srtp_sdes and transport_srtp_dtls to accept the SDP as valid since crypto and fingerprint are both available.

A few alternatives to sprinkling this in transport_srtp_sdes is perhaps to:

  • Remove the UDP/TLS flags from the caller side but that doesn't seem quite right.
  • Use & instead of != for checking rem_proto != PJMEDIA_TP_PROTO_RTP_SAVP.
  • Add a new m=audio line that also has UDP/TLS but maybe that complicates other aspects.

In the end the callee should select the first keying method that it supports (in transport_media_start).

So all the permutations should work:

  • Caller [SDES] -> Callee [SDES] -> Callee selects SDES
  • Caller [DTLS] -> Callee [SDES] -> Callee rejects the call
  • Caller [SDES] -> Callee [DTLS] -> Callee rejects the call
  • Caller [DTLS] -> Callee [DTLS] -> Callee selects DTLS
  • Caller [SDES, DTLS] -> Callee [SDES] -> Callee selects SDES
  • Caller [DTLS, SDES] -> Callee [SDES] -> Callee selects SDES
  • Caller [SDES, DTLS] -> Callee [DTLS] -> Callee selects DTLS
  • Caller [DTLS, SDES] -> Callee [DTLS] -> Callee selects DTLS
  • Caller [SDES, DTLS] -> Callee [SDES, DTLS] -> Callee selects SDES
  • Caller [DTLS, SDES] -> Callee [DTLS, SDES] -> Callee selects DTLS
  • etc...

I can't find anything in the standard that prevents both keying methods to be offered RFC-4568 (SDP) and RFC-8842(SDP DTLS). Though, AI searches beg to differ. But maybe it's hallucinating.

I do see a sipp scenario (tests/pjsua/scripts-sipp/uac-srtp-dtls.xml) that offers both. But maybe that is to do some negative testing.

I'm still testing this with various clients as caller/callee. Please let me know if you have any input or if there is another approach to enabling this functionality. Also, any pointers to add tests for this would be great.

Thanks!

@sauwming
Copy link
Member

sauwming commented Nov 3, 2025

After manually checking the relevant RFC sections, it looks like that this shouldn't be allowed since the media transport profiles are different (UDP/TLS/RTP/SAVP vs RTP/SAVP). But then we also have encountered some remote who offer both (see 952ddfb). Since @nanangizz is the original implementor of DTLS, perhaps he has some insights for this?

One thing for certain is that should we go ahead with this, we need to have an option to enable/disable it with the default disabled since could cause interoperability issue for endpoints that do not expect to see both SDES and DTLS in the same media (which could cause it reject such offer). A compile-time option would be easier to implement but rather cumbersome to test, while a runtime setting can be easily checked with a Sipp scenario.

@sauwming sauwming requested a review from nanangizz November 3, 2025 02:06
@nanangizz
Copy link
Member

Which transport/proto is used in the SDP m= line, or should it be configurable?
Note that, from https://datatracker.ietf.org/doc/html/rfc5764#section-8:

When a RTP/SAVP or RTP/SAVPF stream is transported over DTLS with
UDP, the token SHALL be UDP/TLS/RTP/SAVP or UDP/TLS/RTP/SAVPF
respectively.

Ideally for indicating transport capabilities, we should use this: https://datatracker.ietf.org/doc/html/rfc5939#section-4.2. Unfortunately, we don't support the RFC (yet, btw, even if we did, it may introduce its own interoperability risk :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants