File 1-mediasec-22.1.0.patch of Package asterisk
diff -Nurp asterisk-22.1.0-orig/include/asterisk/res_pjsip.h asterisk-22.1.0/include/asterisk/res_pjsip.h
--- asterisk-22.1.0-orig/include/asterisk/res_pjsip.h 2024-11-21 18:18:07.000000000 +0100
+++ asterisk-22.1.0/include/asterisk/res_pjsip.h 2024-12-17 10:23:50.071642102 +0100
@@ -1049,6 +1049,8 @@ struct ast_sip_endpoint {
unsigned int suppress_q850_reason_headers;
/*! Ignore 183 if no SDP is present */
unsigned int ignore_183_without_sdp;
+ /*! Support mediasec on endpoint */
+ unsigned int support_mediasec;
/*! Type of security negotiation to use (RFC 3329). */
enum ast_sip_security_negotiation security_negotiation;
/*! Client security mechanisms (RFC 3329). */
diff -Nurp asterisk-22.1.0-orig/res/res_pjsip/pjsip_configuration.c asterisk-22.1.0/res/res_pjsip/pjsip_configuration.c
--- asterisk-22.1.0-orig/res/res_pjsip/pjsip_configuration.c 2024-11-21 18:18:07.000000000 +0100
+++ asterisk-22.1.0/res/res_pjsip/pjsip_configuration.c 2024-12-17 10:24:47.245243128 +0100
@@ -2277,6 +2277,7 @@ int ast_res_pjsip_initialize_configurati
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "follow_early_media_fork", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.follow_early_media_fork));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accept_multiple_sdp_answers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.accept_multiple_sdp_answers));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "suppress_q850_reason_headers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, suppress_q850_reason_headers));
+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "support_mediasec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, support_mediasec));
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "incoming_call_offer_pref", "local",
call_offer_pref_handler, incoming_call_offer_pref_to_str, NULL, 0, 0);
diff -Nurp asterisk-22.1.0-orig/res/res_pjsip/pjsip_config.xml asterisk-22.1.0/res/res_pjsip/pjsip_config.xml
--- asterisk-22.1.0-orig/res/res_pjsip/pjsip_config.xml 2024-11-21 18:18:07.000000000 +0100
+++ asterisk-22.1.0/res/res_pjsip/pjsip_config.xml 2024-12-17 10:26:17.459769349 +0100
@@ -1479,6 +1479,12 @@
several options and rules used for STIR/SHAKEN.</para>
</description>
</configOption>
+ <configOption name="support_mediasec">
+ <synopsis>Enables Medisec support for INVITE and SDP.</synopsis>
+ <description><para>
+ When this option is enabled, the Mediasec Headers are added and enforced.</para>
+ </description>
+ </configOption>
<configOption name="allow_unauthenticated_options" default="no">
<synopsis>Skip authentication when receiving OPTIONS requests</synopsis>
<description><para>
diff -Nurp asterisk-22.1.0-orig/res/res_pjsip/pjsip_options.c asterisk-22.1.0/res/res_pjsip/pjsip_options.c
--- asterisk-22.1.0-orig/res/res_pjsip/pjsip_options.c 2024-11-21 18:18:07.000000000 +0100
+++ asterisk-22.1.0/res/res_pjsip/pjsip_options.c 2024-12-17 09:58:46.925502159 +0100
@@ -803,6 +803,15 @@ static void qualify_contact_cb(void *tok
break;
}
+ /* check for 494 */
+ if (status == AVAILABLE && e->body.tsx_state.src.rdata->msg_info.msg->line.status.code == 494) {
+ /* need to resend the options request with mediasec headers */
+ ast_debug(3,"detected 494 - call sip_options_qualify_contact again with mediasec header\n");
+ sip_options_qualify_contact(contact_callback_data->contact, contact_callback_data->aor_options, 494);
+ ao2_ref(contact_callback_data, -1);
+ return;
+ }
+
/* Update the callback data with the new status, this will get handled in the AOR serializer */
contact_callback_data->status = status;
@@ -907,6 +916,14 @@ static int sip_options_qualify_contact(v
return 0;
}
+ 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");
+ }
+
if (ast_sip_send_out_of_dialog_request(tdata, endpoint,
(int)(aor_options->qualify_timeout * 1000), contact_callback_data,
qualify_contact_cb)) {
diff -Nurp asterisk-22.1.0-orig/res/res_pjsip_outbound_registration.c asterisk-22.1.0/res/res_pjsip_outbound_registration.c
--- asterisk-22.1.0-orig/res/res_pjsip_outbound_registration.c 2024-11-21 18:18:07.000000000 +0100
+++ asterisk-22.1.0/res/res_pjsip_outbound_registration.c 2024-12-17 10:39:27.541908562 +0100
@@ -206,6 +206,13 @@
header as necessary.
</para></description>
</configOption>
+ <configOption name="support_mediasec">
+ <synopsis>Enables Mediasec support for outbound REGISTER requests.</synopsis>
+ <description><para>
+ When this option is enabled, outbound REGISTER requests will advertise
+ support for Mediasec.
+ </para></description>
+ </configOption>
<configOption name="support_outbound">
<synopsis>Enables advertising SIP Outbound support (RFC5626) for outbound REGISTER requests.</synopsis>
</configOption>
@@ -371,6 +378,8 @@ struct sip_outbound_registration {
struct ast_sip_auth_vector outbound_auths;
/*! \brief Whether Path support is enabled */
unsigned int support_path;
+ /*! \brief Wether mediasec support is enabled */
+ unsigned int support_mediasec;
/*! \brief Whether Outbound support is enabled */
unsigned int support_outbound;
};
@@ -412,6 +421,8 @@ struct sip_outbound_registration_client_
unsigned int auth_rejection_permanent;
/*! \brief Determines whether SIP Path support should be advertised */
unsigned int support_path;
+ /*! \brief Wether mediasec support is enabled */
+ unsigned int support_mediasec;
/*! \brief Determines whether SIP Outbound support should be advertised */
unsigned int support_outbound;
/*! \brief Type of security negotiation to use (RFC 3329). */
@@ -436,6 +447,8 @@ struct sip_outbound_registration_client_
char *transport_name;
/*! \brief The name of the registration sorcery object */
char *registration_name;
+ /*! \brief Indicator, if there was a 494 response before */
+ unsigned int is494;
/*! \brief Expected time of registration lapse/expiration */
unsigned int registration_expires;
/*! \brief The value for the User-Agent header sent in requests */
@@ -874,6 +887,21 @@ static int handle_client_registration(vo
return -1;
}
+ /* Add some header for mediasec */
+ if (client_state->support_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");
+ }
+ else {
+ 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");
+ }
+ }
+
registration_client_send(client_state, tdata);
return 0;
@@ -1318,6 +1346,29 @@ static int handle_registration_response(
response->client_state->auth_attempted = 1;
ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",
server_uri, client_uri);
+
+ /* Add MEDIASEC headers */
+ if (response->client_state->support_mediasec) {
+ static const pj_str_t headerName = { "Security-Server", 15 };
+ pjsip_generic_string_hdr *secSrv;
+ secSrv = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &headerName, NULL);
+ if (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");
+ }
+ }
+ }
+
pjsip_tx_data_add_ref(tdata);
res = registration_client_send(response->client_state, tdata);
@@ -1345,6 +1396,8 @@ static int handle_registration_response(
if (response->expiration) {
int next_registration_round;
+ response->client_state->is494=0;
+
/* If the registration went fine simply reschedule registration for the future */
ast_debug(1, "Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
update_client_state_status(response->client_state, SIP_REGISTRATION_REGISTERED);
@@ -1363,6 +1416,8 @@ static int handle_registration_response(
}
} else {
ast_debug(1, "Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
+ response->client_state->is494=0;
+
update_client_state_status(response->client_state, SIP_REGISTRATION_UNREGISTERED);
if (PJSIP_TRANSPORT_IS_RELIABLE(response->rdata->tp_info.transport)) {
ast_sip_transport_monitor_unregister_key(response->transport_key,
@@ -1374,6 +1429,22 @@ static int handle_registration_response(
save_response_fields_to_transport(response);
} else if (response->client_state->destroy) {
/* We need to deal with the pending destruction instead. */
+ } else if (response->code == 494) {
+ if (response->client_state->is494) {
+ ast_log(LOG_WARNING, "MEDIASEC registration to '%s' with client '%s' failed (494-loop detected), stopping registration attempt\n",
+ server_uri, client_uri);
+ /* 494 loop detected! This is fatal! */
+ update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_PERMANENT);
+ /* reset is494 */
+ response->client_state->is494=0;
+ } else {
+ /* Try (initial) registration again - but now with additional headers */
+ response->client_state->is494=1;
+ ao2_ref(response->client_state, +1);
+ handle_client_registration(response->client_state);
+ ao2_ref(response, -1);
+ return 0;
+ }
} else if (response->retry_after) {
/* If we have been instructed to retry after a period of time, schedule it as such */
schedule_retry(response, response->retry_after, server_uri, client_uri);
@@ -1956,6 +2027,7 @@ static int sip_outbound_registration_per
state->client_state->max_retries = registration->max_retries;
state->client_state->retries = 0;
state->client_state->support_path = registration->support_path;
+ state->client_state->support_mediasec = registration->support_mediasec;
state->client_state->support_outbound = registration->support_outbound;
state->client_state->security_negotiation = registration->security_negotiation;
state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
@@ -2138,6 +2210,11 @@ static int unregister_task(void *obj)
if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS
&& add_configured_supported_headers(state->client_state, tdata)) {
+ if (state->client_state->support_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");
+ }
registration_client_send(state->client_state, tdata);
}
@@ -2824,6 +2901,7 @@ static int load_module(void)
ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "security_mechanisms", "", security_mechanisms_handler, security_mechanism_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_mediasec", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_mediasec));
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, user_agent));
/*
diff -Nurp asterisk-22.1.0-orig/res/res_pjsip_sdp_rtp.c asterisk-22.1.0/res/res_pjsip_sdp_rtp.c
--- asterisk-22.1.0-orig/res/res_pjsip_sdp_rtp.c 2024-11-21 18:18:07.000000000 +0100
+++ asterisk-22.1.0/res/res_pjsip_sdp_rtp.c 2024-12-17 10:40:43.124027746 +0100
@@ -1677,6 +1677,10 @@ static int add_crypto_to_stream(struct a
}
tmp = session_media->srtp;
+ if (session->endpoint->support_mediasec && ! session->inv_session->neg) {
+ attr = pjmedia_sdp_attr_create(pool, "3ge2ae", &STR_MEDSECREQ);
+ media->attr[media->attr_count++] = attr;
+ }
do {
crypto_attribute = ast_sdp_srtp_get_attrib(tmp,
diff -Nurp asterisk-22.1.0-orig/res/res_pjsip_session.c asterisk-22.1.0/res/res_pjsip_session.c
--- asterisk-22.1.0-orig/res/res_pjsip_session.c 2024-11-21 18:18:07.000000000 +0100
+++ asterisk-22.1.0/res/res_pjsip_session.c 2024-12-17 10:42:58.787831494 +0100
@@ -2525,6 +2525,12 @@ static int sip_session_refresh(struct as
SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(session));
}
}
+ if (session->endpoint->support_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_sip_session_send_request_with_cb(session, tdata, on_response);
ast_sip_session_media_state_free(active_media_state);
@@ -2892,6 +2898,13 @@ int ast_sip_session_create_invite(struct
SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
}
+ if (session->endpoint->support_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");
+ }
+
SCOPE_EXIT_RTN_VALUE(0);
}