Hi all,
I'm implementing client-initiated mediasec negotiation[2] with partial RFC
3329[1] support in the PJSIP library. My target application uses the PJSUA
interface. This is still at an early stage and since I'd like to upstream
this change I think it's best to start a discussion about the approach and
get your views on it.
Outline of expected behaviour:
- In initial REGISTER message, set the following headers:
Require: mediasec
Proxy-Require: mediasec
Security-Client: sdes-srtp; mediasec // A separate header for every
supported mechanism. At least one mechanism must be enabled for the build.
- We refer to this set of headers as the "mediasec initial headers"
- Server responds with 401 Unauthorised and a set of Security-Server
headers:
Security-Server: msrp-tls;mediasec
Security-Server: sdes-srtp;mediasec
Security-Server: dtls-srtp;mediasec
- We refer to this set of headers as the "mediasec server headers"
These headers must be stored for this session. The client must send these
to the server as Security-Verify headers in every request message for this
session.
** If the Server does not send the Security-Server headers in the REGISTER
response, registration is aborted.
- client responds to 401 Unauthorised message as usual and also adds the
following headers (the saved Security-Server headers are sent back as
Security-Verify headers):
Require: mediasec
Proxy-Require: mediasec
Security-Client: sdes-srtp; mediasec
Security-Verify: msrp-tls;mediasec
Security-Verify: sdes-srtp;mediasec
Security-Verify: dtls-srtp;mediasec
- We refer to this set of headers as the "mediasec verification headers"
- Server responds with 200 OK
- client sends INVITE request with the mediasec verification headers and
sets an additional SDP attribute:
a=3ge2ae:Requested
- Server responds with 200 OK
- Any further SIP Request messages must also include the mediasec
verification headers.
Outline of code changes:
I will send an update if I come across alternative implementation ideas.
Please let me know if the following looks like the correct way to proceed.
- Inserting the mediasec headers
sip_auth_client.c: pjsip_auth_clt_init_req() looks like the right place for
this. I inserted some test headers and they appear in all requests.
/* Initialize outgoing request. */
PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
pjsip_tx_data *tdata )
{
...
pj_strdup(tdata->pool,&hs->credential.digest.uri, &uri);
pj_strdup(tdata->pool, &hs->credential.digest.algorithm,
&sess->pref.algorithm);
}
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hs);
}
}
}
-
pjsip_hdr hdr_list;
-
pj_list_init(&hdr_list);
-
pjsip_generic_string_hdr *tmp_hdr;
-
const pj_str_t STR_PROXY_REQ = { "Proxy-Require", 13 };
-
pj_str_t security_proxy_req_val = { "mediasec", 8 };
-
tmp_hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_PROXY_REQ,
-
&security_proxy_req_val);
-
pj_list_push_back(&hdr_list, (pjsip_hdr*)tmp_hdr);
-
const pj_str_t STR_REQ = { "Require", 7 };
-
pj_str_t security_req_val = { "mediasec", 8 };
-
tmp_hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_REQ,
-
&security_req_val);
-
pj_list_push_back(&hdr_list, (pjsip_hdr*)tmp_hdr);
-
const pj_str_t STR_SECURITY_CLIENT = { "Security-Client", 15 };
-
pj_str_t security_client_val = { "sdes-srtp;mediasec", 18 };
-
tmp_hdr = pjsip_generic_string_hdr_create(tdata->pool,
&STR_SECURITY_CLIENT,
-
&security_client_val);
-
pj_list_push_back(&hdr_list, (pjsip_hdr*)tmp_hdr);
-
pjsip_hdr *hdr = hdr_list.next;
-
while (hdr != &hdr_list) {
-
pjsip_hdr *next = hdr->next;
-
pjsip_msg_add_hdr(tdata->msg, hdr);
-
hdr = next;
-
}
return PJ_SUCCESS;
}
-
Pass in a list of security negotiation parameters to
pjsip_auth_clt_init_req() that need to be added to SIP requests (instead of
hardcoded values in the above test code)
This can be done by adding a new data member to struct pjsip_auth_clt_sess
in sip_auth.h of type struct pjsip_security_neg {pj_str_t
security_param_list; pj_str_t security_client_list; pj_str_t
security_server_list;}
-
Initialise auth_clt_sess.security_neg to send the "mediasec initial
headers"
This can be done in pjsua_ac.c: pjsua_acc_set_registration()
-
New parameters to enable/disable the features
pjsua_ac.c: pjsua_acc_set_registration() should only add the headers if the
application has enabled the feature.
RFC 3329 first hop security negotiation is a separate feature that may be
fully implemented if needed by someone else in the future. The mediasec
feature works as an extension to RFC 3329. Therefore these features must
have separate flags to enable/disable.
struct pjsua_acc_config in pjsua.h can be extended to add two new fields:
pjsua_acc_config.use_first_hop_security_neg = PJ_TRUE
//enables rfc 3329 first hop security negotiation
pjsua_acc_config.use_srtp_mediasec = PJMEDIA_SRTP_MEDIASEC_ENABLE;
//enables mediasec support for SRTP. Requires
use_first_hop_security_neg = PJ_TRUE.
These can be used to set similarly named members in struct pjsua_acc in
pjsua_acc.c: pjsua_acc_add()
pjsua_acc.use_first_hop_security_neg
pjsua_acc.use_srtp_mediasec
In (3) above, pjsua_acc_set_registration() will then have access to these
parameters to check if the security negotiation headers need to be added.
- Update pjsip_auth_clt_sess.pjsip_security_neg.security_server_list when
client receives the Security-Server headers in a 401 Unauthorized message
from the server.
So far, the client is set up to only send the "mediasec initial headers" in
all SIP request messages. To create the set of "mediasec verification
headers" pjsip_auth_clt_sess.pjsip_security_neg.security_server_list must
be updated.
I'm still working on this and will send another update for that. The
options I'm exploring include implementing Security-Server header parsing
in sip_parser.c and adding it to a new field in struct pjsip_rx_data; or
extracting the info from pjsip_rx_data.msg in pjsip_auth_clt_reinit_req().
-
Instantiate the media plane security mechanism based on the client and
server side mediasec parameters. Add support sdes-srtp only for now.
-
In the INVITE message, add attribute "a=3ge2ae:requested" to the SDP
attributes
This can be done in sdp.c: print_session() based on some flags set in
struct pjmedia_sdp_session to indicate mediasec support.
Prerequisites:
PJSIP must be built with
define PJMEDIA_HAS_SRTP 1
// At least one out of SDES or DTLS support:
define PJMEDIA_SRTP_HAS_SDES 1
define PJMEDIA_SRTP_HAS_DTLS 1
References:
[1] https://tools.ietf.org/html/rfc3329
[2] https://tools.ietf.org/html/draft-dawes-dispatch-mediasec-parameter-07
Regards,
Rahul
Hi all,
I'm implementing client-initiated mediasec negotiation[2] with partial RFC
3329[1] support in the PJSIP library. My target application uses the PJSUA
interface. This is still at an early stage and since I'd like to upstream
this change I think it's best to start a discussion about the approach and
get your views on it.
Outline of expected behaviour:
1) In initial REGISTER message, set the following headers:
Require: mediasec
Proxy-Require: mediasec
Security-Client: sdes-srtp; mediasec // A separate header for every
supported mechanism. At least one mechanism must be enabled for the build.
* We refer to this set of headers as the "mediasec initial headers"
2) Server responds with 401 Unauthorised and a set of Security-Server
headers:
Security-Server: msrp-tls;mediasec
Security-Server: sdes-srtp;mediasec
Security-Server: dtls-srtp;mediasec
* We refer to this set of headers as the "mediasec server headers"
These headers must be stored for this session. The client must send these
to the server as Security-Verify headers in every request message for this
session.
** If the Server does not send the Security-Server headers in the REGISTER
response, registration is aborted.
3) client responds to 401 Unauthorised message as usual and also adds the
following headers (the saved Security-Server headers are sent back as
Security-Verify headers):
Require: mediasec
Proxy-Require: mediasec
Security-Client: sdes-srtp; mediasec
Security-Verify: msrp-tls;mediasec
Security-Verify: sdes-srtp;mediasec
Security-Verify: dtls-srtp;mediasec
* We refer to this set of headers as the "mediasec verification headers"
4) Server responds with 200 OK
5) client sends INVITE request with the mediasec verification headers and
sets an additional SDP attribute:
a=3ge2ae:Requested
6) Server responds with 200 OK
7) Any further SIP Request messages must also include the mediasec
verification headers.
Outline of code changes:
I will send an update if I come across alternative implementation ideas.
Please let me know if the following looks like the correct way to proceed.
1) Inserting the mediasec headers
sip_auth_client.c: pjsip_auth_clt_init_req() looks like the right place for
this. I inserted some test headers and they appear in all requests.
/* Initialize outgoing request. */
PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
pjsip_tx_data *tdata )
{
...
pj_strdup(tdata->pool,&hs->credential.digest.uri, &uri);
pj_strdup(tdata->pool, &hs->credential.digest.algorithm,
&sess->pref.algorithm);
}
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hs);
}
}
}
+ pjsip_hdr hdr_list;
+ pj_list_init(&hdr_list);
+ pjsip_generic_string_hdr *tmp_hdr;
+ const pj_str_t STR_PROXY_REQ = { "Proxy-Require", 13 };
+ pj_str_t security_proxy_req_val = { "mediasec", 8 };
+ tmp_hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_PROXY_REQ,
+ &security_proxy_req_val);
+ pj_list_push_back(&hdr_list, (pjsip_hdr*)tmp_hdr);
+ const pj_str_t STR_REQ = { "Require", 7 };
+ pj_str_t security_req_val = { "mediasec", 8 };
+ tmp_hdr = pjsip_generic_string_hdr_create(tdata->pool, &STR_REQ,
+ &security_req_val);
+ pj_list_push_back(&hdr_list, (pjsip_hdr*)tmp_hdr);
+ const pj_str_t STR_SECURITY_CLIENT = { "Security-Client", 15 };
+ pj_str_t security_client_val = { "sdes-srtp;mediasec", 18 };
+ tmp_hdr = pjsip_generic_string_hdr_create(tdata->pool,
&STR_SECURITY_CLIENT,
+ &security_client_val);
+ pj_list_push_back(&hdr_list, (pjsip_hdr*)tmp_hdr);
+ pjsip_hdr *hdr = hdr_list.next;
+ while (hdr != &hdr_list) {
+ pjsip_hdr *next = hdr->next;
+ pjsip_msg_add_hdr(tdata->msg, hdr);
+ hdr = next;
+ }
return PJ_SUCCESS;
}
2) Pass in a list of security negotiation parameters to
pjsip_auth_clt_init_req() that need to be added to SIP requests (instead of
hardcoded values in the above test code)
This can be done by adding a new data member to struct pjsip_auth_clt_sess
in sip_auth.h of type struct pjsip_security_neg {pj_str_t
security_param_list; pj_str_t security_client_list; pj_str_t
security_server_list;}
3) Initialise auth_clt_sess.security_neg to send the "mediasec initial
headers"
This can be done in pjsua_ac.c: pjsua_acc_set_registration()
4) New parameters to enable/disable the features
pjsua_ac.c: pjsua_acc_set_registration() should only add the headers if the
application has enabled the feature.
RFC 3329 first hop security negotiation is a separate feature that may be
fully implemented if needed by someone else in the future. The mediasec
feature works as an extension to RFC 3329. Therefore these features must
have separate flags to enable/disable.
struct pjsua_acc_config in pjsua.h can be extended to add two new fields:
pjsua_acc_config.use_first_hop_security_neg = PJ_TRUE
//enables rfc 3329 first hop security negotiation
pjsua_acc_config.use_srtp_mediasec = PJMEDIA_SRTP_MEDIASEC_ENABLE;
//enables mediasec support for SRTP. Requires
use_first_hop_security_neg = PJ_TRUE.
These can be used to set similarly named members in struct pjsua_acc in
pjsua_acc.c: pjsua_acc_add()
pjsua_acc.use_first_hop_security_neg
pjsua_acc.use_srtp_mediasec
In (3) above, pjsua_acc_set_registration() will then have access to these
parameters to check if the security negotiation headers need to be added.
5) Update pjsip_auth_clt_sess.pjsip_security_neg.security_server_list when
client receives the Security-Server headers in a 401 Unauthorized message
from the server.
So far, the client is set up to only send the "mediasec initial headers" in
all SIP request messages. To create the set of "mediasec verification
headers" pjsip_auth_clt_sess.pjsip_security_neg.security_server_list must
be updated.
I'm still working on this and will send another update for that. The
options I'm exploring include implementing Security-Server header parsing
in sip_parser.c and adding it to a new field in struct pjsip_rx_data; or
extracting the info from pjsip_rx_data.msg in pjsip_auth_clt_reinit_req().
6) Instantiate the media plane security mechanism based on the client and
server side mediasec parameters. Add support sdes-srtp only for now.
7) In the INVITE message, add attribute "a=3ge2ae:requested" to the SDP
attributes
This can be done in sdp.c: print_session() based on some flags set in
struct pjmedia_sdp_session to indicate mediasec support.
Prerequisites:
PJSIP must be built with
# define PJMEDIA_HAS_SRTP 1
// At least one out of SDES or DTLS support:
# define PJMEDIA_SRTP_HAS_SDES 1
# define PJMEDIA_SRTP_HAS_DTLS 1
References:
[1] https://tools.ietf.org/html/rfc3329
[2] https://tools.ietf.org/html/draft-dawes-dispatch-mediasec-parameter-07
Regards,
Rahul