From 0841fe74973c68f875a6436f61abdc02ea5bc398 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 30e71b17f7..0203cdb201 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 */ @@ -917,6 +923,8 @@ struct ast_sip_endpoint { unsigned int stir_shaken; /*! 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 2fa98da531..ddcf8fc2d4 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -712,9 +712,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"); @@ -1080,6 +1091,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) @@ -1124,25 +1144,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 54dfe85b20..217a63f7c4 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -2522,10 +2522,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); @@ -2937,10 +2945,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