<p>George Joseph <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/14574">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Joshua Colp: Looks good to me, but someone else must approve
  George Joseph: Looks good to me, approved; Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_stir_shaken: Add stir_shaken option and general improvements.<br><br>Added a new configuration option for PJSIP endpoints - stir_shaken. If<br>set to yes, then STIR/SHAKEN support will be added to inbound and<br>outbound INVITEs. The default is no. Alembic has been updated to include<br>this option.<br><br>Previously the dialplan function was not trimming the whitespace from<br>the parameters it recieved. Now it does.<br><br>Also added a conditional that, when TEST_FRAMEWORK is enabled, the<br>timestamp in the identity header will be overlooked. This is just for<br>testing, since the testsuite will rely on a SIPp scenario with a preset<br>identity header to trigger the MISMATCH result.<br><br>Change-Id: I43d67f1489b8c1c5729ed3ca8d71e35ddf438df1<br>---<br>M configs/samples/pjsip.conf.sample<br>M configs/samples/stir_shaken.conf.sample<br>A contrib/ast-db-manage/config/versions/61797b9fced6_add_stir_shaken.py<br>A doc/CHANGES-staging/stir_shaken.txt<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_stir_shaken.c<br>M res/res_stir_shaken.c<br>9 files changed, 127 insertions(+), 14 deletions(-)<br><br></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 cdb585d..2636f63 100644</span><br><span>--- a/configs/samples/pjsip.conf.sample</span><br><span>+++ b/configs/samples/pjsip.conf.sample</span><br><span>@@ -345,6 +345,10 @@</span><br><span> ;device_state_busy_at=1</span><br><span> ;allow_subscribe=yes</span><br><span> ;sub_min_expiry=30</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; STIR/SHAKEN support.</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken=no</span><br><span> </span><br><span> ;[6001]</span><br><span> ;type=auth</span><br><span>@@ -961,6 +965,20 @@</span><br><span>                            ; chan_sip and prevents these 183 responses from</span><br><span>                            ; being forwarded.</span><br><span>                            ; (default: no)</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken =</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; If this is enabled, STIR/SHAKEN operations will be</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; performed on this endpoint. This includes inbound</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; and outbound INVITEs. On an inbound INVITE, Asterisk</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; will check for an Identity header and attempt to</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; verify the call. On an outbound INVITE, Asterisk will</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; add an Identity header that others can use to verify</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; calls from this endpoint. Additional configuration is</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; done in stir_shaken.conf.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; The STIR_SHAKEN dialplan function must be used to get</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; the verification results on inbound INVITEs. Nothing</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; happens to the call if verification fails; it's up to</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; you to determine what to do with the results.</span><br><span style="color: hsl(120, 100%, 40%);">+                           ; (default: no)</span><br><span> </span><br><span> ;==========================AUTH SECTION OPTIONS=========================</span><br><span> ;[auth]</span><br><span>diff --git a/configs/samples/stir_shaken.conf.sample b/configs/samples/stir_shaken.conf.sample</span><br><span>index 71acad2..957fd14 100644</span><br><span>--- a/configs/samples/stir_shaken.conf.sample</span><br><span>+++ b/configs/samples/stir_shaken.conf.sample</span><br><span>@@ -14,8 +14,11 @@</span><br><span> ; Maximum size to use for caching public keys</span><br><span> ;cache_max_size=1000</span><br><span> ;</span><br><span style="color: hsl(0, 100%, 40%);">-; Maximum time to wait to CURL certificates</span><br><span style="color: hsl(0, 100%, 40%);">-;curl_timeout</span><br><span style="color: hsl(120, 100%, 40%);">+; Maximum time (in seconds) to wait to CURL certificates</span><br><span style="color: hsl(120, 100%, 40%);">+;curl_timeout=2</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; Amount of time (in seconds) a signature is valid for</span><br><span style="color: hsl(120, 100%, 40%);">+;signature_timeout=15</span><br><span> ;</span><br><span> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span><br><span> ;</span><br><span>@@ -48,6 +51,9 @@</span><br><span> ; URL to the public key</span><br><span> ;public_key_url=http://mycompany.com/alice.pub</span><br><span> ;</span><br><span style="color: hsl(120, 100%, 40%);">+; The caller ID number to match on</span><br><span style="color: hsl(120, 100%, 40%);">+;caller_id_number=1234567</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span> ; Must have an attestation of A, B, or C</span><br><span> ;attestation=C</span><br><span> ;</span><br><span>diff --git a/contrib/ast-db-manage/config/versions/61797b9fced6_add_stir_shaken.py b/contrib/ast-db-manage/config/versions/61797b9fced6_add_stir_shaken.py</span><br><span>new file mode 100644</span><br><span>index 0000000..018937c</span><br><span>--- /dev/null</span><br><span>+++ b/contrib/ast-db-manage/config/versions/61797b9fced6_add_stir_shaken.py</span><br><span>@@ -0,0 +1,31 @@</span><br><span style="color: hsl(120, 100%, 40%);">+"""add stir shaken</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+Revision ID: 61797b9fced6</span><br><span style="color: hsl(120, 100%, 40%);">+Revises: fbb7766f17bc</span><br><span style="color: hsl(120, 100%, 40%);">+Create Date: 2020-06-29 11:52:59.946929</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+"""</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# revision identifiers, used by Alembic.</span><br><span style="color: hsl(120, 100%, 40%);">+revision = '61797b9fced6'</span><br><span style="color: hsl(120, 100%, 40%);">+down_revision = 'b80485ff4dd0'</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+from alembic import op</span><br><span style="color: hsl(120, 100%, 40%);">+import sqlalchemy as sa</span><br><span style="color: hsl(120, 100%, 40%);">+from sqlalchemy.dialects.postgresql import ENUM</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+YESNO_NAME = 'yesno_values'</span><br><span style="color: hsl(120, 100%, 40%);">+YESNO_VALUES = ['yes', 'no']</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+AST_BOOL_NAME = 'ast_bool_values'</span><br><span style="color: hsl(120, 100%, 40%);">+AST_BOOL_VALUES = [ '0', '1',</span><br><span style="color: hsl(120, 100%, 40%);">+                    'off', 'on',</span><br><span style="color: hsl(120, 100%, 40%);">+                    'false', 'true',</span><br><span style="color: hsl(120, 100%, 40%);">+                    'no', 'yes' ]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def upgrade():</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_bool_values = ENUM(*AST_BOOL_VALUES, name=AST_BOOL_NAME, create_type=False)</span><br><span style="color: hsl(120, 100%, 40%);">+    op.add_column('ps_endpoints', sa.Column('stir_shaken', ast_bool_values))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def downgrade():</span><br><span style="color: hsl(120, 100%, 40%);">+    op.drop_column('ps_endpoints', 'stir_shaken')</span><br><span>diff --git a/doc/CHANGES-staging/stir_shaken.txt b/doc/CHANGES-staging/stir_shaken.txt</span><br><span>new file mode 100644</span><br><span>index 0000000..3ad1784</span><br><span>--- /dev/null</span><br><span>+++ b/doc/CHANGES-staging/stir_shaken.txt</span><br><span>@@ -0,0 +1,20 @@</span><br><span style="color: hsl(120, 100%, 40%);">+Subject: STIR/SHAKEN</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+STIR/SHAKEN support has been added to Asterisk. Configuration is done in</span><br><span style="color: hsl(120, 100%, 40%);">+stir_shaken.conf. There is a sample configuration file to help you get</span><br><span style="color: hsl(120, 100%, 40%);">+started (asterisk/configs/samples/stir_shaken.conf.sample). Once that's</span><br><span style="color: hsl(120, 100%, 40%);">+set up, you can enable STIR/SHAKEN on any endpoint by setting stir_shaken</span><br><span style="color: hsl(120, 100%, 40%);">+to yes on the endpoint configuration object. This will add an Identity</span><br><span style="color: hsl(120, 100%, 40%);">+header on outgoing INVITEs, and check for an Identity header on incoming</span><br><span style="color: hsl(120, 100%, 40%);">+INVITEs. This option has been added to Alembic as well.</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The information received on an incoming INVITE can be checked using the</span><br><span style="color: hsl(120, 100%, 40%);">+STIR_SHAKEN dialplan function. There are two variations:</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+STIR_SHAKEN(count)</span><br><span style="color: hsl(120, 100%, 40%);">+STIR_SHAKEN(0, verify_result)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+The first variation will tell you how many STIR/SHAKEN results are on the</span><br><span style="color: hsl(120, 100%, 40%);">+channel. The second fetches information for a specific result. The first</span><br><span style="color: hsl(120, 100%, 40%);">+parameter is the index, followed by what information you want to retrieve.</span><br><span style="color: hsl(120, 100%, 40%);">+The available options are 'verify_result', 'identity', and 'attestation'.</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index 0ca29ff..eaa9b21 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -908,6 +908,8 @@</span><br><span>      unsigned int suppress_q850_reason_headers;</span><br><span>   /*! Ignore 183 if no SDP is present */</span><br><span>       unsigned int ignore_183_without_sdp;</span><br><span style="color: hsl(120, 100%, 40%);">+  /*! Enable STIR/SHAKEN support on this endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int stir_shaken;</span><br><span> };</span><br><span> </span><br><span> /*! URI parameter for symmetric transport */</span><br><span>diff --git a/res/res_pjsip.c b/res/res_pjsip.c</span><br><span>index 847a14c..bb77e54 100644</span><br><span>--- a/res/res_pjsip.c</span><br><span>+++ b/res/res_pjsip.c</span><br><span>@@ -1458,6 +1458,14 @@</span><br><span>                                                being forwarded.</para></span><br><span>                                        </description></span><br><span>                                 </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+                         <configOption name="stir_shaken" default="no"></span><br><span style="color: hsl(120, 100%, 40%);">+                                      <synopsis>Enable STIR/SHAKEN support on this endpoint</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+                                  <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+                                               Enable STIR/SHAKEN support on this endpoint. On incoming INVITEs,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             the Identity header will be checked for validity. On outgoing</span><br><span style="color: hsl(120, 100%, 40%);">+                                         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>                        </configObject></span><br><span>                        <configObject name="auth"></span><br><span>                           <synopsis>Authentication type</synopsis></span><br><span>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c</span><br><span>index e3eab8a..89ae3e1 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -2140,6 +2140,7 @@</span><br><span>        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outgoing_answer_codec_prefs",</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 style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "stir_shaken", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, stir_shaken));</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_stir_shaken.c b/res/res_pjsip_stir_shaken.c</span><br><span>index 3620579..60dfdc4 100644</span><br><span>--- a/res/res_pjsip_stir_shaken.c</span><br><span>+++ b/res/res_pjsip_stir_shaken.c</span><br><span>@@ -95,6 +95,11 @@</span><br><span>       long int timestamp;</span><br><span>  struct timeval now = ast_tvnow();</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_debug(3, "Ignoring STIR/SHAKEN timestamp\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  json = ast_json_load_string(json_str, NULL);</span><br><span>         timestamp = ast_json_integer_get(ast_json_object_get(json, "iat"));</span><br><span> </span><br><span>@@ -131,6 +136,10 @@</span><br><span>     int mismatch = 0;</span><br><span>    struct ast_stir_shaken_payload *ss_payload;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       if (!session->endpoint->stir_shaken) {</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>  identity_hdr_val = ast_sip_rdata_get_header_value(rdata, identity_str);</span><br><span>      if (ast_strlen_zero(identity_hdr_val)) {</span><br><span>             ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_NOT_PRESENT);</span><br><span>@@ -278,6 +287,10 @@</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(120, 100%, 40%);">+       if (!session->endpoint->stir_shaken) {</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>  if (ast_strlen_zero(session->id.number.str) && session->id.number.valid) {</span><br><span>             return;</span><br><span>      }</span><br><span>diff --git a/res/res_stir_shaken.c b/res/res_stir_shaken.c</span><br><span>index 632fd1b..7a141f7 100644</span><br><span>--- a/res/res_stir_shaken.c</span><br><span>+++ b/res/res_stir_shaken.c</span><br><span>@@ -153,6 +153,11 @@</span><br><span> /* The maximum length for path storage */</span><br><span> #define MAX_PATH_LEN 256</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* The default amount of time (in seconds) to use for certificate expiration</span><br><span style="color: hsl(120, 100%, 40%);">+ * if no cache data is available</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#define EXPIRATION_BUFFER 15</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_stir_shaken_payload {</span><br><span>      /*! The JWT header */</span><br><span>        struct ast_json *header;</span><br><span>@@ -381,6 +386,10 @@</span><br><span>              }</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         actual_expires.tv_sec += EXPIRATION_BUFFER;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec);</span><br><span> </span><br><span>  ast_db_put(hash, "expiration", time_buf);</span><br><span>@@ -1133,6 +1142,8 @@</span><br><span>  struct stir_shaken_datastore *ss_datastore;</span><br><span>  struct ast_datastore *datastore;</span><br><span>     char *parse;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *first;</span><br><span style="color: hsl(120, 100%, 40%);">+  char *second;</span><br><span>        unsigned int target_index, current_index = 0;</span><br><span>        AST_DECLARE_APP_ARGS(args,</span><br><span>           AST_APP_ARG(first_param);</span><br><span>@@ -1153,17 +1164,20 @@</span><br><span> </span><br><span>      AST_STANDARD_APP_ARGS(args, parse);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (ast_strlen_zero(args.first_param)) {</span><br><span style="color: hsl(120, 100%, 40%);">+      first = ast_strip(args.first_param);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (ast_strlen_zero(first)) {</span><br><span>                ast_log(LOG_ERROR, "An argument must be passed to %s\n", function);</span><br><span>                return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ second = ast_strip(args.second_param);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* Check if we are only looking for the number of STIR/SHAKEN verification results */</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!strcasecmp(args.first_param, "count")) {</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!strcasecmp(first, "count")) {</span><br><span> </span><br><span>             size_t count = 0;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           if (!ast_strlen_zero(args.second_param)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!ast_strlen_zero(second)) {</span><br><span>                      ast_log(LOG_ERROR, "%s only takes 1 paramater for 'count'\n", function);</span><br><span>                   return -1;</span><br><span>           }</span><br><span>@@ -1184,15 +1198,15 @@</span><br><span>  /* If we aren't doing a count, then there should be two parameters. The field</span><br><span>     * we are searching for will be the second parameter. The index is the first.</span><br><span>         */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (ast_strlen_zero(args.second_param)) {</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_strlen_zero(second)) {</span><br><span>               ast_log(LOG_ERROR, "Retrieving a value using %s requires two paramaters (index, value) "</span><br><span style="color: hsl(0, 100%, 40%);">-                      "- only index was given (%s)\n", function, args.second_param);</span><br><span style="color: hsl(120, 100%, 40%);">+                      "- only index was given (%s)\n", function, second);</span><br><span>                return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (ast_str_to_uint(args.first_param, &target_index)) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_str_to_uint(first, &target_index)) {</span><br><span>             ast_log(LOG_ERROR, "Failed to convert index %s to integer for function %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                 args.first_param, function);</span><br><span style="color: hsl(120, 100%, 40%);">+                  first, function);</span><br><span>            return -1;</span><br><span>   }</span><br><span> </span><br><span>@@ -1211,19 +1225,19 @@</span><br><span>      }</span><br><span>    ast_channel_unlock(chan);</span><br><span>    if (current_index != target_index || !datastore) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_WARNING, "No STIR/SHAKEN results for index '%s'\n", args.first_param);</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_WARNING, "No STIR/SHAKEN results for index '%s'\n", first);</span><br><span>            return -1;</span><br><span>   }</span><br><span>    ss_datastore = datastore->data;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  if (!strcasecmp(args.second_param, "identity")) {</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!strcasecmp(second, "identity")) {</span><br><span>             ast_copy_string(buf, ss_datastore->identity, len);</span><br><span style="color: hsl(0, 100%, 40%);">-   } else if (!strcasecmp(args.second_param, "attestation")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(second, "attestation")) {</span><br><span>           ast_copy_string(buf, ss_datastore->attestation, len);</span><br><span style="color: hsl(0, 100%, 40%);">-        } else if (!strcasecmp(args.second_param, "verify_result")) {</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (!strcasecmp(second, "verify_result")) {</span><br><span>                 ast_copy_string(buf, stir_shaken_verification_result_to_string(ss_datastore->verify_result), len);</span><br><span>        } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                ast_log(LOG_ERROR, "No such value '%s' for %s\n", args.second_param, function);</span><br><span style="color: hsl(120, 100%, 40%);">+             ast_log(LOG_ERROR, "No such value '%s' for %s\n", second, function);</span><br><span>               return -1;</span><br><span>   }</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14574">change 14574</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/+/14574"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I43d67f1489b8c1c5729ed3ca8d71e35ddf438df1 </div>
<div style="display:none"> Gerrit-Change-Number: 14574 </div>
<div style="display:none"> Gerrit-PatchSet: 10 </div>
<div style="display:none"> Gerrit-Owner: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Friendly Automation </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Joshua Colp <jcolp@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Sean Bright <sean.bright@gmail.com> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>