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

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_stir_shaken: Add unit tests for signing and verification.<br><br>Added two unit tests, one for signing and another for verifying.<br>stir_shaken_sign checks to make sure that all the required parameters<br>are passed in and then signs the actual payload. If a signature is<br>produced and a payload returned as a result, the test passes.<br>stir_shaken_verify takes the signature from a signed payload to verify.<br>This unit test also verifies that all the required information is passed<br>in, and then attempts to verify the signature. If verification is<br>successful and a payload is returned, the test passes.<br><br>Change-Id: I9fa43380f861ccf710cd0f6b6c102a517c86ea13<br>---<br>M res/res_stir_shaken.c<br>M res/res_stir_shaken/certificate.c<br>M res/res_stir_shaken/certificate.h<br>M res/res_stir_shaken/stir_shaken.c<br>4 files changed, 459 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/res/res_stir_shaken.c b/res/res_stir_shaken.c</span><br><span>index 90ceb93..86117cd 100644</span><br><span>--- a/res/res_stir_shaken.c</span><br><span>+++ b/res/res_stir_shaken.c</span><br><span>@@ -35,6 +35,7 @@</span><br><span> #include "asterisk/pbx.h"</span><br><span> #include "asterisk/global_datastores.h"</span><br><span> #include "asterisk/app.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/test.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>@@ -1195,6 +1196,348 @@</span><br><span>      .read = stir_shaken_read,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void test_stir_shaken_add_fake_astdb_entry(const char *public_key_url, const char *file_path)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct timeval expires = ast_tvnow();</span><br><span style="color: hsl(120, 100%, 40%);">+ char time_buf[32];</span><br><span style="color: hsl(120, 100%, 40%);">+    char hash[41];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_sha1_hash(hash, public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+  add_public_key_to_astdb(public_key_url, file_path);</span><br><span style="color: hsl(120, 100%, 40%);">+   snprintf(time_buf, sizeof(time_buf), "%30lu", expires.tv_sec + 300);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      ast_db_put(hash, "expiration", time_buf);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create a private or public key certificate</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param file_path The path of the file to create</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param private Set to 0 if public, 1 if private</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval -1 on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int test_stir_shaken_write_temp_key(char *file_path, int private)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      FILE *file;</span><br><span style="color: hsl(120, 100%, 40%);">+   int fd;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *data;</span><br><span style="color: hsl(120, 100%, 40%);">+   char *type = private ? "private" : "public";</span><br><span style="color: hsl(120, 100%, 40%);">+      char *private_data =</span><br><span style="color: hsl(120, 100%, 40%);">+          "-----BEGIN EC PRIVATE KEY-----\n"</span><br><span style="color: hsl(120, 100%, 40%);">+          "MHcCAQEEIFkNGlrmRky2j7wmjGBGoPFBsyEQELmEYN02BiiG508noAoGCCqGSM49\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                "AwEHoUQDQgAECwCaeAYwVG/FAnEnkwaucz6o047iSWq3cJBBUc0n2ZlUDr5VywAz\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                "MZ86EthIqF3CGZjhLHn0xRITXYwfqTtWBw==\n"</span><br><span style="color: hsl(120, 100%, 40%);">+            "-----END EC PRIVATE KEY-----";</span><br><span style="color: hsl(120, 100%, 40%);">+     char *public_data =</span><br><span style="color: hsl(120, 100%, 40%);">+           "-----BEGIN PUBLIC KEY-----\n"</span><br><span style="color: hsl(120, 100%, 40%);">+              "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECwCaeAYwVG/FAnEnkwaucz6o047i\n"</span><br><span style="color: hsl(120, 100%, 40%);">+                "SWq3cJBBUc0n2ZlUDr5VywAzMZ86EthIqF3CGZjhLHn0xRITXYwfqTtWBw==\n"</span><br><span style="color: hsl(120, 100%, 40%);">+            "-----END PUBLIC KEY-----";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       fd = mkstemp(file_path);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (fd < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_log(LOG_ERROR, "Failed to create temp %s file: %s\n", type, strerror(errno));</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%);">+   file = fdopen(fd, "w");</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!file) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Failed to create temp %s key file: %s\n", type, strerror(errno));</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%);">+   data = private ? private_data : public_data;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (fputs(data, file) == EOF) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Failed to write temp %s key file\n", type);</span><br><span style="color: hsl(120, 100%, 40%);">+             fclose(file);</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%);">+   fclose(file);</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%);">+AST_TEST_DEFINE(test_stir_shaken_sign)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     char *caller_id_number = "1234567";</span><br><span style="color: hsl(120, 100%, 40%);">+ char file_path[] = "/tmp/stir_shaken_private.XXXXXX";</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(char *, rm_on_exit, file_path, unlink);</span><br><span style="color: hsl(120, 100%, 40%);">+      RAII_VAR(struct ast_json *, json, NULL, ast_json_free);</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ast_stir_shaken_payload *, payload, NULL, ast_stir_shaken_payload_free);</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 TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "stir_shaken_sign";</span><br><span style="color: hsl(120, 100%, 40%);">+         info->category = "/res/res_stir_shaken/";</span><br><span style="color: hsl(120, 100%, 40%);">+                info->summary = "STIR/SHAKEN sign unit test";</span><br><span style="color: hsl(120, 100%, 40%);">+            info->description =</span><br><span style="color: hsl(120, 100%, 40%);">+                        "Tests signing a JWT with a private key.";</span><br><span style="color: hsl(120, 100%, 40%);">+          return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We only need a private key to sign */</span><br><span style="color: hsl(120, 100%, 40%);">+      test_stir_shaken_write_temp_key(file_path, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+        test_stir_shaken_create_cert(caller_id_number, file_path);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Test missing header section */</span><br><span style="color: hsl(120, 100%, 40%);">+     json = ast_json_pack("{s: {s: {s: s}}}", "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+  payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (missing 'header')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test missing payload section */</span><br><span style="color: hsl(120, 100%, 40%);">+    ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+          STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+                "x5u", "http://testing123");</span><br><span style="color: hsl(120, 100%, 40%);">+      payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (missing 'payload')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test missing alg section */</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "ppt",</span><br><span style="color: hsl(120, 100%, 40%);">+                STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE, "x5u", "http://testing123", "payload",</span><br><span style="color: hsl(120, 100%, 40%);">+              "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+  payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (missing 'alg')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test invalid alg value */</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+          "invalid algorithm", "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+           "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (wrong 'alg')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test missing ppt section */</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+                STIR_SHAKEN_ENCRYPTION_ALGORITHM, "typ", STIR_SHAKEN_TYPE, "x5u", "http://testing123",</span><br><span style="color: hsl(120, 100%, 40%);">+          "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (missing 'ppt')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test invalid ppt value */</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+          STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", "invalid ppt", "typ", STIR_SHAKEN_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+                "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (wrong 'ppt')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test missing typ section */</span><br><span style="color: hsl(120, 100%, 40%);">+        ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+                STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "x5u", "http://testing123",</span><br><span style="color: hsl(120, 100%, 40%);">+           "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (missing 'typ')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test invalid typ value */</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+          STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", "invalid typ",</span><br><span style="color: hsl(120, 100%, 40%);">+         "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (wrong 'typ')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test missing orig section */</span><br><span style="color: hsl(120, 100%, 40%);">+       ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: s}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+               STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+                "x5u", "http://testing123", "payload", "filler", "filler");</span><br><span style="color: hsl(120, 100%, 40%);">+ payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (missing 'orig')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test missing tn section */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: s}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+               STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+                "x5u", "http://testing123", "payload", "orig", "filler");</span><br><span style="color: hsl(120, 100%, 40%);">+   payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Signed an invalid JWT (missing 'tn')\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test valid JWT */</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_json_free(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+          STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+                "x5u", "http://testing123", "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_test_status_update(test, "Failed to sign a valid JWT\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return AST_TEST_PASS;</span><br><span 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_TEST_DEFINE(test_stir_shaken_verify)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       char *caller_id_number = "1234567";</span><br><span style="color: hsl(120, 100%, 40%);">+ char *public_key_url = "http://testing123";</span><br><span style="color: hsl(120, 100%, 40%);">+ char *header = "{\"header\": \"placeholder\"}";</span><br><span style="color: hsl(120, 100%, 40%);">+ char public_path[] = "/tmp/stir_shaken_public.XXXXXX";</span><br><span style="color: hsl(120, 100%, 40%);">+      char private_path[] = "/tmp/stir_shaken_public.XXXXXX";</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(char *, rm_on_exit_public, public_path, unlink);</span><br><span style="color: hsl(120, 100%, 40%);">+     RAII_VAR(char *, rm_on_exit_private, private_path, unlink);</span><br><span style="color: hsl(120, 100%, 40%);">+   RAII_VAR(char *, json_str, NULL, ast_json_free);</span><br><span style="color: hsl(120, 100%, 40%);">+      RAII_VAR(struct ast_json *, json, NULL, ast_json_free);</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ast_stir_shaken_payload *, signed_payload, NULL, ast_stir_shaken_payload_free);</span><br><span style="color: hsl(120, 100%, 40%);">+       RAII_VAR(struct ast_stir_shaken_payload *, returned_payload, NULL, ast_stir_shaken_payload_free);</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 TEST_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               info->name = "stir_shaken_verify";</span><br><span style="color: hsl(120, 100%, 40%);">+               info->category = "/res/res_stir_shaken/";</span><br><span style="color: hsl(120, 100%, 40%);">+                info->summary = "STIR/SHAKEN verify unit test";</span><br><span style="color: hsl(120, 100%, 40%);">+          info->description =</span><br><span style="color: hsl(120, 100%, 40%);">+                        "Tests verifying a signature with a public key";</span><br><span style="color: hsl(120, 100%, 40%);">+            return AST_TEST_NOT_RUN;</span><br><span style="color: hsl(120, 100%, 40%);">+      case TEST_EXECUTE:</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* We need the private key to sign, but we also need the corresponding</span><br><span style="color: hsl(120, 100%, 40%);">+         * public key to verify */</span><br><span style="color: hsl(120, 100%, 40%);">+    test_stir_shaken_write_temp_key(public_path, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      test_stir_shaken_write_temp_key(private_path, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     test_stir_shaken_create_cert(caller_id_number, private_path);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Get the signature */</span><br><span style="color: hsl(120, 100%, 40%);">+       json = ast_json_pack("{s: {s: s, s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg",</span><br><span style="color: hsl(120, 100%, 40%);">+          STIR_SHAKEN_ENCRYPTION_ALGORITHM, "ppt", STIR_SHAKEN_PPT, "typ", STIR_SHAKEN_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+                "x5u", public_key_url, "payload", "orig", "tn", caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+    signed_payload = ast_stir_shaken_sign(json);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!signed_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_test_status_update(test, "Failed to sign a valid JWT\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Get the message to use for verification */</span><br><span style="color: hsl(120, 100%, 40%);">+ json_str = ast_json_dump_string(json);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!json_str) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_test_status_update(test, "Failed to create string from JSON\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test empty header parameter */</span><br><span style="color: hsl(120, 100%, 40%);">+     returned_payload = ast_stir_shaken_verify("", json_str, (const char *)signed_payload->signature,</span><br><span style="color: hsl(120, 100%, 40%);">+         STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (returned_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_test_status_update(test, "Verified a signature with missing 'header'\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test empty payload parameter */</span><br><span style="color: hsl(120, 100%, 40%);">+    returned_payload = ast_stir_shaken_verify(header, "", (const char *)signed_payload->signature,</span><br><span style="color: hsl(120, 100%, 40%);">+           STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (returned_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_test_status_update(test, "Verified a signature with missing 'payload'\n");</span><br><span style="color: hsl(120, 100%, 40%);">+              test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test empty signature parameter */</span><br><span style="color: hsl(120, 100%, 40%);">+  returned_payload = ast_stir_shaken_verify(header, json_str, "",</span><br><span style="color: hsl(120, 100%, 40%);">+             STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (returned_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_test_status_update(test, "Verified a signature with missing 'signature'\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test empty algorithm parameter */</span><br><span style="color: hsl(120, 100%, 40%);">+  returned_payload = ast_stir_shaken_verify(header, json_str, (const char *)signed_payload->signature,</span><br><span style="color: hsl(120, 100%, 40%);">+               "", public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (returned_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_test_status_update(test, "Verified a signature with missing 'algorithm'\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Test empty public key URL */</span><br><span style="color: hsl(120, 100%, 40%);">+       returned_payload = ast_stir_shaken_verify(header, json_str, (const char *)signed_payload->signature,</span><br><span style="color: hsl(120, 100%, 40%);">+               STIR_SHAKEN_ENCRYPTION_ALGORITHM, "");</span><br><span style="color: hsl(120, 100%, 40%);">+      if (returned_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_test_status_update(test, "Verified a signature with missing 'public key URL'\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Trick the function into thinking we've already downloaded the key */</span><br><span style="color: hsl(120, 100%, 40%);">+   test_stir_shaken_add_fake_astdb_entry(public_key_url, public_path);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Verify a valid signature */</span><br><span style="color: hsl(120, 100%, 40%);">+        returned_payload = ast_stir_shaken_verify(header, json_str, (const char *)signed_payload->signature,</span><br><span style="color: hsl(120, 100%, 40%);">+               STIR_SHAKEN_ENCRYPTION_ALGORITHM, public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!returned_payload) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_test_status_update(test, "Failed to verify a valid signature\n");</span><br><span style="color: hsl(120, 100%, 40%);">+               remove_public_key_from_astdb(public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+         test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+              return AST_TEST_FAIL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   remove_public_key_from_astdb(public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       test_stir_shaken_cleanup_cert(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return AST_TEST_PASS;</span><br><span 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 /* TEST_FRAMEWORK */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int reload_module(void)</span><br><span> {</span><br><span>     if (stir_shaken_sorcery) {</span><br><span>@@ -1217,6 +1560,9 @@</span><br><span> </span><br><span>       res |= ast_custom_function_unregister(&stir_shaken_function);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ AST_TEST_UNREGISTER(test_stir_shaken_sign);</span><br><span style="color: hsl(120, 100%, 40%);">+   AST_TEST_UNREGISTER(test_stir_shaken_verify);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      return res;</span><br><span> }</span><br><span> </span><br><span>@@ -1248,6 +1594,9 @@</span><br><span> </span><br><span>     res |= ast_custom_function_register(&stir_shaken_function);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   AST_TEST_REGISTER(test_stir_shaken_sign);</span><br><span style="color: hsl(120, 100%, 40%);">+     AST_TEST_REGISTER(test_stir_shaken_verify);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        return res;</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_stir_shaken/certificate.c b/res/res_stir_shaken/certificate.c</span><br><span>index e889a36..73b5ce1 100644</span><br><span>--- a/res/res_stir_shaken/certificate.c</span><br><span>+++ b/res/res_stir_shaken/certificate.c</span><br><span>@@ -244,6 +244,80 @@</span><br><span>         return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Name for test certificaate */</span><br><span style="color: hsl(120, 100%, 40%);">+#define TEST_CONFIG_NAME "test_stir_shaken_certificate"</span><br><span style="color: hsl(120, 100%, 40%);">+/* The public key URL to use for the test certificate */</span><br><span style="color: hsl(120, 100%, 40%);">+#define TEST_CONFIG_URL "http://testing123"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int test_stir_shaken_cleanup_cert(const char *caller_id_number)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct stir_shaken_certificate *cert;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sorcery *sorcery;</span><br><span style="color: hsl(120, 100%, 40%);">+  int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        sorcery = ast_stir_shaken_sorcery();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        cert = stir_shaken_certificate_get_by_caller_id_number(caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!cert) {</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%);">+   res = ast_sorcery_delete(sorcery, cert);</span><br><span style="color: hsl(120, 100%, 40%);">+      ao2_cleanup(cert);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Failed to delete sorcery object with caller ID "</span><br><span style="color: hsl(120, 100%, 40%);">+                        "'%s'\n", caller_id_number);</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%);">+   res = ast_sorcery_remove_wizard_mapping(sorcery, CONFIG_TYPE, "memory");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return res;</span><br><span 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 test_stir_shaken_create_cert(const char *caller_id_number, const char *file_path)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct stir_shaken_certificate *cert;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sorcery *sorcery;</span><br><span style="color: hsl(120, 100%, 40%);">+  EVP_PKEY *private_key;</span><br><span style="color: hsl(120, 100%, 40%);">+        int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        sorcery = ast_stir_shaken_sorcery();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        res = ast_sorcery_insert_wizard_mapping(sorcery, CONFIG_TYPE, "memory", "testing", 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Failed to insert STIR/SHAKEN test certificate mapping\n");</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%);">+   cert = ast_sorcery_alloc(sorcery, CONFIG_TYPE, TEST_CONFIG_NAME);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!cert) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Failed to allocate test certificate\n");</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_string_field_set(cert, path, file_path);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_string_field_set(cert, public_key_url, TEST_CONFIG_URL);</span><br><span style="color: hsl(120, 100%, 40%);">+  ast_string_field_set(cert, caller_id_number, caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     private_key = stir_shaken_read_key(cert->path, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!private_key) {</span><br><span style="color: hsl(120, 100%, 40%);">+           ast_log(LOG_ERROR, "Failed to read test key from %s\n", cert->path);</span><br><span style="color: hsl(120, 100%, 40%);">+             test_stir_shaken_cleanup_cert(caller_id_number);</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%);">+   cert->private_key = private_key;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_create(sorcery, cert);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return res;</span><br><span 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 /* TEST_FRAMEWORK */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int stir_shaken_certificate_unload(void)</span><br><span> {</span><br><span>     ast_cli_unregister_multiple(stir_shaken_certificate_cli,</span><br><span>diff --git a/res/res_stir_shaken/certificate.h b/res/res_stir_shaken/certificate.h</span><br><span>index fda3bf1..ff30318 100644</span><br><span>--- a/res/res_stir_shaken/certificate.h</span><br><span>+++ b/res/res_stir_shaken/certificate.h</span><br><span>@@ -24,6 +24,14 @@</span><br><span> </span><br><span> struct stir_shaken_certificate;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Get a STIR/SHAKEN certificate by caller ID number</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param callier_id_number The caller ID number</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL if not found</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval The certificate on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span> struct stir_shaken_certificate *stir_shaken_certificate_get_by_caller_id_number(const char *caller_id_number);</span><br><span> </span><br><span> /*!</span><br><span>@@ -46,6 +54,33 @@</span><br><span>  */</span><br><span> EVP_PKEY *stir_shaken_certificate_get_private_key(struct stir_shaken_certificate *cert);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#ifdef TEST_FRAMEWORK</span><br><span 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 Clean up the certificate and mappings set up in test_stir_shaken_init</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param caller_id_number The caller ID of the certificate to clean up</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int test_stir_shaken_cleanup_cert(const char *caller_id_number);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Initialize a test certificate through wizard mappings</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note test_stir_shaken_cleanup should be called when done with this certificate</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param caller_id_number The caller ID of the certificate to create</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param file_path The path to the private key for this certificate</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval non-zero on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int test_stir_shaken_create_cert(const char *caller_id_number, const char *file_path);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* TEST_FRAMEWORK */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span>  * \brief Load time initialization for the stir/shaken 'certificate' configuration</span><br><span>  *</span><br><span>diff --git a/res/res_stir_shaken/stir_shaken.c b/res/res_stir_shaken/stir_shaken.c</span><br><span>index 10caca9..220104a 100644</span><br><span>--- a/res/res_stir_shaken/stir_shaken.c</span><br><span>+++ b/res/res_stir_shaken/stir_shaken.c</span><br><span>@@ -90,7 +90,7 @@</span><br><span> </span><br><span>     fp = fopen(path, "r");</span><br><span>     if (!fp) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ast_log(LOG_ERROR, "Failed to read private key file '%s'\n", path);</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "Failed to read %s key file '%s'\n", priv ? "private" : "public", path);</span><br><span>            return NULL;</span><br><span>         }</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/14408">change 14408</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/+/14408"/><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: I9fa43380f861ccf710cd0f6b6c102a517c86ea13 </div>
<div style="display:none"> Gerrit-Change-Number: 14408 </div>
<div style="display:none"> Gerrit-PatchSet: 5 </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-MessageType: merged </div>