diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index f4cda1ea94a5a31df9f9daafb984f7fb9a85a331..483a63a73ee3f7f1e1f7fc7ec0325efce7fd38b0 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 306bac89e683da950f83f4179dbc718be54a1ce9..4854ff3c7856cf5a1cd70e408a7b8fc77c51f078 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 bc18850288a8c84553280cdbe02b43a7b20703dd..5fadd4f7f11e323d50f59a2ce86351fc3044bd00 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 912c2bcfc462f6b51962492d229b0f34dbd0c1e4..118b30b4b87ec9a3f99b64e9665e32c725180bcf 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);