diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index 30e71b17f7843a37f927d79f776c73a22ea2c1c2..0203cdb2011578e6840e536cfa4204b6a0d19315 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 59cec2c60751243470c8ed57b1b1dc537efbd289..4f35ad204748586d190bee03c295b2ef3466e4fe 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 6dec18e2da2d1387b9ba96410f803c7e0c74ffcc..ee90fd1151aa158bb558932d1a02f3442c7c365d 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -705,9 +705,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"); @@ -1051,6 +1062,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) @@ -1090,25 +1110,36 @@ static int handle_registration_response(void *data) response->client_state->registration_name, response->client_state->server_uri, response->client_state->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 f02a02c4ae0253339c3f75ca855239ca84976e9c..1c9e5a71fe36d30b6341a8397381af4f529614f0 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); @@ -2930,10 +2938,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);