New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Does libsrtp keep a static list of managed streams identified by their SSRC? #68
Comments
Sorry for the delayed response. I was on travel last week. Are you using the same srtp_ctx_t* when invoking srtp_protect() for each packet? If so, it's probably reusing the same stream context for both packets since it uses the SSRC to lookup the stream context. The replay database is under the stream context. |
Thanks for the response. I think I know what is happening:
AFAIU this is ok since the new RTP packets form peer-A are different than the previous ones, but in the server I'm overriding its SSRC value to "1234" and then pass them to the So basically, in my scenario I need to set a different SSRC before calling Thanks a lot. |
If you are using two srtp_ctx_t* references, one for peer A and one for peer B, then the err_status_replay_old error is likely due to a repeating sequence number on the context for peer B. Changing the SSRC will probably not make a difference. You'll probably have to maintain a separate RTP sequence number for peer B to make sure it's not reused after the peer A session is restarted. If you're not rekeying the context with peer B, then you shouldn't reuse that context when sending repeated packets. You'll probably want to rekey the peer B context. |
Thanks for your response. However I do not fully understand. I expect that, when calling
Is this the order? |
I would like to explain better my scenario:
All works fine. The problem happens when Peer A is restarted. Its DTLS-SRTP context is deleted (so also its outbound and inbound Then Peer A sends again RTP (note that this RTP has nothing to do with the previous one as the client has been restarted). The server performs the same steps as above, and then sometimes I get the So in this case, I understand that, indeed, the sequence numbers of those new RTP packets form Peer A may create a conflict with the previous RTP stream from Peer A, and hence the encrypt error. Am I right? If so, I understand that when Peer A is restarted and performs again the DTLS-SRTP setup, the server must choose a different SSRC value for the RTP coming from Peer A so the outbound Thanks a lot. |
Q: So in this case, I understand that, indeed, the sequence numbers of those new RTP packets form Peer A may create a conflict with the previous RTP stream from Peer A, and hence the encrypt error. Am I right? A: I believe you're correct. Peer A is likely repeating the sequence number of some packets, causing the error when you re-encrypt it for peer B (or C). Q: If so, I understand that when Peer A is restarted and performs again the DTLS-SRTP setup, the server must choose a different SSRC value for the RTP coming from Peer A so the outbound srtp_ctx_t of Peer B and Peer C will see those packets belonging to a new "stream" so there won't be sequence number problems. Am I right? A: Yes, choosing a new SSRC may resolve the issue. But it's highly recommended to rekey the session between the server and peer B (and peer C). Another approach may be to use the EKT feature in libsrtp. Unfortunately the EKT draft was never ratified. But EKT support was added to libsrtp at some point in the past. This is beyond my expertise since the EKT code was contributed by another developer. But my understanding is EKT was developed specifically to solve the problem you're addressing. You may want to take a look at the EKT draft. |
Thanks a lot! I will take a look to EKT, but first I want the "simple" case to properly work (and EKT may not be suitable for all the use-cases in my server given that in some cases it will behave as a gateway between DTLS-SRTP peers and SDES-SRTP or plain RTP peers. Anyhow, you replied:
I understand that it is recommended not to leak the session between the server and peer B (and peer C) with unused streams. What about if I do the following? Instead of setting Really thanks a lot. |
That should resolve your problem since invoking srtp_add_stream() will result in a new initialization of the anti-replay database for the stream. The streams are indexed by SSRC and normally created implicitly when using ssrc_any_outbound. You'll simply be creating the stream explicitly. But you really should rekey the other SRTP sessions to peers B & C. Otherwise you'll end up reusing the initialization vector for AES encryption, which is fatal when GCM mode is used. |
Yes. It is a different source, in fact. ALternatively, make sure the peer-B context doesn't see the source as having stopped, and modify any after-reattachment seqnums and timestamps to make the interrupted source streams appear as a single stream with an interruption. |
Does "rekey the other SRTP session to B & C" mean force a new SRTP key exchange with both peers B and C? I cannot do that just because A has re-connected as it would involve a new SDP O/A with all the conference peers every time a peer reconnects. So, is it enough if I set a new SSRC for the incoming RTP of Peer A after it reconnects to the conference?
I understand that this is not needed if I do not reuse a previously used SSRC, am I right? Thanks a lot to both. |
Yes, you would have to perform a new SRTP key exchange with both peers (B&C). I'm assuming you're using AES-CTR mode. The problem is CTR mode is a stream cipher. Any nonce reuse is considered catastrophic. Since the nonce is derived from the sequence number in the RTP packet, and you're potentially reusing sequence numbers (indicated by the error you received that started this discussion), then you're at risk for nonce reuse. The same problem is presented when using AES-GCM mode. This needs to be avoided if you wish to provide a secure solution. Take a look at EKT. It was designed with intent to solve the problem you've presented. |
Thanks a lot, but I would like to confirm that this problem:
This problem won't happen in case I do NOT reuse the same SSRC for a new stream (which replaces an old one) within the same calls to BTW: How to select AES-CTR, AES-GCM or any other mode? I don't see that in the API. Is it something that I can set when creating a srtp session or policy? or does it depend on the peer? Regarding EKT, AFAIK it just make sense when both peers use SRTP, which may not be true in my case. Even more, I'm building a conference server (which does not mix but relays all the streams to other participants). |
The SSRC is also a component into the nonce (a.k.a. IV) used for AES-CTR mode. If you're changing the SSRC, then this may help prevent nonce resuse. Bottom line, you'll need to ensure the nonce is never reused. Please refer to section 4.1.1 of RFC 3711 which warns about this and discusses the need to rekey. You'll need to understand how the nonce is derived and ensure it's never reused. Your approach of cloning the packing and hacking the SSRC may circumvent the nonce reuse checks within libsrtp. You would select the AES mode on the SRTP policy. The cipher_type member on the policy can be set to AES_ICM, AES_192_ICM, AES_256_ICM, AES_128_GCM, or AES_256_GCM. There are some other settings for this defined in crypto_types.h, but I've never seen them used and not sure if they are supported (SEAL, AES_CBC). |
Really thanks a lot. I just use Definitely I need to go in depth with RFC 3711. Will do it. I strongly appreciate all the help provided in this thread. I will close the issue given that it is not an issue :) |
Using those policy helper functions, you're using AES-CTR mode. If you want GCM mode, you can use one of the GCM policy helpers (e.g. crypto_policy_set_aes_gcm_128_8_auth). GCM mode is only supported when the --enable-openssl option is used to configure libsrtp. |
Thanks a lot for the clarification. |
I create two
srtp_t
sessions, setpolicy.ssrc.type = ssrc_any_outbound
in both of them, and then call tosrtp_protect()
to both of them by passing the same RTP packet/data with the same SSRC value in both calls (note that before callingsrtp_protect()
I do a memcpy of the original RTP data, so the original one remains unchanged when the second call tosrtp_protect()
takes place in the second session).In this scenario I get lot of
err_status_replay_old
errors ("replay check failed (index too old)").So I wonder: may be libsrtp handles a global/static list of streams so two different and independent
srtp_t
sessions should NEVER try to protect the same RTP packet?If this is true, please confirm it. Thanks a lot.
The text was updated successfully, but these errors were encountered: