From bf9ee40b31bd9b5e8d30298c95080e1067b8453c Mon Sep 17 00:00:00 2001 From: Grzegorz Sluja <grzegorz.sluja@iopsys.eu> Date: Thu, 18 Mar 2021 08:49:22 +0100 Subject: [PATCH] Mediasec headers add dynamically based on server's response Change implementation of adding mediasec headers in REGISTER, INVITE, REINVITE, OPTIONS events to be dynamically configured based on the response from the Sip Server. Signed-off-by: Grzegorz Sluja <grzegorz.sluja@iopsys.eu> --- include/asterisk/res_pjsip.h | 8 ++++ res/res_pjsip/pjsip_options.c | 15 +++++-- res/res_pjsip_outbound_registration.c | 65 ++++++++++++++++++++------- res/res_pjsip_session.c | 33 ++++++++++---- 4 files changed, 93 insertions(+), 28 deletions(-) diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index f4cda1ea94..483a63a73e 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -818,6 +818,12 @@ struct ast_sip_endpoint_media_configuration { struct ast_stream_codec_negotiation_prefs codec_prefs_outgoing_answer; }; +/*! \brief List entry structure for list of security mechanisms */ +struct security_mechanism { + AST_LIST_ENTRY(security_mechanism) entry; + pj_str_t value[1]; +}; + /*! * \brief An entity with which Asterisk communicates */ @@ -919,6 +925,8 @@ struct ast_sip_endpoint { unsigned int allow_unauthenticated_options; /*! Support mediasec on endpoint */ unsigned int mediasec; + /*! Security mechanisms supported by peer */ + AST_LIST_HEAD_NOLOCK(, security_mechanism) security_mechanisms; }; /*! URI parameter for symmetric transport */ diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 306bac89e6..4854ff3c78 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -919,9 +919,18 @@ static int sip_options_qualify_contact(void *obj, void *arg, int flags) if (flags && flags == 494) { /* add mediasec header */ ast_debug(3,"OPTIONS: adding MEDIASEC headers\n"); - ast_sip_add_header(tdata,"Security-Verify","msrp-tls;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","sdes-srtp;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","dtls-srtp;mediasec"); + ast_sip_add_header(tdata,"Security-Client","sdes-srtp;mediasec"); + ast_sip_add_header(tdata,"Proxy-Require","mediasec"); + ast_sip_add_header(tdata,"Require","mediasec"); + + if(!AST_LIST_EMPTY(&endpoint->security_mechanisms)) { + struct security_mechanism *sec_mechanism; + AST_LIST_TRAVERSE(&endpoint->security_mechanisms, sec_mechanism, entry) { + char secVerify[pj_strlen(&sec_mechanism->value) + 1]; + ast_copy_pj_str(secVerify, &sec_mechanism->value, sizeof(secVerify)); + ast_sip_add_header(tdata,"Security-Verify",secVerify); + } + } } if (ast_sip_send_out_of_dialog_request(tdata, endpoint, diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index bc18850288..5fadd4f7f1 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -711,9 +711,20 @@ static int handle_client_registration(void *data) if (client_state->mediasec) { if (client_state->is494) { /* answer for 494 */ - ast_sip_add_header(tdata,"Security-Verify","msrp-tls;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","sdes-srtp;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","dtls-srtp;mediasec"); + struct ast_sip_endpoint *endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + client_state->registration_name); + struct security_mechanism *sec_mechanism; + if (!endpoint) { + ast_log(LOG_ERROR, "No endpoint found to add mediasec headers\n"); + return -1; + } + if(!AST_LIST_EMPTY(&endpoint->security_mechanisms)) { + AST_LIST_TRAVERSE(&endpoint->security_mechanisms, sec_mechanism, entry) { + char secVerify[pj_strlen(&sec_mechanism->value) + 1]; + ast_copy_pj_str(secVerify, &sec_mechanism->value, sizeof(secVerify)); + ast_sip_add_header(tdata,"Security-Verify",secVerify); + } + } } else { ast_sip_add_header(tdata,"Security-Client","sdes-srtp;mediasec"); @@ -1079,6 +1090,15 @@ static void save_response_fields_to_transport(struct registration_response *resp } } +/*! \brief Free any endpoint security mechanisms that have been stored */ +static void clear_endpoint_security_mechanisms(struct ast_sip_endpoint *endpoint) +{ + struct security_mechanism *sec_mechanism; + + while ((sec_mechanism = AST_LIST_REMOVE_HEAD(&endpoint->security_mechanisms, entry))) { + ast_free(sec_mechanism); + } +} /*! \brief Callback function for handling a response to a registration attempt */ static int handle_registration_response(void *data) @@ -1123,25 +1143,36 @@ static int handle_registration_response(void *data) ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n", server_uri, client_uri); - /* Add MEDIASEC headers */ + /* Store & Add MEDIASEC headers */ if (response->client_state->mediasec) { + struct ast_sip_endpoint *endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", + response->client_state->registration_name); static const pj_str_t headerName = { "Security-Server", 15 }; - pjsip_generic_string_hdr *secSrv; + pjsip_generic_string_hdr *secSrv = NULL; + + if (!endpoint) { + ast_log(LOG_ERROR, "No endpoint found to store/add mediasec headers\n"); + return -1; + } secSrv = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &headerName, NULL); - if (secSrv) { + while (secSrv) { response->client_state->is494=0; - - static const pj_str_t headerNameVrfy = { "Security-Verify", 15 }; - pjsip_generic_string_hdr *secVrfy; - secVrfy = pjsip_msg_find_hdr_by_name(tdata->msg, &headerNameVrfy, NULL); - - /* initial register doesn't contain it */ - if (! secVrfy) { - ast_debug(3, "Adding MEDIASEC headers\n"); - ast_sip_add_header(tdata,"Security-Verify","msrp-tls;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","sdes-srtp;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","dtls-srtp;mediasec"); + if(AST_LIST_EMPTY(&endpoint->security_mechanisms)) { + struct security_mechanism *sec_mechanism; + char local_info[pj_strlen(&secSrv->hvalue) + 1]; + sec_mechanism = ast_calloc(1, sizeof(*sec_mechanism) + pj_strlen(&secSrv->hvalue)); + if (!sec_mechanism) { + ast_log(LOG_ERROR, "Unable to store server security mechanisms\n"); + clear_endpoint_security_mechanisms(endpoint); + return; + } + pj_strdup_with_null(tdata->pool, &sec_mechanism->value, &secSrv->hvalue); + response->client_state->is494=0; + AST_LIST_INSERT_TAIL(&endpoint->security_mechanisms, sec_mechanism, entry); + ast_copy_pj_str(local_info, &sec_mechanism->value, sizeof(local_info)); + ast_sip_add_header(tdata,"Security-Verify",local_info); } + secSrv = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &headerName, secSrv->next); } } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 912c2bcfc4..118b30b4b8 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2515,10 +2515,18 @@ static int sip_session_refresh(struct ast_sip_session *session, } if (session->endpoint->mediasec && session->endpoint->media.rtp.encryption == AST_SIP_MEDIA_ENCRYPT_SDES) { - ast_debug(3, "INVITE: Adding MEDIASEC headers\n"); - ast_sip_add_header(tdata,"Security-Verify","msrp-tls;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","sdes-srtp;mediasec"); - ast_sip_add_header(tdata,"Security-Verify","dtls-srtp;mediasec"); + ast_debug(3, "Session Refresh: Adding MEDIASEC headers\n"); + ast_sip_add_header(tdata,"Security-Client","sdes-srtp;mediasec"); + ast_sip_add_header(tdata,"Proxy-Require","mediasec"); + ast_sip_add_header(tdata,"Require","mediasec"); + if(!AST_LIST_EMPTY(&session->endpoint->security_mechanisms)) { + struct security_mechanism *sec_mechanism; + AST_LIST_TRAVERSE(&session->endpoint->security_mechanisms, sec_mechanism, entry) { + char secVerify[pj_strlen(&sec_mechanism->value) + 1]; + ast_copy_pj_str(secVerify, &sec_mechanism->value, sizeof(secVerify)); + ast_sip_add_header(tdata,"Security-Verify",secVerify); + } + } } ast_sip_session_send_request_with_cb(session, tdata, on_response); ast_sip_session_media_state_free(active_media_state); @@ -2880,10 +2888,19 @@ int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data } if (session->endpoint->mediasec && session->endpoint->media.rtp.encryption == AST_SIP_MEDIA_ENCRYPT_SDES) { - ast_debug(3, "INVITE: Adding MEDIASEC headers\n"); - ast_sip_add_header(*tdata,"Security-Verify","msrp-tls;mediasec"); - ast_sip_add_header(*tdata,"Security-Verify","sdes-srtp;mediasec"); - ast_sip_add_header(*tdata,"Security-Verify","dtls-srtp;mediasec"); + ast_debug(3, "INVITE: Adding MEDIASEC headers\n"); + ast_sip_add_header(*tdata,"Security-Client","sdes-srtp;mediasec"); + ast_sip_add_header(*tdata,"Proxy-Require","mediasec"); + ast_sip_add_header(*tdata,"Require","mediasec"); + + if(!AST_LIST_EMPTY(&session->endpoint->security_mechanisms)) { + struct security_mechanism *sec_mechanism; + AST_LIST_TRAVERSE(&session->endpoint->security_mechanisms, sec_mechanism, entry) { + char secVerify[pj_strlen(&sec_mechanism->value) + 1]; + ast_copy_pj_str(secVerify, &sec_mechanism->value, sizeof(secVerify)); + ast_sip_add_header(*tdata,"Security-Verify",secVerify); + } + } } SCOPE_EXIT_RTN_VALUE(0); -- GitLab