<p>Friendly Automation has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18404">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">AST-2022-002 - res_stir_shaken/curl: Add ACL checks for Identity header.<br><br>Adds a new configuration option, stir_shaken_profile, in pjsip.conf that<br>can be specified on a per endpoint basis. This option will reference a<br>stir_shaken_profile that can be configured in stir_shaken.conf. The type<br>of this option must be 'profile'. The stir_shaken option can be<br>specified on this object with the same values as before (attest, verify,<br>on), but it cannot be off since having the profile itself implies wanting<br>STIR/SHAKEN support. You can also specify an ACL from acl.conf (along<br>with permit and deny lines in the object itself) that will be used to<br>limit what interfaces Asterisk will attempt to retrieve information from<br>when reading the Identity header.<br><br>ASTERISK-29476<br><br>Change-Id: I87fa61f78a9ea0cd42530691a30da3c781842406<br>---<br>M configs/samples/pjsip.conf.sample<br>M configs/samples/stir_shaken.conf.sample<br>M include/asterisk/res_pjsip.h<br>M include/asterisk/res_stir_shaken.h<br>M res/res_pjsip/pjsip_config.xml<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_stir_shaken.c<br>M res/res_stir_shaken.c<br>M res/res_stir_shaken/curl.c<br>M res/res_stir_shaken/curl.h<br>A res/res_stir_shaken/profile.c<br>A res/res_stir_shaken/profile.h<br>A res/res_stir_shaken/profile_private.h<br>13 files changed, 558 insertions(+), 17 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/04/18404/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample</span><br><span>index 8507b4e..b1c1657 100644</span><br><span>--- a/configs/samples/pjsip.conf.sample</span><br><span>+++ b/configs/samples/pjsip.conf.sample</span><br><span>@@ -349,6 +349,7 @@</span><br><span> ; STIR/SHAKEN support.</span><br><span> ;</span><br><span> ;stir_shaken=no</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken_profile=my_profile</span><br><span> </span><br><span> ;[6001]</span><br><span> ;type=auth</span><br><span>@@ -930,6 +931,9 @@</span><br><span>                            ; happens to the call if verification fails; it's up to</span><br><span>                            ; you to determine what to do with the results.</span><br><span>                            ; (default: no)</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken_profile =</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; If a profile is specified (defined in stir_shaken.conf),</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; this endpoint will follow the rules defined there.</span><br><span> ;allow_unauthenticated_options =</span><br><span>                            ; By default, chan_pjsip will challenge an incoming</span><br><span>                            ; OPTIONS request for authentication credentials just</span><br><span>diff --git a/configs/samples/stir_shaken.conf.sample b/configs/samples/stir_shaken.conf.sample</span><br><span>index c39bc97..677d3bb 100644</span><br><span>--- a/configs/samples/stir_shaken.conf.sample</span><br><span>+++ b/configs/samples/stir_shaken.conf.sample</span><br><span>@@ -83,3 +83,21 @@</span><br><span> ;</span><br><span> ; Must have an attestation of A, B, or C</span><br><span> ;attestation=C</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%);">+; Profiles can be defined here which can be referenced by channel drivers.</span><br><span style="color: hsl(120, 100%, 40%);">+;[my_profile]</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; type must be "profile"</span><br><span style="color: hsl(120, 100%, 40%);">+;type=profile</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; Set stir_shaken to 'attest', 'verify', or 'on', which is the default</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken=on</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; You can specify an ACL that will be used strictly for the Identity header when downloading public certificates</span><br><span style="color: hsl(120, 100%, 40%);">+;acllist=myacllist</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; You can also do permit / deny lines if you want (also supports IPv6)</span><br><span style="color: hsl(120, 100%, 40%);">+;permit=0.0.0.0/0.0.0.0</span><br><span style="color: hsl(120, 100%, 40%);">+;deny=127.0.0.1</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index 9f35393..209cdbf 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -878,6 +878,8 @@</span><br><span>               AST_STRING_FIELD(accountcode);</span><br><span>               /*! If set, we'll push incoming MWI NOTIFYs to stasis using this mailbox */</span><br><span>              AST_STRING_FIELD(incoming_mwi_mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+               /*! STIR/SHAKEN profile to use */</span><br><span style="color: hsl(120, 100%, 40%);">+             AST_STRING_FIELD(stir_shaken_profile);</span><br><span>       );</span><br><span>   /*! Configuration for extensions */</span><br><span>  struct ast_sip_endpoint_extensions extensions;</span><br><span>diff --git a/include/asterisk/res_stir_shaken.h b/include/asterisk/res_stir_shaken.h</span><br><span>index 92eb0ec..ece99b5 100644</span><br><span>--- a/include/asterisk/res_stir_shaken.h</span><br><span>+++ b/include/asterisk/res_stir_shaken.h</span><br><span>@@ -38,6 +38,8 @@</span><br><span> </span><br><span> struct ast_stir_shaken_payload;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_acl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_json;</span><br><span> </span><br><span> /*!</span><br><span>@@ -66,6 +68,38 @@</span><br><span> unsigned int ast_stir_shaken_get_signature_timeout(void);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a stir_shaken_profile by id</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The profile will need to be unref'd when not needed anymore</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id The id of the stir_shaken_profile to get</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval stir_shaken_profile on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile(const char *id);</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 Check if a stir_shaken_profile supports attestation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile The stir_shaken_profile to test</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 if not supported</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if supported</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_stir_shaken_profile_supports_attestation(const struct stir_shaken_profile *profile);</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 Check if a stir_shaken_profile supports verification</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile The stir_shaken_profile to test</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 if not supported</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if supported</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_stir_shaken_profile_supports_verification(const struct stir_shaken_profile *profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Add a STIR/SHAKEN verification result to a channel</span><br><span>  *</span><br><span>  * \param chan The channel</span><br><span>@@ -113,6 +147,26 @@</span><br><span>  const char *algorithm, const char *public_cert_url, int *failure_code);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Same as ast_stir_shaken_verify2, but passes in a stir_shaken_profile with additional configuration</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note failure_code will be written to in this function</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param header The payload header</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param payload The payload section</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param signature The payload signature</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param algorithm The signature algorithm</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param public_cert_url The public key URL</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param failure_code Additional failure information</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile The stir_shaken_profile</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval ast_stir_shaken_payload on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stir_shaken_payload *ast_stir_shaken_verify_with_profile(const char *header, const char *payload,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *signature, const char *algorithm, const char *public_cert_url, int *failure,</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct stir_shaken_profile *profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span>  * \brief Retrieve the stir/shaken sorcery context</span><br><span>  *</span><br><span>  * \retval The stir/shaken sorcery context</span><br><span>diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml</span><br><span>index 3e0a6e7..ca5a266 100644</span><br><span>--- a/res/res_pjsip/pjsip_config.xml</span><br><span>+++ b/res/res_pjsip/pjsip_config.xml</span><br><span>@@ -1424,6 +1424,13 @@</span><br><span>                                           INVITEs, an Identity header will be added.</para></span><br><span>                                      </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="stir_shaken_profile" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                        <synopsis>STIR/SHAKEN profile containing additional configuration options</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                               A STIR/SHAKEN profile that is defined in stir_shaken.conf. Contains</span><br><span style="color: hsl(120, 100%, 40%);">+                                           several options and rules used for STIR/SHAKEN.</para></span><br><span style="color: hsl(120, 100%, 40%);">+                                  </description></span><br><span style="color: hsl(120, 100%, 40%);">+                          </configOption></span><br><span>                                <configOption name="allow_unauthenticated_options" default="no"></span><br><span>                                   <synopsis>Skip authentication when receiving OPTIONS requests</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 e32a3d2..39c3dab 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -2192,6 +2192,7 @@</span><br><span>             "prefer: pending, operation: intersect, keep: all",</span><br><span>                codec_prefs_handler, outgoing_answer_codec_prefs_to_str, NULL, 0, 0);</span><br><span>        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "stir_shaken", "off", stir_shaken_handler, stir_shaken_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+   ast_sorcery_object_field_register(sip_sorcery, "endpoint", "stir_shaken_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, stir_shaken_profile));</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> </span><br><span>  if (ast_sip_initialize_sorcery_transport()) {</span><br><span>diff --git a/res/res_pjsip_stir_shaken.c b/res/res_pjsip_stir_shaken.c</span><br><span>index 27aa4d8..19e846f 100644</span><br><span>--- a/res/res_pjsip_stir_shaken.c</span><br><span>+++ b/res/res_pjsip_stir_shaken.c</span><br><span>@@ -217,13 +217,16 @@</span><br><span>       int mismatch = 0;</span><br><span>    struct ast_stir_shaken_payload *ss_payload;</span><br><span>  int failure_code = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct stir_shaken_profile *, profile, NULL, ao2_cleanup);</span><br><span> </span><br><span>      /* Check if this is a reinvite. If it is, we don't need to do anything */</span><br><span>        if (rdata->msg_info.to->tag.slen) {</span><br><span>            return 0;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_VERIFY) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+   profile = ast_stir_shaken_get_profile(session->endpoint->stir_shaken_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+  if ((profile && !ast_stir_shaken_profile_supports_verification(profile))</span><br><span style="color: hsl(120, 100%, 40%);">+              && ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_VERIFY) == 0)) {</span><br><span>                 return 0;</span><br><span>    }</span><br><span> </span><br><span>@@ -309,7 +312,8 @@</span><br><span> </span><br><span>      attestation = get_attestation_from_payload(payload);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        ss_payload = ast_stir_shaken_verify2(header, payload, signature, algorithm, public_cert_url, &failure_code);</span><br><span style="color: hsl(120, 100%, 40%);">+      ss_payload = ast_stir_shaken_verify_with_profile(header, payload, signature, algorithm, public_cert_url, &failure_code, profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      if (!ss_payload) {</span><br><span> </span><br><span>               if (failure_code == AST_STIR_SHAKEN_VERIFY_FAILED_TO_GET_CERT) {</span><br><span>@@ -471,7 +475,11 @@</span><br><span> </span><br><span> static void stir_shaken_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     if ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_ATTEST) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+   RAII_VAR(struct stir_shaken_profile *, profile, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ profile = ast_stir_shaken_get_profile(session->endpoint->stir_shaken_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+  if ((profile && !ast_stir_shaken_profile_supports_attestation(profile))</span><br><span style="color: hsl(120, 100%, 40%);">+               && ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_ATTEST) == 0)) {</span><br><span>                 return;</span><br><span>      }</span><br><span> </span><br><span>diff --git a/res/res_stir_shaken.c b/res/res_stir_shaken.c</span><br><span>index 19e2654..52480ff 100644</span><br><span>--- a/res/res_stir_shaken.c</span><br><span>+++ b/res/res_stir_shaken.c</span><br><span>@@ -38,6 +38,7 @@</span><br><span> #include "asterisk/global_datastores.h"</span><br><span> #include "asterisk/app.h"</span><br><span> #include "asterisk/test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/acl.h"</span><br><span> </span><br><span> #include "asterisk/res_stir_shaken.h"</span><br><span> #include "res_stir_shaken/stir_shaken.h"</span><br><span>@@ -45,6 +46,7 @@</span><br><span> #include "res_stir_shaken/store.h"</span><br><span> #include "res_stir_shaken/certificate.h"</span><br><span> #include "res_stir_shaken/curl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "res_stir_shaken/profile.h"</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span>  <configInfo name="res_stir_shaken" language="en_US"></span><br><span>@@ -108,6 +110,29 @@</span><br><span>                                        <synopsis>The caller ID number to match on.</synopsis></span><br><span>                           </configOption></span><br><span>                        </configObject></span><br><span style="color: hsl(120, 100%, 40%);">+                 <configObject name="profile"></span><br><span style="color: hsl(120, 100%, 40%);">+                         <synopsis>STIR/SHAKEN profile configuration options</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                            <configOption name="type"></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <synopsis>Must be of type 'profile'.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                           </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="stir_shaken" default="on"></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <synopsis>STIR/SHAKEN configuration settings</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                   <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                               Attest, verify, or do both STIR/SHAKEN operations. On incoming</span><br><span style="color: hsl(120, 100%, 40%);">+                                                INVITEs, the Identity header will be checked for validity. On</span><br><span style="color: hsl(120, 100%, 40%);">+                                         outgoing INVITEs, an Identity header will be added.</para></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="acllist" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                    <synopsis>An existing ACL from acl.conf to use</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                         </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="permit" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                     <synopsis>An IP or subnet to permit</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                            </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="deny" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+                                       <synopsis>An IP or subnet to deny</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                              </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                 </configObject></span><br><span>                </configFile></span><br><span>  </configInfo></span><br><span>  <function name="STIR_SHAKEN" language="en_US"></span><br><span>@@ -205,6 +230,33 @@</span><br><span>      return ast_stir_shaken_signature_timeout(stir_shaken_general_get());</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_strlen_zero(id)) {</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 ast_stir_shaken_get_profile_by_name(id);</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%);">+unsigned int ast_stir_shaken_profile_supports_attestation(const struct stir_shaken_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!profile) {</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%);">+   return (profile->stir_shaken & STIR_SHAKEN_ATTEST);</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%);">+unsigned int ast_stir_shaken_profile_supports_verification(const struct stir_shaken_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!profile) {</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%);">+   return (profile->stir_shaken & STIR_SHAKEN_VERIFY);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \brief Convert an ast_stir_shaken_verification_result to string representation</span><br><span>  *</span><br><span>@@ -556,7 +608,7 @@</span><br><span>  * \retval NULL on failure</span><br><span>  * \retval full path filename on success</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static char *run_curl(const char *public_cert_url, const char *path)</span><br><span style="color: hsl(120, 100%, 40%);">+static char *run_curl(const char *public_cert_url, const char *path, const struct ast_acl_list *acl)</span><br><span> {</span><br><span>      struct curl_cb_data *data;</span><br><span>   char *filename;</span><br><span>@@ -567,7 +619,7 @@</span><br><span>                return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   filename = curl_public_key(public_cert_url, path, data);</span><br><span style="color: hsl(120, 100%, 40%);">+      filename = curl_public_key(public_cert_url, path, data, acl);</span><br><span>        if (!filename) {</span><br><span>             ast_log(LOG_ERROR, "Could not retrieve public key for '%s'\n", public_cert_url);</span><br><span>           curl_cb_data_free(data);</span><br><span>@@ -593,7 +645,7 @@</span><br><span>  * \retval NULL on failure</span><br><span>  * \retval full path filename on success</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static char *curl_and_check_expiration(const char *public_cert_url, const char *path, int *curl)</span><br><span style="color: hsl(120, 100%, 40%);">+static char *curl_and_check_expiration(const char *public_cert_url, const char *path, int *curl, const struct ast_acl_list *acl)</span><br><span> {</span><br><span>       char *filename;</span><br><span> </span><br><span>@@ -602,7 +654,7 @@</span><br><span>            return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   filename = run_curl(public_cert_url, path);</span><br><span style="color: hsl(120, 100%, 40%);">+   filename = run_curl(public_cert_url, path, acl);</span><br><span>     if (!filename) {</span><br><span>             return NULL;</span><br><span>         }</span><br><span>@@ -664,7 +716,8 @@</span><br><span>  * \retval 0 on success</span><br><span>  * \retval 1 on failure</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static int stir_shaken_verify_setup_file_paths(const char *public_cert_url, char **file_path, char **dir_path, int *curl)</span><br><span style="color: hsl(120, 100%, 40%);">+static int stir_shaken_verify_setup_file_paths(const char *public_cert_url, char **file_path, char **dir_path, int *curl,</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct ast_acl_list *acl)</span><br><span> {</span><br><span>         *file_path = get_path_to_public_key(public_cert_url);</span><br><span>        if (ast_asprintf(dir_path, "%s/keys/%s", ast_config_AST_DATA_DIR, STIR_SHAKEN_DIR_NAME) < 0) {</span><br><span>@@ -682,7 +735,7 @@</span><br><span>            ast_free(*file_path);</span><br><span> </span><br><span>            /* Download to the default path */</span><br><span style="color: hsl(0, 100%, 40%);">-              *file_path = run_curl(public_cert_url, *dir_path);</span><br><span style="color: hsl(120, 100%, 40%);">+            *file_path = run_curl(public_cert_url, *dir_path, acl);</span><br><span>              if (!(*file_path)) {</span><br><span>                         return 1;</span><br><span>            }</span><br><span>@@ -706,7 +759,7 @@</span><br><span>  * \retval 1 on failure</span><br><span>  */</span><br><span> static int stir_shaken_verify_validate_cert(const char *public_cert_url, char **file_path, char *dir_path, int *curl,</span><br><span style="color: hsl(0, 100%, 40%);">-      EVP_PKEY **public_key)</span><br><span style="color: hsl(120, 100%, 40%);">+        EVP_PKEY **public_key, const struct ast_acl_list *acl)</span><br><span> {</span><br><span>  if (public_key_is_expired(public_cert_url)) {</span><br><span> </span><br><span>@@ -716,7 +769,7 @@</span><br><span> </span><br><span>          /* If this fails, then there's nothing we can do */</span><br><span>              ast_free(*file_path);</span><br><span style="color: hsl(0, 100%, 40%);">-           *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl);</span><br><span style="color: hsl(120, 100%, 40%);">+              *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl, acl);</span><br><span>                if (!(*file_path)) {</span><br><span>                         return 1;</span><br><span>            }</span><br><span>@@ -732,7 +785,7 @@</span><br><span>              remove_public_key_from_astdb(public_cert_url);</span><br><span> </span><br><span>           ast_free(*file_path);</span><br><span style="color: hsl(0, 100%, 40%);">-           *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl);</span><br><span style="color: hsl(120, 100%, 40%);">+              *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl, acl);</span><br><span>                if (!(*file_path)) {</span><br><span>                         return 1;</span><br><span>            }</span><br><span>@@ -759,6 +812,12 @@</span><br><span> struct ast_stir_shaken_payload *ast_stir_shaken_verify2(const char *header, const char *payload, const char *signature,</span><br><span>  const char *algorithm, const char *public_cert_url, int *failure_code)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+   return ast_stir_shaken_verify_with_profile(header, payload, signature, algorithm, public_cert_url, failure_code, 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%);">+struct ast_stir_shaken_payload *ast_stir_shaken_verify_with_profile(const char *header, const char *payload, const char *signature,</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *algorithm, const char *public_cert_url, int *failure_code, const struct stir_shaken_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span>         struct ast_stir_shaken_payload *ret_payload;</span><br><span>         EVP_PKEY *public_key;</span><br><span>        int curl = 0;</span><br><span>@@ -766,11 +825,14 @@</span><br><span>        RAII_VAR(char *, dir_path, NULL, ast_free);</span><br><span>  RAII_VAR(char *, combined_str, NULL, ast_free);</span><br><span>      size_t combined_size;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_acl_list *acl;</span><br><span> </span><br><span>  if (stir_shaken_verify_check_empty_strings(header, payload, signature, algorithm, public_cert_url)) {</span><br><span>                return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ acl = profile ? (const struct ast_acl_list *)profile->acl : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       /* Check to see if we have already downloaded this public cert. The reason we</span><br><span>         * store the file path is because:</span><br><span>    *</span><br><span>@@ -781,12 +843,12 @@</span><br><span>    * {configurable) directories, we already have the storage mechanism in place.</span><br><span>        * The only thing that would be left to do is pull from the configuration.</span><br><span>    */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (stir_shaken_verify_setup_file_paths(public_cert_url, &file_path, &dir_path, &curl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (stir_shaken_verify_setup_file_paths(public_cert_url, &file_path, &dir_path, &curl, acl)) {</span><br><span>           return NULL;</span><br><span>         }</span><br><span> </span><br><span>        /* Check to see if the cert we downloaded (or already had) is expired */</span><br><span style="color: hsl(0, 100%, 40%);">-        if (stir_shaken_verify_validate_cert(public_cert_url, &file_path, dir_path, &curl, &public_key)) {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (stir_shaken_verify_validate_cert(public_cert_url, &file_path, dir_path, &curl, &public_key, acl)) {</span><br><span>          *failure_code = AST_STIR_SHAKEN_VERIFY_FAILED_TO_GET_CERT;</span><br><span>           return NULL;</span><br><span>         }</span><br><span>@@ -1679,6 +1741,7 @@</span><br><span> {</span><br><span>       int res = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      stir_shaken_profile_unload();</span><br><span>        stir_shaken_certificate_unload();</span><br><span>    stir_shaken_store_unload();</span><br><span>  stir_shaken_general_unload();</span><br><span>@@ -1718,6 +1781,11 @@</span><br><span>               return AST_MODULE_LOAD_DECLINE;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (stir_shaken_profile_load()) {</span><br><span style="color: hsl(120, 100%, 40%);">+             unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  ast_sorcery_load(ast_stir_shaken_sorcery());</span><br><span> </span><br><span>     res |= ast_custom_function_register(&stir_shaken_function);</span><br><span>diff --git a/res/res_stir_shaken/curl.c b/res/res_stir_shaken/curl.c</span><br><span>index cd78461..fb06de5 100644</span><br><span>--- a/res/res_stir_shaken/curl.c</span><br><span>+++ b/res/res_stir_shaken/curl.c</span><br><span>@@ -21,9 +21,12 @@</span><br><span> #include "asterisk/utils.h"</span><br><span> #include "asterisk/logger.h"</span><br><span> #include "asterisk/file.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/acl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include "curl.h"</span><br><span> #include "general.h"</span><br><span> #include "stir_shaken.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "profile.h"</span><br><span> </span><br><span> #include <curl/curl.h></span><br><span> #include <sys/stat.h></span><br><span>@@ -52,6 +55,11 @@</span><br><span>   const char *url;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct curl_cb_open_socket {</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct ast_acl_list *acl;</span><br><span style="color: hsl(120, 100%, 40%);">+       curl_socket_t *sockfd;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct curl_cb_data *curl_cb_data_create(void)</span><br><span> {</span><br><span>  struct curl_cb_data *data;</span><br><span>@@ -73,6 +81,18 @@</span><br><span>      ast_free(data);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void curl_cb_open_socket_free(struct curl_cb_open_socket *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!data) {</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%);">+   close(*data->sockfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* We don't need to free the ACL since we just use a reference */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> char *curl_cb_data_get_cache_control(const struct curl_cb_data *data)</span><br><span> {</span><br><span>   if (!data) {</span><br><span>@@ -200,7 +220,26 @@</span><br><span>  return real_size;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data)</span><br><span style="color: hsl(120, 100%, 40%);">+static curl_socket_t stir_shaken_curl_open_socket_callback(void *our_data, curlsocktype purpose, struct curl_sockaddr *address)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct curl_cb_open_socket *data = our_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!ast_acl_list_is_empty((struct ast_acl_list *)data->acl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            struct ast_sockaddr ast_address = { {0,} };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_sockaddr_copy_sockaddr(&ast_address, &address->addr, address->addrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (ast_apply_acl((struct ast_acl_list *)data->acl, &ast_address, NULL) != AST_SENSE_ALLOW) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  return CURLE_COULDNT_CONNECT;</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%);">+   *data->sockfd = socket(address->family, address->socktype, address->protocol);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return *data->sockfd;</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%);">+char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data, const struct ast_acl_list *acl)</span><br><span> {</span><br><span>  FILE *public_key_file;</span><br><span>       char *filename;</span><br><span>@@ -209,13 +248,25 @@</span><br><span>      CURL *curl;</span><br><span>  char curl_errbuf[CURL_ERROR_SIZE + 1];</span><br><span>       struct curl_cb_write_buf *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct curl_cb_open_socket *open_socket_data;</span><br><span style="color: hsl(120, 100%, 40%);">+ curl_socket_t sockfd;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       buf = ast_calloc(1, sizeof(*buf));</span><br><span style="color: hsl(120, 100%, 40%);">+    curl_errbuf[CURL_ERROR_SIZE] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        buf = ast_calloc(1, sizeof(*buf));</span><br><span>   if (!buf) {</span><br><span>          ast_log(LOG_ERROR, "Failed to allocate memory for CURL write buffer for %s\n", public_cert_url);</span><br><span>           return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ open_socket_data = ast_calloc(1, sizeof(*open_socket_data));</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!open_socket_data) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Failed to allocate memory for open socket callback\n");</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%);">+     open_socket_data->acl = acl;</span><br><span style="color: hsl(120, 100%, 40%);">+       open_socket_data->sockfd = &sockfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         buf->url = public_cert_url;</span><br><span>       curl_errbuf[CURL_ERROR_SIZE] = '\0';</span><br><span> </span><br><span>@@ -231,14 +282,19 @@</span><br><span>     curl_easy_setopt(curl, CURLOPT_WRITEDATA, buf);</span><br><span>      curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);</span><br><span>    curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, MAX_BUF_SIZE_PER_WRITE);</span><br><span style="color: hsl(120, 100%, 40%);">+   curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, stir_shaken_curl_open_socket_callback);</span><br><span style="color: hsl(120, 100%, 40%);">+    curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, open_socket_data);</span><br><span> </span><br><span>        if (curl_easy_perform(curl)) {</span><br><span>               ast_log(LOG_ERROR, "%s\n", curl_errbuf);</span><br><span>           curl_easy_cleanup(curl);</span><br><span>             ast_free(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+                curl_cb_open_socket_free(open_socket_data);</span><br><span>          return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ curl_cb_open_socket_free(open_socket_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);</span><br><span> </span><br><span>         curl_easy_cleanup(curl);</span><br><span>diff --git a/res/res_stir_shaken/curl.h b/res/res_stir_shaken/curl.h</span><br><span>index ae8feda..2dbd5d2 100644</span><br><span>--- a/res/res_stir_shaken/curl.h</span><br><span>+++ b/res/res_stir_shaken/curl.h</span><br><span>@@ -18,6 +18,8 @@</span><br><span> #ifndef _STIR_SHAKEN_CURL_H</span><br><span> #define _STIR_SHAKEN_CURL_H</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_acl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Forward declaration for CURL callback data */</span><br><span> struct curl_cb_data;</span><br><span> </span><br><span>@@ -66,10 +68,11 @@</span><br><span>  * \param public_cert_url The public cert URL</span><br><span>  * \param path The path to download the file to</span><br><span>  * \param data The curl_cb_data</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param acl The ACL to use for cURL (if not NULL)</span><br><span>  *</span><br><span>  * \retval NULL on failure</span><br><span>  * \retval full path filename on success</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data);</span><br><span style="color: hsl(120, 100%, 40%);">+char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data, const struct ast_acl_list *acl);</span><br><span> </span><br><span> #endif /* _STIR_SHAKEN_CURL_H */</span><br><span>diff --git a/res/res_stir_shaken/profile.c b/res/res_stir_shaken/profile.c</span><br><span>new file mode 100644</span><br><span>index 0000000..5d4fa9b</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_stir_shaken/profile.c</span><br><span>@@ -0,0 +1,241 @@</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, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Ben Ford <bford@sangoma.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%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/cli.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "stir_shaken.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "profile.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_stir_shaken.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_TYPE "profile"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void stir_shaken_profile_destructor(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_free_acl_list(cfg->acl);</span><br><span style="color: hsl(120, 100%, 40%);">+</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%);">+static void *stir_shaken_profile_alloc(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct stir_shaken_profile *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    cfg = ast_sorcery_generic_alloc(sizeof(*cfg), stir_shaken_profile_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!cfg) {</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 cfg;</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 stir_shaken_profile *stir_shaken_profile_get(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return ast_sorcery_retrieve_by_id(ast_stir_shaken_sorcery(), CONFIG_TYPE, id);</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 ao2_container *stir_shaken_profile_get_all(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        return ast_sorcery_retrieve_by_fields(ast_stir_shaken_sorcery(), CONFIG_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+         AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, 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%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile_by_name(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sorcery_retrieve_by_id(ast_stir_shaken_sorcery(), CONFIG_TYPE, name);</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 stir_shaken_profile_apply(const struct ast_sorcery *sorcery, void *obj)</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 stir_shaken_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 stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!strcasecmp("attest", var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         cfg->stir_shaken = STIR_SHAKEN_ATTEST;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (!strcasecmp("verify", var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          cfg->stir_shaken = STIR_SHAKEN_VERIFY;</span><br><span style="color: hsl(120, 100%, 40%);">+     } else if (!strcasecmp("on", var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              cfg->stir_shaken = STIR_SHAKEN_ON;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_WARNING, "'%s' is not a valid value for option "</span><br><span style="color: hsl(120, 100%, 40%);">+                        "'stir_shaken' for %s %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                var->value, CONFIG_TYPE, ast_sorcery_object_get_id(cfg));</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%);">+   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 const char *stir_shaken_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+      [STIR_SHAKEN_ATTEST] = "attest",</span><br><span style="color: hsl(120, 100%, 40%);">+    [STIR_SHAKEN_VERIFY] = "verify",</span><br><span style="color: hsl(120, 100%, 40%);">+    [STIR_SHAKEN_ON] = "on",</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 stir_shaken_to_str(const void *obj, const intptr_t *args, char **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ARRAY_IN_BOUNDS(cfg->stir_shaken, stir_shaken_map)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          *buf = ast_strdup(stir_shaken_map[cfg->stir_shaken]);</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 stir_shaken_acl_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 stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+        int error = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        int ignore;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(var->value)) {</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_append_acl(var->name, var->value, &cfg->acl, &error, &ignore);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return error;</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 acl_to_str(const void *obj, const intptr_t *args, char **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct ast_acl_list *acl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct ast_acl *first_acl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (cfg && !ast_acl_list_is_empty(acl_list=cfg->acl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            AST_LIST_LOCK(acl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+              first_acl = AST_LIST_FIRST(acl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (ast_strlen_zero(first_acl->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    *buf = "deny/permit";</span><br><span style="color: hsl(120, 100%, 40%);">+               } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      *buf = first_acl->name;</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             AST_LIST_UNLOCK(acl_list);</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 = ast_strdup(*buf);</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 char *stir_shaken_profile_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct stir_shaken_profile *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch(cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "stir_shaken show profile";</span><br><span style="color: hsl(120, 100%, 40%);">+         e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Usage: stir_shaken show profile <id>\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                      "       Show the stir/shaken profile settings for a given id\n";</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+            if (a->pos == 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 return stir_shaken_tab_complete_name(a->word, stir_shaken_profile_get_all());</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%);">+   if (a->argc != 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return CLI_SHOWUSAGE;</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%);">+   cfg = stir_shaken_profile_get(a->argv[3]);</span><br><span style="color: hsl(120, 100%, 40%);">+ stir_shaken_cli_show(cfg, a, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_acl_output(a->fd, cfg->acl, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  ao2_cleanup(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CLI_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 char *stir_shaken_profile_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct ao2_container *container;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    switch(cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+                e->command = "stir_shaken show profiles";</span><br><span style="color: hsl(120, 100%, 40%);">+                e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+                 "Usage: stir_shaken show profiles\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                        "       Show all profiles for stir/shaken\n";</span><br><span style="color: hsl(120, 100%, 40%);">+               return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CLI_GENERATE:</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%);">+   if (a->argc != 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+                return CLI_SHOWUSAGE;</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%);">+   container = stir_shaken_profile_get_all();</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!container || ao2_container_count(container) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_cli(a->fd, "No stir/shaken ACLs found\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           ao2_cleanup(container);</span><br><span style="color: hsl(120, 100%, 40%);">+               return CLI_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%);">+   ao2_callback(container, OBJ_NODATA, stir_shaken_cli_show, a);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     return CLI_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 struct ast_cli_entry stir_shaken_profile_cli[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_CLI_DEFINE(stir_shaken_profile_show, "Show stir/shaken profile by id"),</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_CLI_DEFINE(stir_shaken_profile_show_all, "Show all stir/shaken profiles"),</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 stir_shaken_profile_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_cli_unregister_multiple(stir_shaken_profile_cli,</span><br><span style="color: hsl(120, 100%, 40%);">+          ARRAY_LEN(stir_shaken_profile_cli));</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%);">+int stir_shaken_profile_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sorcery *sorcery = ast_stir_shaken_sorcery();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_sorcery_apply_default(sorcery, CONFIG_TYPE, "config", "stir_shaken.conf,criteria=type=profile");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (ast_sorcery_object_register(sorcery, CONFIG_TYPE, stir_shaken_profile_alloc,</span><br><span style="color: hsl(120, 100%, 40%);">+              NULL, stir_shaken_profile_apply)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "stir/shaken - failed to register '%s' sorcery object\n", CONFIG_TYPE);</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%);">+   ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "type", "", OPT_NOOP_T, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "stir_shaken", "on", stir_shaken_handler, stir_shaken_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "deny", "", stir_shaken_acl_handler, NULL, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "permit", "", stir_shaken_acl_handler, NULL, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "acllist", "", stir_shaken_acl_handler, acl_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli_register_multiple(stir_shaken_profile_cli,</span><br><span style="color: hsl(120, 100%, 40%);">+            ARRAY_LEN(stir_shaken_profile_cli));</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_stir_shaken/profile.h b/res/res_stir_shaken/profile.h</span><br><span>new file mode 100644</span><br><span>index 0000000..5617e9a</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_stir_shaken/profile.h</span><br><span>@@ -0,0 +1,39 @@</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, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Ben Ford <bford@sangoma.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%);">+#ifndef _STIR_SHAKEN_PROFILE_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define _STIR_SHAKEN_PROFILE_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "profile_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile_by_name(const char *name);</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 Load time initialization for the stir/shaken 'profile' object</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success, -1 on error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int stir_shaken_profile_load(void);</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 Unload time cleanup for the stir/shaken 'profile'</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success, -1 on error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int stir_shaken_profile_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* _STIR_SHAKEN_PROFILE_H */</span><br><span>diff --git a/res/res_stir_shaken/profile_private.h b/res/res_stir_shaken/profile_private.h</span><br><span>new file mode 100644</span><br><span>index 0000000..536a0fe</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_stir_shaken/profile_private.h</span><br><span>@@ -0,0 +1,40 @@</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, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Ben Ford <bford@sangoma.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%);">+#ifndef _STIR_SHAKEN_PROFILE_PRIVATE_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define _STIR_SHAKEN_PROFILE_PRIVATE_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/acl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum stir_shaken_profile_behavior {</span><br><span style="color: hsl(120, 100%, 40%);">+        /*! Only do STIR/SHAKEN attestation */</span><br><span style="color: hsl(120, 100%, 40%);">+        STIR_SHAKEN_ATTEST = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Only do STIR/SHAKEN verification */</span><br><span style="color: hsl(120, 100%, 40%);">+       STIR_SHAKEN_VERIFY = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+       /*! Do STIR/SHAKEN attestation and verification */</span><br><span style="color: hsl(120, 100%, 40%);">+    STIR_SHAKEN_ON = 3,</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 stir_shaken_profile {</span><br><span style="color: hsl(120, 100%, 40%);">+       SORCERY_OBJECT(details);</span><br><span style="color: hsl(120, 100%, 40%);">+      unsigned int stir_shaken;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct ast_acl_list *acl;</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%);">+#endif /* _STIR_SHAKEN_PROFILE_PRIVATE_H */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18404">change 18404</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/+/18404"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 18 </div>
<div style="display:none"> Gerrit-Change-Id: I87fa61f78a9ea0cd42530691a30da3c781842406 </div>
<div style="display:none"> Gerrit-Change-Number: 18404 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Friendly Automation </div>
<div style="display:none"> Gerrit-CC: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>