<p>Maximilian Fridrich has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18837">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Add mediasec capabilities<br><br>This patch adds support for mediasec SIP headers and SDP attributes.<br>These are defined in RFC 3329, 3GPP TS 24.229 and<br>draft-dawes-sipcore-mediasec-parameter. The new features are<br>implemented so that a backbone for RFC 3329 is present to streamline<br>future work on RFC 3329.<br><br>With this patch, Asterisk can communicate with Deutsche Telekom trunks<br>which require these fields.<br><br>ASTERISK-30032<br><br>Change-Id: Ia7f5b5ba42db18074fdd5428c4e1838728586be2<br>---<br>M include/asterisk/res_pjsip.h<br>M include/asterisk/res_pjsip_session.h<br>M res/res_pjsip/pjsip_config.xml<br>M res/res_pjsip/pjsip_configuration.c<br>A res/res_pjsip/security_agreements.c<br>M res/res_pjsip_outbound_registration.c<br>A res/res_pjsip_rfc3329.c<br>M res/res_pjsip_sdp_rtp.c<br>M res/res_pjsip_session.c<br>9 files changed, 713 insertions(+), 3 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/37/18837/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index 1714cff..c458fe2 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -283,6 +283,47 @@</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief The kind of security negotiation</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_sip_security_negotiation {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! No security mechanism negotiation */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_SECURITY_NEG_NONE = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Use mediasec security mechanism negotiation */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_SECURITY_NEG_MEDIASEC,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add RFC 3329 (sec-agree) mechanism negotiation in the future */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief The security mechanism type</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+enum ast_sip_security_mechanism_type {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_SECURITY_MECH_NONE,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Use msrp-tls as security mechanism */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_SECURITY_MECH_MSRP_TLS,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Use sdes-srtp as security mechanism */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_SECURITY_MECH_SDES_SRTP,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Use dtls-srtp as security mechanism */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_SECURITY_MECH_DTLS_SRTP,</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add RFC 3329 (sec-agree) mechanisms like tle, digest, ipsec-ike in the future */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Structure representing a security mechanism as defined in RFC 3329</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sip_security_mechanism {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Sorcery object */</span><br><span style="color: hsl(120, 100%, 40%);">+ SORCERY_OBJECT(details);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Used to determine which security mechanism to use. */</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_sip_security_mechanism_type type;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* The preference of this security mechanism. The higher the value, the more preferred. */</span><br><span style="color: hsl(120, 100%, 40%);">+ float qvalue;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Optional mechanism parameters. May be NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_vector_string *mechanism_parameters;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_VECTOR(ast_sip_security_mechanism_vector, struct ast_sip_security_mechanism *);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Contact associated with an address of record</span><br><span> */</span><br><span> struct ast_sip_contact {</span><br><span>@@ -353,6 +394,8 @@</span><br><span> );</span><br><span> /*! The round trip time in microseconds */</span><br><span> int64_t rtt;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The security mechanism list of the contact (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism_vector security_mechanisms;</span><br><span> /*! Current status for a contact (default - unavailable) */</span><br><span> enum ast_sip_contact_status_type status;</span><br><span> /*! Last status for a contact (default - unavailable) */</span><br><span>@@ -880,6 +923,10 @@</span><br><span> unsigned int send_connected_line;</span><br><span> /*! Ignore 183 if no SDP is present */</span><br><span> unsigned int ignore_183_without_sdp;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Type of security negotiation to use (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_sip_security_negotiation security_negotiation;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Client security mechanisms (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism_vector security_mechanisms;</span><br><span> /*! Set which STIR/SHAKEN behaviors we want on this endpoint */</span><br><span> unsigned int stir_shaken;</span><br><span> /*! Should we authenticate OPTIONS requests per RFC 3261? */</span><br><span>@@ -929,6 +976,87 @@</span><br><span> int ast_sip_is_media_type_in(pjsip_media_type *a, ...) attribute_sentinel;</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Add security headers to transmission data</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param security_mechanisms Vector of security mechanisms.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param header_name The header name under which to add the security mechanisms.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ... One of Security-Client, Security-Server, Security-Verify.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param add_qval If zero, don't add the q-value to the header.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param tdata The transmission data.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero Failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_add_security_headers(struct ast_sip_security_mechanism_vector *security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *header_name, int add_qval, pjsip_tx_data *tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Append to security mechanism vector from SIP header</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param security_mechanisms Vector of security mechanisms to append to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param hdr The header of the security mechanisms.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ... Header name must be one of Security-Client, Security-Server, Security-Verify.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_header_to_security_mechanism(struct ast_sip_security_mechanism_vector *security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ const pjsip_generic_string_hdr *hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Initialize security mechanism vector from string of security mechanisms.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param security_mechanisms Pointer to vector of security mechanisms to initialize.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param value String of security mechanisms as defined in RFC 3329.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero Failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_security_mechanism_vector_init(struct ast_sip_security_mechanism_vector *security_mechanism, const char *value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Removes all headers of a specific name and value from a pjsip_msg.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param msg PJSIP message from which to remove headers.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param hdr_name Name of the header to remove.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param value Optional string value of the header to remove.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ... If NULL, remove all headers of given hdr_name.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_remove_headers_by_name_and_value(pjsip_msg *msg, const pj_str_t *hdr_name, const char* value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Free contents of a security mechanism vector.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param security_mechanisms Vector whose contents are to be freed</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Allocate a security mechanism from a string.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param security_mechanism Pointer-pointer to the security mechanism to allocate.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param value The security mechanism string as defined in RFC 3329 (section 2.2)</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param ... in the form <mechanism_name>;q=<q_value>;<mechanism_parameters></span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero Failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_str_to_security_mechanism(struct ast_sip_security_mechanism **security_mechanism, const char *value);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Duplicate a security mechanism.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param security_mechanisms Security mechanism to duplicate.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval Pointer to duplicated security mechanism. May be NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sip_security_mechanism *ast_sip_security_mechanism_dup(const struct ast_sip_security_mechanism *security_mechanism);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Set the security negotiation based on a given string.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param security_negotiation Security negotiation enum to set.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param val String that represents a security_negotiation value.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 Success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero Failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_set_security_negotiation(enum ast_sip_security_negotiation *security_negotiation, const char *val);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Initialize an auth vector with the configured values.</span><br><span> *</span><br><span> * \param vector Vector to initialize</span><br><span>diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h</span><br><span>index e7a9457..b530ceb 100644</span><br><span>--- a/include/asterisk/res_pjsip_session.h</span><br><span>+++ b/include/asterisk/res_pjsip_session.h</span><br><span>@@ -30,6 +30,8 @@</span><br><span> #include "asterisk/sdp_srtp.h"</span><br><span> /* Needed for ast_media_type */</span><br><span> #include "asterisk/codec.h"</span><br><span style="color: hsl(120, 100%, 40%);">+/* Needed for ast_sip_security_mechanism_vector */</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjsip.h"</span><br><span> </span><br><span> /* Forward declarations */</span><br><span> struct ast_sip_endpoint;</span><br><span>@@ -225,6 +227,8 @@</span><br><span> pjsip_uri *request_uri;</span><br><span> /*! Media statistics for negotiated RTP streams */</span><br><span> AST_VECTOR(, struct ast_rtp_instance_stats *) media_stats;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! The security mechanism list of the peer (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism_vector server_security_mechanisms;</span><br><span> /*! Number of challenges received during outgoing requests to determine if we are in a loop */</span><br><span> unsigned int authentication_challenge_count:4;</span><br><span> /*! Originating Line Info (ANI II digits) */</span><br><span>diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml</span><br><span>index e9abc86..2fddaa8 100644</span><br><span>--- a/res/res_pjsip/pjsip_config.xml</span><br><span>+++ b/res/res_pjsip/pjsip_config.xml</span><br><span>@@ -56,6 +56,22 @@</span><br><span> List of comma separated AoRs that the endpoint should be associated with.</span><br><span> </para></description></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="security_negotiation" default="no"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>The kind of security agreement negotiation to use. Currently, only mediasec is supported.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <description></span><br><span style="color: hsl(120, 100%, 40%);">+ <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+ <enum name="no" /></span><br><span style="color: hsl(120, 100%, 40%);">+ <enum name="mediasec" /></span><br><span style="color: hsl(120, 100%, 40%);">+ </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+ </description></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="security_mechanisms"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>List of security mechanisms supported.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+ This is a comma-delimited list of security mechanisms to use. Each security mechanism</span><br><span style="color: hsl(120, 100%, 40%);">+ must be in the form defined by RFC 3329 section 2.2.</span><br><span style="color: hsl(120, 100%, 40%);">+ </para></description></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> <configOption name="auth"></span><br><span> <synopsis>Authentication Object(s) associated with the endpoint</synopsis></span><br><span> <description><para></span><br><span>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c</span><br><span>index b514cea..5c213a0 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -247,6 +247,31 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int security_mechanism_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_endpoint *endpoint = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sip_security_mechanism_vector_init(&endpoint->security_mechanisms, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_set_security_negotiation(enum ast_sip_security_negotiation *security_negotiation, const char *val) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strcasecmp("no", val)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *security_negotiation = AST_SIP_SECURITY_NEG_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp("mediasec", val)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *security_negotiation = AST_SIP_SECURITY_NEG_MEDIASEC;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int security_negotiation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_endpoint *endpoint = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sip_set_security_negotiation(&endpoint->security_negotiation, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *auths)</span><br><span> {</span><br><span> int i;</span><br><span>@@ -2042,6 +2067,8 @@</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_unauthenticated_options", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_unauthenticated_options));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_incoming_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_incoming_call_profile));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_outgoing_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_outgoing_call_profile));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "security_mechanisms", "", security_mechanism_handler, NULL, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "security_negotiation", "no", security_negotiation_handler, NULL, NULL, 0, 0);</span><br><span> </span><br><span> if (ast_sip_initialize_sorcery_transport()) {</span><br><span> ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");</span><br><span>diff --git a/res/res_pjsip/security_agreements.c b/res/res_pjsip/security_agreements.c</span><br><span>new file mode 100644</span><br><span>index 0000000..f9e10ed</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_pjsip/security_agreements.c</span><br><span>@@ -0,0 +1,291 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Commend International</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Maximilian Fridrich <m.fridrich@commend.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Interact with security agreement negotiations and mechanisms</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \author Maximilian Fridrich <m.fridrich@commend.com></span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <pjsip.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjsip.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_sip_str_to_security_mechanism_type(const char *security_mechanism) {</span><br><span style="color: hsl(120, 100%, 40%);">+ int result = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strcasecmp(security_mechanism, "msrp-tls")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ result = AST_SIP_SECURITY_MECH_MSRP_TLS;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(security_mechanism, "sdes-srtp")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ result = AST_SIP_SECURITY_MECH_SDES_SRTP;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(security_mechanism, "dtls-srtp")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ result = AST_SIP_SECURITY_MECH_DTLS_SRTP;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return result;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *ast_sip_security_mechanism_type_to_str(enum ast_sip_security_mechanism_type mech_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mech_type == AST_SIP_SECURITY_MECH_MSRP_TLS) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return "msrp-tls";</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (mech_type == AST_SIP_SECURITY_MECH_SDES_SRTP) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return "sdes-srtp";</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (mech_type == AST_SIP_SECURITY_MECH_DTLS_SRTP) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return "dtls-srtp";</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int ast_sip_security_mechanism_to_str(const struct ast_sip_security_mechanism *security_mechanism, int add_qvalue, char **buf) {</span><br><span style="color: hsl(120, 100%, 40%);">+ char tmp[64];</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t size;</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t buf_size = 128;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *ret = ast_calloc(buf_size, sizeof(char));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ret || !security_mechanism) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ strncat(ret, ast_sip_security_mechanism_type_to_str(security_mechanism->type), buf_size - strlen(ret) - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (add_qvalue) {</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(tmp, sizeof(tmp), ";q=%f.4", security_mechanism->qvalue);</span><br><span style="color: hsl(120, 100%, 40%);">+ strncat(ret, tmp, buf_size - strlen(ret) - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ size = AST_VECTOR_SIZE(security_mechanism->mechanism_parameters);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < size; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(tmp, sizeof(tmp), ";%s", AST_VECTOR_GET(security_mechanism->mechanism_parameters, i));</span><br><span style="color: hsl(120, 100%, 40%);">+ strncat(ret, tmp, buf_size - strlen(ret) - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *buf = ret;</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_sip_security_mechanism *ast_sip_security_mechanism_dup(const struct ast_sip_security_mechanism *security_mechanism) {</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t i;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *ret;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!security_mechanism) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ret = ast_calloc(1, sizeof(*ret));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ret) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ret->type = security_mechanism->type;</span><br><span style="color: hsl(120, 100%, 40%);">+ ret->qvalue = security_mechanism->qvalue;</span><br><span style="color: hsl(120, 100%, 40%);">+ ret->mechanism_parameters = ast_malloc(sizeof(*ret->mechanism_parameters));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ret->mechanism_parameters) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(ret);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_INIT(ret->mechanism_parameters, AST_VECTOR_SIZE(security_mechanism->mechanism_parameters));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(security_mechanism->mechanism_parameters); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ char *param = ast_strdup(AST_VECTOR_GET(security_mechanism->mechanism_parameters, i));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (param && AST_VECTOR_APPEND(ret->mechanism_parameters, param)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(param);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return ret;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_remove_headers_by_name_and_value(pjsip_msg *msg, const pj_str_t *hdr_name, const char* value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct pjsip_generic_string_hdr *hdr = pjsip_msg_find_hdr_by_name(msg, hdr_name, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (; hdr; hdr = pjsip_msg_find_hdr_by_name(msg, hdr_name, hdr->next)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (value == NULL || !pj_strcmp2(&hdr->hvalue, value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_list_erase(hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (hdr->next == hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t size;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *mech;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!security_mechanisms) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ size = AST_VECTOR_SIZE(security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < size; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ mech = AST_VECTOR_GET(security_mechanisms, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(mech->mechanism_parameters);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(mech);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_str_to_security_mechanism(struct ast_sip_security_mechanism **security_mechanism, const char *value) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *mech;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *param;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *tmp1;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *tmp2;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mechanism = ast_strdupa(value);</span><br><span style="color: hsl(120, 100%, 40%);">+ int err = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int type = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mech = ast_calloc(1, sizeof(*mech));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mech) {</span><br><span style="color: hsl(120, 100%, 40%);">+ err = ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ mech->mechanism_parameters = ast_calloc(1, sizeof(*mech->mechanism_parameters));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!mech->mechanism_parameters) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(mech->mechanism_parameters);</span><br><span style="color: hsl(120, 100%, 40%);">+ err = ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp1 = ast_strsep(&mechanism, ';', AST_STRSEP_ALL);</span><br><span style="color: hsl(120, 100%, 40%);">+ type = ast_sip_str_to_security_mechanism_type(tmp1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (type == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Invalid mechanism */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(mech->mechanism_parameters);</span><br><span style="color: hsl(120, 100%, 40%);">+ err = EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ mech->type = type;</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((param = ast_strsep(&mechanism, ';', AST_STRSEP_ALL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!param) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(mech->mechanism_parameters);</span><br><span style="color: hsl(120, 100%, 40%);">+ err = EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto out;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (strlen(param) > 3 && !strncmp(param, "q=0.", 4)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp1 = ast_strdupa(param);</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp2 = strtok(tmp1, "=");</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp2 = strtok(NULL, "");</span><br><span style="color: hsl(120, 100%, 40%);">+ mech->qvalue = strtof(tmp2, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ param = ast_strdup(param);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(mech->mechanism_parameters, param);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *security_mechanism = mech;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+out:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (err) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(mech);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return err;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_add_security_headers(struct ast_sip_security_mechanism_vector *security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *header_name, int add_qval, pjsip_tx_data *tdata) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *mech;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ int mech_cnt;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+ int add_qvalue = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!security_mechanisms || !tdata) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strcmp(header_name, "Security-Client")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ add_qvalue = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (strcmp(header_name, "Security-Server") &&</span><br><span style="color: hsl(120, 100%, 40%);">+ strcmp(header_name, "Security-Verify")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If we're adding Security-Client headers, don't add q-value</span><br><span style="color: hsl(120, 100%, 40%);">+ * even if the function caller requested it. */</span><br><span style="color: hsl(120, 100%, 40%);">+ add_qvalue = add_qvalue && add_qval;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mech_cnt = AST_VECTOR_SIZE(security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < mech_cnt; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ mech = AST_VECTOR_GET(security_mechanisms, i);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_sip_security_mechanism_to_str(mech, add_qvalue, &buf)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ continue;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_header(tdata, header_name, buf);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_header_to_security_mechanism(struct ast_sip_security_mechanism_vector *security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ const pjsip_generic_string_hdr *hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *mech;</span><br><span style="color: hsl(120, 100%, 40%);">+ char buf[512];</span><br><span style="color: hsl(120, 100%, 40%);">+ char *hdr_val;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mechanism;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!security_mechanisms || !hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pj_strcmp2(&hdr->name, "Security-Client") && pj_strcmp2(&hdr->name, "Security-Server") &&</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strcmp2(&hdr->name, "Security-Verify")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_copy_pj_str(buf, &hdr->hvalue, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr_val = ast_skip_blanks(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((mechanism = ast_strsep(&hdr_val, ',', AST_STRSEP_ALL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_sip_str_to_security_mechanism(&mech, mechanism)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(security_mechanisms, mech);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ast_sip_security_mechanism_vector_init(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *value)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ char *val = value ? ast_strdupa(value) : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *mech;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mechanism;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_SIZE(security_mechanisms)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_INIT(security_mechanisms, 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!val) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((mechanism = ast_strsep(&val, ',', AST_STRSEP_ALL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_sip_str_to_security_mechanism(&mech, mechanism)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(security_mechanisms, mech);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>\ No newline at end of file</span><br><span>diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c</span><br><span>index b00221a..c102f18 100644</span><br><span>--- a/res/res_pjsip_outbound_registration.c</span><br><span>+++ b/res/res_pjsip_outbound_registration.c</span><br><span>@@ -87,6 +87,22 @@</span><br><span> are made.</span><br><span> </para></description></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="security_negotiation" default="no"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>The kind of security agreement negotiation to use. Currently, only mediasec is supported.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <description></span><br><span style="color: hsl(120, 100%, 40%);">+ <enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+ <enum name="no" /></span><br><span style="color: hsl(120, 100%, 40%);">+ <enum name="mediasec" /></span><br><span style="color: hsl(120, 100%, 40%);">+ </enumlist></span><br><span style="color: hsl(120, 100%, 40%);">+ </description></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="security_mechanisms"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>List of security mechanisms supported.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+ This is a comma-delimited list of security mechanisms to use. Each security mechanism</span><br><span style="color: hsl(120, 100%, 40%);">+ must be in the form defined by RFC 3329 section 2.2.</span><br><span style="color: hsl(120, 100%, 40%);">+ </para></description></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> <configOption name="outbound_auth" default=""></span><br><span> <synopsis>Authentication object(s) to be used for outbound registrations.</synopsis></span><br><span> <description><para></span><br><span>@@ -328,6 +344,10 @@</span><br><span> unsigned int max_retries;</span><br><span> /*! \brief Whether to add a line parameter to the outbound Contact or not */</span><br><span> unsigned int line;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Type of security negotiation to use (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_sip_security_negotiation security_negotiation;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Client security mechanisms (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism_vector security_mechanisms;</span><br><span> /*! \brief Configured authentication credentials */</span><br><span> struct ast_sip_auth_vector outbound_auths;</span><br><span> /*! \brief Whether Path support is enabled */</span><br><span>@@ -371,6 +391,12 @@</span><br><span> unsigned int auth_rejection_permanent;</span><br><span> /*! \brief Determines whether SIP Path support should be advertised */</span><br><span> unsigned int support_path;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Type of security negotiation to use (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ enum ast_sip_security_negotiation security_negotiation;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Client security mechanisms (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism_vector security_mechanisms;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Security mechanisms of the peer (RFC 3329). */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism_vector server_security_mechanisms;</span><br><span> /*! CSeq number of last sent auth request. */</span><br><span> unsigned int auth_cseq;</span><br><span> /*! \brief Serializer for stuff and things */</span><br><span>@@ -655,6 +681,18 @@</span><br><span> pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (client_state->security_negotiation == AST_SIP_SECURITY_NEG_MEDIASEC) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (client_state->status == SIP_REGISTRATION_REGISTERED) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_security_headers(&client_state->server_security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Security-Verify", 0, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_security_headers(&client_state->security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Security-Client", 0, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_header(tdata, "Require", "mediasec");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_header(tdata, "Proxy-Require", "mediasec");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> registration_client_send(client_state, tdata);</span><br><span> </span><br><span> return 0;</span><br><span>@@ -946,9 +984,20 @@</span><br><span> static int handle_registration_response(void *data)</span><br><span> {</span><br><span> struct registration_response *response = data;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sip_outbound_registration *reg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_endpoint *endpt = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact *contact = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_aor *aor = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact_status *contact_status = NULL;</span><br><span> pjsip_regc_info info;</span><br><span> char server_uri[PJSIP_MAX_URL_SIZE];</span><br><span> char client_uri[PJSIP_MAX_URL_SIZE];</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t security_server = { "Security-Server", 15 };</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t security_verify = { "Security-Verify", 15 };</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t security_client = { "Security-Client", 15 };</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t proxy_require = { "Proxy-Require", 13 };</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t require = { "Require", 7 };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> </span><br><span> if (response->client_state->status == SIP_REGISTRATION_STOPPED) {</span><br><span> ao2_ref(response, -1);</span><br><span>@@ -972,7 +1021,7 @@</span><br><span> return 0;</span><br><span> }</span><br><span> }</span><br><span style="color: hsl(0, 100%, 40%);">- } else if ((response->code == 401 || response->code == 407)</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if ((response->code == 401 || response->code == 407 || response->code == 494)</span><br><span> && (!response->client_state->auth_attempted</span><br><span> || response->rdata->msg_info.cseq->cseq != response->client_state->auth_cseq)) {</span><br><span> int res;</span><br><span>@@ -985,6 +1034,45 @@</span><br><span> ast_debug(1, "Sending authenticated REGISTER to server '%s' from client '%s'\n",</span><br><span> server_uri, client_uri);</span><br><span> pjsip_tx_data_add_ref(tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((reg = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", response->client_state->registration_name)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+ (endpt = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", reg->endpoint)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+ (aor = ast_sip_location_retrieve_aor(endpt->aors)) &&</span><br><span style="color: hsl(120, 100%, 40%);">+ (contact = ast_sip_location_retrieve_first_aor_contact(aor))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Get contact status through registration -> endpoint name -> aor -> contact */</span><br><span style="color: hsl(120, 100%, 40%);">+ contact_status = ast_sip_get_contact_status(contact);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!AST_VECTOR_SIZE(&response->client_state->server_security_mechanisms)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add server list of security mechanism to client_state and contact status */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_generic_string_hdr *header;</span><br><span style="color: hsl(120, 100%, 40%);">+ header = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &security_server, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (; header;</span><br><span style="color: hsl(120, 100%, 40%);">+ header = pjsip_msg_find_hdr_by_name(response->rdata->msg_info.msg, &security_server, header->next)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_header_to_security_mechanism(&response->client_state->server_security_mechanisms, header);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (contact_status) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add server security mechanisms to contact status to be able to send correct</span><br><span style="color: hsl(120, 100%, 40%);">+ * Security-Verify headers on subsequent non-REGISTER requests</span><br><span style="color: hsl(120, 100%, 40%);">+ * through this outbound registration.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_header_to_security_mechanism(&contact_status->security_mechanisms, header);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (response->client_state->security_negotiation == AST_SIP_SECURITY_NEG_MEDIASEC) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add Security-Verify headers (no q-value when using mediasec)</span><br><span style="color: hsl(120, 100%, 40%);">+ * and remove Security-Client, Proxy-Require, and Require header.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pjsip_msg_find_hdr_by_name(tdata->msg, &security_verify, NULL) == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_security_headers(&response->client_state->server_security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ "Security-Verify", 0, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_remove_headers_by_name_and_value(tdata->msg, &security_client, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_remove_headers_by_name_and_value(tdata->msg, &proxy_require, "mediasec");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_remove_headers_by_name_and_value(tdata->msg, &require, "mediasec");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> res = registration_client_send(response->client_state, tdata);</span><br><span> </span><br><span> /* Save the cseq that actually got sent. */</span><br><span>@@ -1488,12 +1576,22 @@</span><br><span> ast_free(name);</span><br><span> }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_INIT(&state->client_state->security_mechanisms, AST_VECTOR_SIZE(®istration->security_mechanisms));</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(®istration->security_mechanisms); ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *mech = ast_sip_security_mechanism_dup(AST_VECTOR_GET(®istration->security_mechanisms, i));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mech && AST_VECTOR_APPEND(&state->client_state->security_mechanisms, mech)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(mech->mechanism_parameters);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(mech);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> state->client_state->retry_interval = registration->retry_interval;</span><br><span> state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;</span><br><span> state->client_state->fatal_retry_interval = registration->fatal_retry_interval;</span><br><span> state->client_state->max_retries = registration->max_retries;</span><br><span> state->client_state->retries = 0;</span><br><span> state->client_state->support_path = registration->support_path;</span><br><span style="color: hsl(120, 100%, 40%);">+ state->client_state->security_negotiation = registration->security_negotiation;</span><br><span> state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;</span><br><span> max_delay = registration->max_random_initial_delay;</span><br><span> </span><br><span>@@ -1592,6 +1690,20 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int security_mechanisms_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sip_outbound_registration *registration = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sip_security_mechanism_vector_init(®istration->security_mechanisms, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int security_negotiation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sip_outbound_registration *registration = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sip_set_security_negotiation(®istration->security_negotiation, var->value);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span> {</span><br><span> struct sip_outbound_registration *registration = obj;</span><br><span>@@ -2318,6 +2430,8 @@</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));</span><br><span> ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0);</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "security_negotiation", "no", security_negotiation_handler, NULL, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "security_mechanisms", "", security_mechanisms_handler, NULL, NULL, 0, 0);</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));</span><br><span> </span><br><span>diff --git a/res/res_pjsip_rfc3329.c b/res/res_pjsip_rfc3329.c</span><br><span>new file mode 100644</span><br><span>index 0000000..308b687</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_pjsip_rfc3329.c</span><br><span>@@ -0,0 +1,124 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Commend International</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Maximilian Fridrich <m.fridrich@commend.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*** MODULEINFO</span><br><span style="color: hsl(120, 100%, 40%);">+ <depend>pjproject</depend></span><br><span style="color: hsl(120, 100%, 40%);">+ <depend>res_pjsip</depend></span><br><span style="color: hsl(120, 100%, 40%);">+ <depend>res_pjsip_session</depend></span><br><span style="color: hsl(120, 100%, 40%);">+ <support_level>core</support_level></span><br><span style="color: hsl(120, 100%, 40%);">+ ***/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <pjsip.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pjsip_ua.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjsip.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjsip_session.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/module.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/causes.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/threadpool.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void rfc3329_incoming_response(struct ast_sip_session *session, struct pjsip_rx_data *rdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t str_security_server = { "Security-Server", 15 };</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact_status *contact_status = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ int contact_has_mechanisms = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *mech;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_generic_string_hdr *header;</span><br><span style="color: hsl(120, 100%, 40%);">+ char buf[128];</span><br><span style="color: hsl(120, 100%, 40%);">+ char *hdr_val;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *mechanism;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (session && session->contact) {</span><br><span style="color: hsl(120, 100%, 40%);">+ contact_status = ast_sip_get_contact_status(session->contact);</span><br><span style="color: hsl(120, 100%, 40%);">+ contact_has_mechanisms = contact_status && AST_VECTOR_SIZE(&contact_status->security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_SIZE(&session->server_security_mechanisms) && contact_has_mechanisms) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_security_server, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (; header;</span><br><span style="color: hsl(120, 100%, 40%);">+ header = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_security_server, header->next)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Parse Security-Server headers and add to session and contact status</span><br><span style="color: hsl(120, 100%, 40%);">+ * to use for future requests. */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_copy_pj_str(buf, &header->hvalue, sizeof(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr_val = ast_skip_blanks(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((mechanism = ast_strsep(&hdr_val, ',', AST_STRSEP_ALL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_sip_str_to_security_mechanism(&mech, mechanism)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(&session->server_security_mechanisms, mech);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (contact_status && !contact_has_mechanisms) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(&contact_status->security_mechanisms, mech);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void rfc3329_outgoing_request(struct ast_sip_session *session, struct pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t security_verify = { "Security-Verify", 15 };</span><br><span style="color: hsl(120, 100%, 40%);">+ struct pjsip_generic_string_hdr *hdr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact_status *contact_status = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (session->endpoint->security_negotiation != AST_SIP_SECURITY_NEG_MEDIASEC) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ contact_status = ast_sip_get_contact_status(session->contact);</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &security_verify, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_SIZE(&contact_status->security_mechanisms) && hdr == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add Security-Verify headers (with q-value) */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_security_headers(&contact_status->security_mechanisms, "Security-Verify", 0, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!hdr && AST_VECTOR_SIZE(&session->endpoint->security_mechanisms)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add Security-Client headers (no q-value) and Require, Proxy-Require */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_security_headers(&session->endpoint->security_mechanisms, "Security-Client", 0, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_header(tdata, "Require", "mediasec");</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_header(tdata, "Proxy-Require", "mediasec");</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_sip_session_supplement rfc3329_supplement = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .incoming_response = rfc3329_incoming_response,</span><br><span style="color: hsl(120, 100%, 40%);">+ .outgoing_request = rfc3329_outgoing_request,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int load_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_session_register_supplement(&rfc3329_supplement);</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int unload_module(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_session_unregister_supplement(&rfc3329_supplement);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP RFC 3329 Support (partial)",</span><br><span style="color: hsl(120, 100%, 40%);">+ .support_level = AST_MODULE_SUPPORT_CORE,</span><br><span style="color: hsl(120, 100%, 40%);">+ .load = load_module,</span><br><span style="color: hsl(120, 100%, 40%);">+ .unload = unload_module,</span><br><span style="color: hsl(120, 100%, 40%);">+ .load_pri = AST_MODPRI_APP_DEPEND,</span><br><span style="color: hsl(120, 100%, 40%);">+ .requires = "res_pjsip,res_pjsip_session",</span><br><span style="color: hsl(120, 100%, 40%);">+);</span><br><span>diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c</span><br><span>index 3b2e299..4614b96 100644</span><br><span>--- a/res/res_pjsip_sdp_rtp.c</span><br><span>+++ b/res/res_pjsip_sdp_rtp.c</span><br><span>@@ -1526,6 +1526,7 @@</span><br><span> static const pj_str_t STR_PASSIVE = { "passive", 7 };</span><br><span> static const pj_str_t STR_ACTPASS = { "actpass", 7 };</span><br><span> static const pj_str_t STR_HOLDCONN = { "holdconn", 8 };</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t STR_MEDSECREQ = { "requested", 9 };</span><br><span> enum ast_rtp_dtls_setup setup;</span><br><span> </span><br><span> switch (session_media->encryption) {</span><br><span>@@ -1556,6 +1557,11 @@</span><br><span> media->attr[media->attr_count++] = attr;</span><br><span> } while ((tmp = AST_LIST_NEXT(tmp, sdp_srtp_list)));</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (session->endpoint->security_negotiation == AST_SIP_SECURITY_NEG_MEDIASEC) {</span><br><span style="color: hsl(120, 100%, 40%);">+ attr = pjmedia_sdp_attr_create(pool, "3ge2ae", &STR_MEDSECREQ);</span><br><span style="color: hsl(120, 100%, 40%);">+ media->attr[media->attr_count++] = attr;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> break;</span><br><span> case AST_SIP_MEDIA_ENCRYPT_DTLS:</span><br><span> if (setup_dtls_srtp(session, session_media)) {</span><br><span>diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c</span><br><span>index 3c55af7..c2f1dd1 100644</span><br><span>--- a/res/res_pjsip_session.c</span><br><span>+++ b/res/res_pjsip_session.c</span><br><span>@@ -4746,7 +4746,7 @@</span><br><span> ast_debug(1, "%s: reINVITE received final response code %d\n",</span><br><span> ast_sip_session_get_name(session),</span><br><span> tsx->status_code);</span><br><span style="color: hsl(0, 100%, 40%);">- if ((tsx->status_code == 401 || tsx->status_code == 407)</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((tsx->status_code == 401 || tsx->status_code == 407 || tsx->status_code == 494)</span><br><span> && ++session->authentication_challenge_count < MAX_RX_CHALLENGES</span><br><span> && !ast_sip_create_request_with_auth(</span><br><span> &session->endpoint->outbound_auths,</span><br><span>@@ -4840,7 +4840,7 @@</span><br><span> ast_sip_session_get_name(session),</span><br><span> (int) pj_strlen(&tsx->method.name), pj_strbuf(&tsx->method.name),</span><br><span> tsx->status_code);</span><br><span style="color: hsl(0, 100%, 40%);">- if ((tsx->status_code == 401 || tsx->status_code == 407)</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((tsx->status_code == 401 || tsx->status_code == 407 || tsx->status_code == 494)</span><br><span> && ++session->authentication_challenge_count < MAX_RX_CHALLENGES</span><br><span> && !ast_sip_create_request_with_auth(</span><br><span> &session->endpoint->outbound_auths,</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18837">change 18837</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/18837"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Ia7f5b5ba42db18074fdd5428c4e1838728586be2 </div>
<div style="display:none"> Gerrit-Change-Number: 18837 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Maximilian Fridrich <m.fridrich@commend.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>