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

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Ia7f5b5ba42db18074fdd5428c4e1838728586be2 </div>
<div style="display:none"> Gerrit-Change-Number: 18837 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Maximilian Fridrich <m.fridrich@commend.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>