diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 351ce09edaadbab5c13eaed7f527ad071e4cf0c6..f4cda1ea94a5a31df9f9daafb984f7fb9a85a331 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -917,6 +917,8 @@ struct ast_sip_endpoint {
 	unsigned int stir_shaken;
 	/*! Should we authenticate OPTIONS requests per RFC 3261? */
 	unsigned int allow_unauthenticated_options;
+	/*! Support mediasec on endpoint */
+	unsigned int mediasec;
 };
 
 /*! URI parameter for symmetric transport */
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 84c25594b1b78c33f5ac331386ed9e0720a4bf89..0abaf679d97a6aab0a7021f348f3b9d2bdae4081 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -1464,6 +1464,12 @@
 						being forwarded.</para>
 					</description>
 				</configOption>
+				<configOption name="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="stir_shaken" default="no">
 					<synopsis>Enable STIR/SHAKEN support on this endpoint</synopsis>
 					<description><para>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 6defa7cb96a542d75ae9a13dad7b90afe52bd71c..584b8328bb1a1836b7ac0e94d5426ca5781de65b 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -2154,6 +2154,7 @@ int ast_res_pjsip_initialize_configuration(void)
 		codec_prefs_handler, outgoing_answer_codec_prefs_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "stir_shaken", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, stir_shaken));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_unauthenticated_options", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_unauthenticated_options));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mediasec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, mediasec));
 
 	if (ast_sip_initialize_sorcery_transport()) {
 		ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index e1f048e9a6a78d2839488347a1b1c11350bf61ca..306bac89e683da950f83f4179dbc718be54a1ce9 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -212,6 +212,8 @@ static struct ao2_container *sip_options_endpoint_state_compositors;
  */
 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 @@ static void qualify_contact_cb(void *token, pjsip_event *e)
 		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 @@ static int sip_options_qualify_contact(void *obj, void *arg, int flags)
 		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 --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index ad603180f7962dbdd6fb8badb81e537f392361aa..bc18850288a8c84553280cdbe02b43a7b20703dd 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -181,6 +181,13 @@
 						header as necessary.
 					</para></description>
 				</configOption>
+				<configOption name="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>
@@ -335,6 +342,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 mediasec;
 	/*! \brief Whether Outbound support is enabled */
 	unsigned int support_outbound;
 };
@@ -376,6 +385,8 @@ struct sip_outbound_registration_client_state {
 	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 mediasec;
 	/*! \brief Determines whether SIP Outbound support should be advertised */
 	unsigned int support_outbound;
 	/*! CSeq number of last sent auth request. */
@@ -392,6 +403,8 @@ struct sip_outbound_registration_client_state {
 	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) */
@@ -694,6 +707,21 @@ static int handle_client_registration(void *data)
 		return -1;
 	}
 
+	/* Add some header for mediasec */
+	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");
+		}
+		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;
@@ -1094,6 +1122,29 @@ static int handle_registration_response(void *data)
 			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->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);
 
@@ -1120,6 +1171,7 @@ static int handle_registration_response(void *data)
 		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);
@@ -1136,6 +1188,7 @@ static int handle_registration_response(void *data)
 				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,
@@ -1145,6 +1198,22 @@ static int handle_registration_response(void *data)
 		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);
@@ -1728,6 +1797,7 @@ static int sip_outbound_registration_perform(void *data)
 	state->client_state->max_retries = registration->max_retries;
 	state->client_state->retries = 0;
 	state->client_state->support_path = registration->support_path;
+	state->client_state->mediasec = registration->mediasec;
 	state->client_state->support_outbound = registration->support_outbound;
 	state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;
 
@@ -1872,6 +1942,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->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);
 	}
 
@@ -2554,6 +2629,7 @@ static int load_module(void)
 	ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_outbound", "no", OPT_YESNO_T, 1, FLDSET(struct sip_outbound_registration, support_outbound));
 	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", "mediasec", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, mediasec));
 
 	/*
 	 * Register sorcery observers.
diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c
index a6f497568b3916631b31dc9002c77a67bf9df76b..f00519b9c67667060b543f31e75491744c0c726b 100644
--- a/res/res_pjsip_sdp_rtp.c
+++ b/res/res_pjsip_sdp_rtp.c
@@ -1593,6 +1593,7 @@ static int add_crypto_to_stream(struct ast_sip_session *session,
 	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) {
@@ -1609,6 +1610,11 @@ static int add_crypto_to_stream(struct ast_sip_session *session,
 
 		tmp = session_media->srtp;
 
+		if (session->endpoint->mediasec) {
+			attr = pjmedia_sdp_attr_create(pool, "3ge2ae", &STR_MEDSECREQ);
+			media->attr[media->attr_count++] = attr;
+		}
+
 		do {
 			crypto_attribute = ast_sdp_srtp_get_attrib(tmp,
 				0 /* DTLS running? No */,
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index b1288b59362c16155baffa8cef48e43e66580f5b..1dd635f1247c5ece91c4853e0f29d7673f5f55d4 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -2513,6 +2513,13 @@ static int sip_session_refresh(struct ast_sip_session *session,
 			SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING, "%s: on_request_creation failed.\n", ast_sip_session_get_name(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_sip_session_send_request_with_cb(session, tdata, on_response);
 	ast_sip_session_media_state_free(active_media_state);
 
@@ -2872,6 +2879,13 @@ int ast_sip_session_create_invite(struct ast_sip_session *session, pjsip_tx_data
 		SCOPE_EXIT_RTN_VALUE(-1, "pjsip_inv_invite failed\n");
 	}
 
+	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");
+	}
+
 	SCOPE_EXIT_RTN_VALUE(0);
 }