-
Notifications
You must be signed in to change notification settings - Fork 814
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
Add the option to check the source address of ClientHello message on DTLS-SRTP #4261
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make sure this is tested with various scenarios, e.g:
- with & without ICE,
- ICE chooses TURN & STUN/host as valid candidate.
* | ||
* Default value: 0 | ||
*/ | ||
#ifndef PJMEDIA_SRTP_DTLS_CHECK_HELLO_ADDR |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need a compile-time setting? and why is the default 0 if it may cause a security issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might add a slight delay in starting the handshake (wait for the transport address and RTP source address to be available) and possible issues when using aggressive nomination.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reading the pdf, I believe the address check should be made mandatory for ICE, and the address should match one of the verified (valid?) candidates obtained during ICE check, so there should be no delay because ICE check has been done.
For no-ICE, then you can use the compile-time setting, because the best we can do is compare it with the SDP address, which may not be accurate.
When using this option, it is recommended to use regular nomination for ICE. When enabling STUN with aggressive nomination might result in a different candidate pair type being used between endpoints and preventing the handshake. |
This is the case when using ICE with STUN (aggressive nomination):
|
For trickle ICE, the candidates may be added rapidly while app is allowed to send/recv data before the ICE nego is completed. So if the proposed feature is on, perhaps it should indeed check the source address against all remote candidates. This may be applicable for aggressive mode too. |
- The check will always be performed when ICE is use - Check the RTP/RTPC address against the candidate when ICE is use
So now, does it work for aggressive & trickle modes? |
Yes, now working with aggressive and trickle |
For ICE: If no ICE is used: |
It looks like "verified" is specific to the recommendation, not really ICE things? |
Correct. ICE itself doesn't use the term "verified", and the document explains it in the media consent verification phase, which means that that the other party is the peer they claim to be. So this way, security can be achieved.
Yes, this is fine too. So, it means that |
Yes. Note that in ICE, the status belongs to pair-check instead of candidate, a remote candidate may be paired (& checked) against multiple local candidates. If DTLS just needs to list remote candidates that has been checked, it can be done but needs to be clarified in the docs. |
There's an issue when using aggressive nomination/trickle:
Controlled side:
Check 1 connectivity check was received late, so the controlling side will use Check 3 instead and fail the Check 1. |
It looks like it's caused by pjproject/pjnath/src/pjnath/ice_session.c Lines 1734 to 1741 in f986ad8
pjproject/pjnath/include/pjnath/config.h Lines 352 to 360 in f986ad8
I don't quite understand the reasoning why we enable this setting by default though, especially about the statement |
After setting |
Yes, we need to check against all verified remote candidates. According to my understanding (let me know if this is not correct), a verified remote candidate is a remote candidate that has successfully sent an ICE check to us. |
I assume
|
From the docs:
I think we can interpret it as: So I agree with @sauwming that a verified remote candidate is a remote candidate that has successfully sent an ICE check to us, with additional note, it uses the correct user & pass (I think our ICE/STUN implementation has checked the user/pass before responding, need to verify though). IIRC ICE doesn't maintain a list of them. Furthermore, if ICE is active, what if we put the source check in ICE itself, e.g: in pj_ice_sess_on_rx_pkt(), and as usual, it is better configurable. |
- Remove the enum candidate APIs - Move the source checking for ICE - Use the remote candidate which has received STUN request or has completed the connectivity check as a valid source - Don't send respond to STUN request with USE-CANDIDATE when the ICE is completed.
pjnath/src/pjnath/ice_session.c
Outdated
} | ||
PJ_LOG(2, (ice->obj_name, "Ignoring incoming message for " | ||
"component [%d], from src addr [%s]", | ||
comp_id, psrc_addr)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Specify the reason of ignoring, e.g: s/"component [%d], from src addr [%s]"/"component %d because source address %s is unrecognized"? Note that
pj_sockaddr_print(..,3)
will also print bracket for IPv6. - Won't log level 2 be too verbose for low level API, perhaps 4?
"no need to send response")); | ||
pj_grp_lock_release(ice->grp_lock); | ||
return PJ_SUCCESS; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part seems rather OOT and change the ICE flow/algo? Usually this kind of changes is specified (including the reason) in the PR desc.
pjnath/include/pjnath/ice_session.h
Outdated
* | ||
* Default value is PJ_ICE_SESS_CHECK_SRC_ADDR. | ||
*/ | ||
unsigned check_src_addr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not boolean?
dtls_srtp_ice_cand ice_rem_cand[NUM_CHANNEL]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still used?
typedef struct dtls_srtp_ice_cand | ||
{ | ||
unsigned cand_cnt; | ||
pj_sockaddr cand_addr[PJ_ICE_MAX_CAND]; | ||
} dtls_srtp_ice_cand; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still used?
* has been successful for this candidate. | ||
* | ||
*/ | ||
pj_bool_t checked; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to specify that this flag is only used by remote candidate?
@@ -1361,6 +1374,50 @@ static pj_status_t dtls_on_recv(pjmedia_transport *tp, unsigned idx, | |||
(ds->setup == DTLS_SETUP_ACTPASS || ds->setup == DTLS_SETUP_PASSIVE)) | |||
{ | |||
pj_status_t status; | |||
pj_bool_t check_hello_addr = PJ_FALSE; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed if the check is already done in ICE?
And if we don't use ICE, should we compare it against the SDP?
I don't mind if we don't, but we need to document it somewhere
@@ -3734,6 +3746,29 @@ PJ_DEF(pj_status_t) pj_ice_sess_on_rx_pkt(pj_ice_sess *ice, | |||
|
|||
PJ_RACE_ME(5); | |||
|
|||
if (ice->opt.check_src_addr) { | |||
for (i = 0; i < ice->rcand_cnt; ++i) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this slow down ICE tp considerably, if we have to iterate through all remote candidates for every packet?
There is a possible issue with
DTLS
“ClientHello” Race Conditions leading to DDoS attack.This is done by sending a malicious DTLS ClientHello message from any
IP address to the expected port, potentially causing a “network race condition” if the malicious
messages is processed before the legitimate one.
For ICE use, this patch will add
pj_ice_sess_options::check_src_addr
andPJ_ICE_SESS_CHECK_SRC_ADDR
to allow ICE sessionto check the source against the 'verified' remote candidate. i.e.: remote candidates which has
a completed connectivity check or received a connectivity check.
For non-ICE use, this patch will add the option (
PJMEDIA_SRTP_DTLS_CHECK_HELLO_ADDR
) to enable checking the source address of the "ClientHello" message is coming from the source specified in the SDP.This patch will also add the change related to ICE behavior:
pjproject/pjnath/src/pjnath/ice_session.c
Lines 2720 to 2727 in 205baf0
However, the STUN request itself has been answered previously. In an aggressive nomination setting, this will be problematic since this will indicate that the new nomination was accepted. In this case, we can ignore the new nomination.