<p>Maximilian Fridrich has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/19387">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip: 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>A contrib/ast-db-manage/config/versions/417c0247fd7e_add_security_negotiation_and_security_.py<br>A doc/CHANGES-staging/res_pjsip_rfc3329.txt<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>M res/res_pjsip/pjsip_options.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>12 files changed, 962 insertions(+), 4 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/87/19387/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/contrib/ast-db-manage/config/versions/417c0247fd7e_add_security_negotiation_and_security_.py b/contrib/ast-db-manage/config/versions/417c0247fd7e_add_security_negotiation_and_security_.py</span><br><span>new file mode 100644</span><br><span>index 0000000..34847fcb</span><br><span>--- /dev/null</span><br><span>+++ b/contrib/ast-db-manage/config/versions/417c0247fd7e_add_security_negotiation_and_security_.py</span><br><span>@@ -0,0 +1,49 @@</span><br><span style="color: hsl(120, 100%, 40%);">+"""add security_negotiation and security_mechanisms to endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Revision ID: 417c0247fd7e</span><br><span style="color: hsl(120, 100%, 40%);">+Revises: 539f68bede2c</span><br><span style="color: hsl(120, 100%, 40%);">+Create Date: 2022-08-08 15:35:31.416964</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%);">+# revision identifiers, used by Alembic.</span><br><span style="color: hsl(120, 100%, 40%);">+revision = '417c0247fd7e'</span><br><span style="color: hsl(120, 100%, 40%);">+down_revision = '539f68bede2c'</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from alembic import op</span><br><span style="color: hsl(120, 100%, 40%);">+import sqlalchemy as sa</span><br><span style="color: hsl(120, 100%, 40%);">+from sqlalchemy.dialects.postgresql import ENUM</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+SECURITY_NEGOTIATION_NAME = 'security_negotiation_values'</span><br><span style="color: hsl(120, 100%, 40%);">+SECURITY_NEGOTIATION_VALUES = ['no', 'mediasec']</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def upgrade():</span><br><span style="color: hsl(120, 100%, 40%);">+ context = op.get_context()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if context.bind.dialect.name == 'postgresql':</span><br><span style="color: hsl(120, 100%, 40%);">+ security_negotiation_values = ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME)</span><br><span style="color: hsl(120, 100%, 40%);">+ security_negotiation_values.create(op.get_bind(), checkfirst=False)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ op.add_column('ps_endpoints', sa.Column('security_negotiation',</span><br><span style="color: hsl(120, 100%, 40%);">+ ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME, create_type=False)))</span><br><span style="color: hsl(120, 100%, 40%);">+ op.add_column('ps_endpoints', sa.Column('security_mechanisms', sa.String(512)))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ op.add_column('ps_registrations', sa.Column('security_negotiation',</span><br><span style="color: hsl(120, 100%, 40%);">+ ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME, create_type=False)))</span><br><span style="color: hsl(120, 100%, 40%);">+ op.add_column('ps_registrations', sa.Column('security_mechanisms', sa.String(512)))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def downgrade():</span><br><span style="color: hsl(120, 100%, 40%);">+ context = op.get_context()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if context.bind.dialect.name == 'mssql':</span><br><span style="color: hsl(120, 100%, 40%);">+ op.drop_constraint('ck_ps_endpoints_security_negotiation_security_negotiation_values', 'ps_endpoints')</span><br><span style="color: hsl(120, 100%, 40%);">+ op.drop_constraint('ck_ps_registrations_security_negotiation_security_negotiation_values', 'ps_registrations')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ op.drop_column('ps_endpoints', 'security_negotiation')</span><br><span style="color: hsl(120, 100%, 40%);">+ op.drop_column('ps_endpoints', 'security_mechanisms')</span><br><span style="color: hsl(120, 100%, 40%);">+ op.drop_column('ps_registrations', 'security_negotiation')</span><br><span style="color: hsl(120, 100%, 40%);">+ op.drop_column('ps_registrations', 'security_mechanisms')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if context.bind.dialect.name == 'postgresql':</span><br><span style="color: hsl(120, 100%, 40%);">+ enum = ENUM(*SECURITY_NEGOTIATION_VALUES, name=SECURITY_NEGOTIATION_NAME)</span><br><span style="color: hsl(120, 100%, 40%);">+ enum.drop(op.get_bind(), checkfirst=False)</span><br><span>\ No newline at end of file</span><br><span>diff --git a/doc/CHANGES-staging/res_pjsip_rfc3329.txt b/doc/CHANGES-staging/res_pjsip_rfc3329.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..06510b5</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/res_pjsip_rfc3329.txt</span><br><span>@@ -0,0 +1,6 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: res_pjsip</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Added options "security_negotiation" and "security_mechanisms" to pjsip</span><br><span style="color: hsl(120, 100%, 40%);">+endpoints and registrations. "security_negotiation" can be set to "no" (default)</span><br><span style="color: hsl(120, 100%, 40%);">+or "mediasec", and "security_mechanisms" can be a list of comma-separated</span><br><span style="color: hsl(120, 100%, 40%);">+security_mechanisms in the form defined by RFC 3329 section 2.2.</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index 3cba04a..743b19f 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -320,6 +320,45 @@</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 = 0,</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%);">+ /* 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. */</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>@@ -390,6 +429,13 @@</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%);">+ /*!</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%);">+ * Stores the values of Security-Server headers in 401/421/494 responses to an</span><br><span style="color: hsl(120, 100%, 40%);">+ * in-dialog request or successful outbound registration which will be used to</span><br><span style="color: hsl(120, 100%, 40%);">+ * set the Security-Verify headers of all subsequent requests to the contact.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</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>@@ -987,6 +1033,10 @@</span><br><span> unsigned int suppress_q850_reason_headers;</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>@@ -1038,6 +1088,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%);">+ * 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 hdr The header of the security mechanisms.</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%);">+ * 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(const pjsip_generic_string_hdr *hdr,</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%);">+</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%);">+ * 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 Duplicate a security mechanism.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param dst Security mechanism to duplicate to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param src Security mechanism to duplicate.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_sip_security_mechanism_vector *src);</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 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 49e6007..471ecd4 100644</span><br><span>--- a/include/asterisk/res_pjsip_session.h</span><br><span>+++ b/include/asterisk/res_pjsip_session.h</span><br><span>@@ -33,6 +33,8 @@</span><br><span> /* Needed for pjmedia_sdp_session and pjsip_inv_session */</span><br><span> #include <pjsip_ua.h></span><br><span> </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>diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml</span><br><span>index 3cec9a4..9e3b17d 100644</span><br><span>--- a/res/res_pjsip/pjsip_config.xml</span><br><span>+++ b/res/res_pjsip/pjsip_config.xml</span><br><span>@@ -1472,6 +1472,22 @@</span><br><span> responses.</para></span><br><span> </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="geoloc_incoming_call_profile" default=""></span><br><span> <synopsis>Geolocation profile to apply to incoming calls</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 cf42f88..e63018e 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -256,6 +256,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>@@ -2236,6 +2261,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/pjsip_options.c b/res/res_pjsip/pjsip_options.c</span><br><span>index 7632dea..220a947 100644</span><br><span>--- a/res/res_pjsip/pjsip_options.c</span><br><span>+++ b/res/res_pjsip/pjsip_options.c</span><br><span>@@ -348,6 +348,8 @@</span><br><span> {</span><br><span> struct ast_sip_contact_status *contact_status = obj;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(&contact_status->security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ast_string_field_free_memory(contact_status);</span><br><span> }</span><br><span> </span><br><span>@@ -365,6 +367,7 @@</span><br><span> ao2_ref(contact_status, -1);</span><br><span> return NULL;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_INIT(&contact_status->security_mechanisms, 0);</span><br><span> strcpy(contact_status->name, name); /* SAFE */</span><br><span> return contact_status;</span><br><span> }</span><br><span>@@ -385,6 +388,8 @@</span><br><span> dst->rtt = src->rtt;</span><br><span> dst->status = src->status;</span><br><span> dst->last_status = src->last_status;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_copy(&dst->security_mechanisms, &src->security_mechanisms);</span><br><span> return dst;</span><br><span> }</span><br><span> </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..e542e7c</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_pjsip/security_agreements.c</span><br><span>@@ -0,0 +1,340 @@</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%);">+static struct ast_sip_security_mechanism *ast_sip_security_mechanisms_alloc(size_t n_params)</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ mech = ast_calloc(1, sizeof(struct ast_sip_security_mechanism));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mech == NULL) {</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%);">+ mech->qvalue = 0.0;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_INIT(&mech->mechanism_parameters, n_params) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(mech);</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%);">+ return 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%);">+static struct ast_sip_security_mechanism *ast_sip_security_mechanisms_copy(</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_sip_security_mechanism *src)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_security_mechanism *dst = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i, n_params;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *param;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ n_params = AST_VECTOR_SIZE(&src->mechanism_parameters);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ dst = ast_sip_security_mechanisms_alloc(n_params);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (dst == NULL) {</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%);">+ dst->type = src->type;</span><br><span style="color: hsl(120, 100%, 40%);">+ dst->qvalue = src->qvalue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < n_params; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ param = ast_strdup(AST_VECTOR_GET(&src->mechanism_parameters, i));</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(&dst->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%);">+ return dst;</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 ast_sip_security_mechanisms_destroy(struct ast_sip_security_mechanism *mech)</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(&mech->mechanism_parameters); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(AST_VECTOR_GET(&mech->mechanism_parameters, i));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</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 style="color: hsl(120, 100%, 40%);">+void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_sip_security_mechanism_vector *src)</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%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(dst);</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(src); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+ mech = AST_VECTOR_GET(src, i);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(dst, ast_sip_security_mechanisms_copy(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%);">+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%);">+ struct ast_sip_security_mechanism *mech;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</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%);">+ for (i = 0; i < AST_VECTOR_SIZE(security_mechanisms); 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%);">+ ast_sip_security_mechanisms_destroy(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%);">+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 == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (security_mechanism == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(ret);</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%);">+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%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Parses a string representing a q_value to a float.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Valid q values must be in the range from 0.0 to 1.0 inclusively.</span><br><span style="color: hsl(120, 100%, 40%);">+ * </span><br><span style="color: hsl(120, 100%, 40%);">+ * \param q_value</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval The parsed qvalue or -1.0 on failure.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static float parse_qvalue(const char *q_value) {</span><br><span style="color: hsl(120, 100%, 40%);">+ char *end;</span><br><span style="color: hsl(120, 100%, 40%);">+ float ret = strtof(q_value, &end);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (end == q_value) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Not a number. */</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1.0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if ('\0' != *end) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Extra character at end of input. */</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1.0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (ret > 1.0 || ret < 0.0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Out of valid range. */</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1.0;</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%);">+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 *tmp;</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_sip_security_mechanisms_alloc(1);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ tmp = ast_strsep(&mechanism, ';', AST_STRSEP_ALL);</span><br><span style="color: hsl(120, 100%, 40%);">+ type = ast_sip_str_to_security_mechanism_type(tmp);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (type == -1) {</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%);">+</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%);">+ 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 (!strncmp(param, "q=0", 4) || !strncmp(param, "q=1", 4)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ mech->qvalue = parse_qvalue(¶m[2]);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (mech->qvalue < 0.0) {</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%);">+ 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 && (mech != NULL)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_destroy(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%);">+ ast_free(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(const pjsip_generic_string_hdr *hdr,</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%);">+</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_stricmp2(&hdr->name, "Security-Client") && pj_stricmp2(&hdr->name, "Security-Server") &&</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_stricmp2(&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%);">+ ast_sip_security_mechanisms_vector_destroy(security_mechanisms);</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>diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c</span><br><span>index 0c9b1ee..c85b5ee 100644</span><br><span>--- a/res/res_pjsip_outbound_registration.c</span><br><span>+++ b/res/res_pjsip_outbound_registration.c</span><br><span>@@ -92,6 +92,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>@@ -342,6 +358,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>@@ -389,6 +409,12 @@</span><br><span> unsigned int support_path;</span><br><span> /*! \brief Determines whether SIP Outbound support should be advertised */</span><br><span> unsigned int support_outbound;</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>@@ -561,6 +587,117 @@</span><br><span> static pj_str_t PATH_NAME = { "path", 4 };</span><br><span> static pj_str_t OUTBOUND_NAME = { "outbound", 8 };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AST_VECTOR(pjsip_generic_string_hdr_vector, pjsip_generic_string_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%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Callback function which finds a contact whose contact_status has security mechanisms.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param obj Pointer to the ast_sip_contact.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param arg Pointer-pointer to a contact_status that will be set to the contact_status found by this function.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param flags Flags used by the ao2_callback function.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The refcount of the found contact_status must be decremented by the caller.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int contact_has_security_mechanisms(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact *contact = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact_status **ret = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact_status *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 (!contact_status) {</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%);">+ if (!AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(contact_status);</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%);">+ *ret = contact_status;</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 contact_add_security_headers_to_status(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact *contact = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct pjsip_generic_string_hdr_vector *header_vector = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_contact_status *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 (!contact_status) {</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%);">+ if (AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {</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%);">+ ao2_lock(contact_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_CALLBACK_VOID(header_vector, ast_sip_header_to_security_mechanism, &contact_status->security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(contact_status);</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%);">+ ao2_cleanup(contact_status);</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%);">+/*! \brief Adds security negotiation mechanisms of outbound registration client state as Security headers to tdata. */</span><br><span style="color: hsl(120, 100%, 40%);">+static void add_security_headers(struct sip_outbound_registration_client_state *client_state,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</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 ao2_container *contact_container;</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%);">+ struct ast_sip_security_mechanism_vector *sec_mechs = NULL;</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 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%);">+ 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%);">+ /* Get contact status through registration -> endpoint name -> aor -> contact (if set) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((reg = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", client_state->registration_name))</span><br><span style="color: hsl(120, 100%, 40%);">+ && !ast_strlen_zero(reg->endpoint) && (endpt = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", reg->endpoint))</span><br><span style="color: hsl(120, 100%, 40%);">+ && (contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->aors))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Retrieve all contacts associated with aors from this endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+ * and find the first one that has security mechanisms.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_callback(contact_container, 0, contact_has_security_mechanisms, &contact_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (contact_status) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_lock(contact_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ sec_mechs = &contact_status->security_mechanisms;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(contact_container);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Use client_state->server_security_mechanisms if contact_status does not exist. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!contact_status && AST_VECTOR_SIZE(&client_state->server_security_mechanisms)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ sec_mechs = &client_state->server_security_mechanisms;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (client_state->status == SIP_REGISTRATION_REGISTERED || client_state->status == SIP_REGISTRATION_REJECTED_TEMPORARY</span><br><span style="color: hsl(120, 100%, 40%);">+ || client_state->auth_attempted) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sec_mechs != NULL && 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(sec_mechs, "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%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_security_headers(&client_state->security_mechanisms, "Security-Client", 0, 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%);">+ 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%);">+ /* Cleanup */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (contact_status) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(contact_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(contact_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(endpt);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(reg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Helper function which sends a message and cleans up, if needed, on failure */</span><br><span> static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state,</span><br><span> pjsip_tx_data *tdata)</span><br><span>@@ -585,6 +722,9 @@</span><br><span> */</span><br><span> pjsip_tx_data_add_ref(tdata);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add Security-Verify or Security-Client headers */</span><br><span style="color: hsl(120, 100%, 40%);">+ add_security_headers(client_state, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*</span><br><span> * Set the transport in case transports were reloaded.</span><br><span> * When pjproject removes the extraneous error messages produced,</span><br><span>@@ -832,6 +972,8 @@</span><br><span> </span><br><span> update_client_state_status(client_state, SIP_REGISTRATION_STOPPED);</span><br><span> ast_sip_auth_vector_destroy(&client_state->outbound_auths);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(&client_state->security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(&client_state->server_security_mechanisms);</span><br><span> ao2_ref(client_state, -1);</span><br><span> </span><br><span> return 0;</span><br><span>@@ -1089,19 +1231,60 @@</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> pjsip_cseq_hdr *cseq_hdr;</span><br><span> pjsip_tx_data *tdata;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,</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%);">+ 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 ao2_container *contact_container = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_generic_string_hdr *header;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct pjsip_generic_string_hdr_vector header_vector;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((reg = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration",</span><br><span style="color: hsl(120, 100%, 40%);">+ response->client_state->registration_name)) && reg->endpoint &&</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%);">+ /* Retrieve all contacts associated with aors from this endpoint (if set). */</span><br><span style="color: hsl(120, 100%, 40%);">+ contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->aors);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add server list of security mechanism to client_state and contact status if exists. */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_INIT(&header_vector, 1);</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%);">+ 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%);">+ AST_VECTOR_APPEND(&header_vector, header);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_header_to_security_mechanism(header, &response->client_state->server_security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ if (contact_container) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add server security mechanisms to contact status of all associated contacts to be able to send correct</span><br><span style="color: hsl(120, 100%, 40%);">+ * Security-Verify headers on subsequent non-REGISTER requests through this outbound registration.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_callback(contact_container, OBJ_NODATA, contact_add_security_headers_to_status, &header_vector);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(contact_container);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_FREE(&header_vector);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(endpt);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(reg);</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->code == 494) {</span><br><span style="color: hsl(120, 100%, 40%);">+ update_client_state_status(response->client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);</span><br><span style="color: hsl(120, 100%, 40%);">+ response->client_state->retries++;</span><br><span style="color: hsl(120, 100%, 40%);">+ schedule_registration(response->client_state, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(response, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!ast_sip_create_request_with_auth(&response->client_state->outbound_auths,</span><br><span> response->rdata, response->old_request, &tdata)) {</span><br><span> response->client_state->auth_attempted = 1;</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> res = registration_client_send(response->client_state, tdata);</span><br><span> </span><br><span> /* Save the cseq that actually got sent. */</span><br><span>@@ -1372,6 +1555,7 @@</span><br><span> struct sip_outbound_registration *registration = obj;</span><br><span> </span><br><span> ast_sip_auth_vector_destroy(®istration->outbound_auths);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(®istration->security_mechanisms);</span><br><span> </span><br><span> ast_string_field_free_memory(registration);</span><br><span> }</span><br><span>@@ -1721,6 +1905,8 @@</span><br><span> </span><br><span> /* Just in case the client state is being reused for this registration, free the auth information */</span><br><span> ast_sip_auth_vector_destroy(&state->client_state->outbound_auths);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(&state->client_state->security_mechanisms);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_destroy(&state->client_state->server_security_mechanisms);</span><br><span> </span><br><span> AST_VECTOR_INIT(&state->client_state->outbound_auths, AST_VECTOR_SIZE(®istration->outbound_auths));</span><br><span> for (i = 0; i < AST_VECTOR_SIZE(®istration->outbound_auths); ++i) {</span><br><span>@@ -1730,6 +1916,8 @@</span><br><span> ast_free(name);</span><br><span> }</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_security_mechanisms_vector_copy(&state->client_state->security_mechanisms,</span><br><span style="color: hsl(120, 100%, 40%);">+ ®istration->security_mechanisms);</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>@@ -1737,6 +1925,7 @@</span><br><span> state->client_state->retries = 0;</span><br><span> state->client_state->support_path = registration->support_path;</span><br><span> state->client_state->support_outbound = registration->support_outbound;</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>@@ -1835,6 +2024,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>@@ -2564,6 +2767,8 @@</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> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_outbound", "no", OPT_YESNO_T, 1, FLDSET(struct sip_outbound_registration, support_outbound));</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..167dfa0</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_pjsip_rfc3329.c</span><br><span>@@ -0,0 +1,150 @@</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%);">+ 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->endpoint || !session->endpoint->security_negotiation</span><br><span style="color: hsl(120, 100%, 40%);">+ || !session->contact || !(contact_status = ast_sip_get_contact_status(session->contact))) {</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%);">+ ao2_lock(contact_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (AST_VECTOR_SIZE(&contact_status->security_mechanisms)) {</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%);">+ 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 contact status 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(&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%);">+out:</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(contact_status);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(contact_status);</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 add_outgoing_request_headers(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, 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 (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(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 (contact_status == NULL) {</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%);">+ ao2_lock(contact_status);</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%);">+ } else if (!hdr && AST_VECTOR_SIZE(&endpoint->security_mechanisms)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Add Security-Client headers (no q-value) */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_security_headers(&endpoint->security_mechanisms, "Security-Client", 0, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_unlock(contact_status);</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%);">+ ao2_cleanup(contact_status);</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%);">+ if (session->contact == NULL) {</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%);">+ add_outgoing_request_headers(session->endpoint, session->contact, 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%);">+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 void rfc3329_options_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ add_outgoing_request_headers(endpoint, contact, 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%);">+static struct ast_sip_supplement rfc3329_options_supplement = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .method = "OPTIONS",</span><br><span style="color: hsl(120, 100%, 40%);">+ .outgoing_request = rfc3329_options_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%);">+ ast_sip_register_supplement(&rfc3329_options_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 e7b19e4..75f1d54 100644</span><br><span>--- a/res/res_pjsip_sdp_rtp.c</span><br><span>+++ b/res/res_pjsip_sdp_rtp.c</span><br><span>@@ -1607,6 +1607,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>@@ -1637,6 +1638,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 2b2d92e..fa3d813 100644</span><br><span>--- a/res/res_pjsip_session.c</span><br><span>+++ b/res/res_pjsip_session.c</span><br><span>@@ -4816,7 +4816,8 @@</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</span><br><span style="color: hsl(120, 100%, 40%);">+ || (session->endpoint->security_negotiation && 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>@@ -4910,7 +4911,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/+/19387">change 19387</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/+/19387"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 19 </div>
<div style="display:none"> Gerrit-Change-Id: Ia7f5b5ba42db18074fdd5428c4e1838728586be2 </div>
<div style="display:none"> Gerrit-Change-Number: 19387 </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>