On 30.05.19 at 10:24 Michael Maier wrote:
> Hello!
> 
> I wrote some code, which adds basic media encryption support to be used with 
> Deutsche Telekom. The attached patch is based on Asterisk 16.3
> and works for me :-) - not fully tested yet. If you want to use it, you have 
> to enable media_encryption=sdes for the extension (and
> transport tls and tls1.2). Use at your own risk!
> 
> 
> The current patch lacks a basic mediasec option, which prevents adding the 
> mediasec headers to each *initial* REGISTER or to each INVITE (if
> sdes is activated). As of today, I don't know how to solve this problem 
> without too much changes.
> Anyway: It looks like the additional HEADERs seem not to disrupt other ISPs 
> (tested with one other ISP). This option should be accessible in
> rtp, session and register environment. Maybe there is a possibility to 
> exchange data between register, session and rtp environment. This way, it
> would be possible to dynamically set mediasec in session and rtp based on the 
> result of the initial register. It would be necessary at the
> same time, to dynamically disable sdes encryption if activation of mediasec 
> didn't succeed.
> 
> One more open point is the check for the 3 headers using the same name 
> (Security-Server and Security-Verify). How can they be checked
> regarding order? Is there a function to get each value of the same header? 
> Maybe based on an array index? This way it would be possible to
> create the Security-Verify headers dynamically based on the 494 or 401 
> response.
> 
> The UPDATE package (used as a watchdog circuit during a call each 15 minutes) 
> seems not to be affected - I couldn't find any problem at this
> point.


Attached is a new version of the mediasec patch. The following items changed:

- No more differentiation between initial REGISTER and ReREGISTERS (because if 
server was restarted, the ReREGISTER
  could have been done w/o mediasec and subsequent calls have been broken 
because of missing SRTP support by provider).
- Added memorymanagement for the additional 494 requests.

The patch contains the complete code necessary for mediasec (tested with 
Deutsche Telekom) and asterisk 16.4.1 (should work too w/ 16.5.0).

This patch doesn't contain an additional sdp version fix, which is needed to 
reach some numbers in Germany via Deutsche Telekom - see
https://issues.asterisk.org/jira/secure/attachment/58493/sdp-version-v2.patch
(https://issues.asterisk.org/jira/browse/ASTERISK-28452)


Regards
Michael
diff -urN asterisk-16.5.0/res/res_pjsip/pjsip_options.c asterisk-16.5.0.new/res/res_pjsip/pjsip_options.c
--- asterisk-16.5.0/res/res_pjsip/pjsip_options.c	2019-07-27 11:38:14.000000000 +0200
+++ asterisk-16.5.0.new/res/res_pjsip/pjsip_options.c	2019-08-31 15:59:33.399000000 +0200
@@ -212,6 +212,8 @@
  */
 static struct ast_taskprocessor *management_serializer;
 
+static int sip_options_qualify_contact(void *obj, void *arg, int flags);
+
 static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
 {
 	pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
@@ -801,6 +803,15 @@
 		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;
 
@@ -905,6 +916,14 @@
 		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 -urN asterisk-16.5.0/res/res_pjsip_outbound_registration.c asterisk-16.5.0.new/res/res_pjsip_outbound_registration.c
--- asterisk-16.5.0/res/res_pjsip_outbound_registration.c	2019-07-27 11:38:14.000000000 +0200
+++ asterisk-16.5.0.new/res/res_pjsip_outbound_registration.c	2019-09-01 13:28:36.326000000 +0200
@@ -361,6 +361,8 @@
 	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 Outbound registration state information (persists for lifetime that registration should exist) */
@@ -597,6 +599,19 @@
 		pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
 	}
 
+	/* Add some header for 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;
@@ -917,6 +932,27 @@
 			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 */
+			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);
 
@@ -943,6 +979,8 @@
 		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);
@@ -959,6 +997,8 @@
 				response->client_state->registration_name);
 		} 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);
 			ast_sip_transport_monitor_unregister(response->rdata->tp_info.transport,
 				registration_transport_shutdown_cb, response->client_state->registration_name,
@@ -966,6 +1006,22 @@
 		}
 	} 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);
diff -urN asterisk-16.5.0/res/res_pjsip_sdp_rtp.c asterisk-16.5.0.new/res/res_pjsip_sdp_rtp.c
--- asterisk-16.5.0/res/res_pjsip_sdp_rtp.c	2019-07-27 11:38:14.000000000 +0200
+++ asterisk-16.5.0.new/res/res_pjsip_sdp_rtp.c	2019-08-27 19:12:34.183000000 +0200
@@ -1429,6 +1429,7 @@
 	static const pj_str_t STR_PASSIVE = { "passive", 7 };
 	static const pj_str_t STR_ACTPASS = { "actpass", 7 };
 	static const pj_str_t STR_HOLDCONN = { "holdconn", 8 };
+	static const pj_str_t STR_MEDSECREQ = { "requested", 9 };
 	enum ast_rtp_dtls_setup setup;
 
 	switch (session_media->encryption) {
@@ -1444,6 +1445,8 @@
 		}
 
 		tmp = session_media->srtp;
+		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 -urN asterisk-16.5.0/res/res_pjsip_session.c asterisk-16.5.0.new/res/res_pjsip_session.c
--- asterisk-16.5.0/res/res_pjsip_session.c	2019-07-27 11:38:14.000000000 +0200
+++ asterisk-16.5.0.new/res/res_pjsip_session.c	2019-08-27 19:12:34.184000000 +0200
@@ -2109,6 +2109,13 @@
 		return -1;
 	}
 
+    	if (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");
+	    }
+
 	return 0;
 }
 
-- 
_____________________________________________________________________
-- Bandwidth and Colocation Provided by http://www.api-digital.com --

asterisk-dev mailing list
To UNSUBSCRIBE or update options visit:
   http://lists.digium.com/mailman/listinfo/asterisk-dev

Reply via email to