<p>Benjamin Keith Ford has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/15822">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">STIR/SHAKEN: Fix certificate type and storage.<br><br>During OpenSIPit, we found out that the public certificates must be of<br>type X.509. When reading in public keys, we use the corresponding X.509<br>functions now.<br><br>We also discovered that we needed a better naming scheme for the<br>certificates since certificates with the same name would cause issues<br>(overwriting certs, etc.). Now when we download a public certificate, we<br>get the serial number from it and use that as the name of the cached<br>certificate.<br><br>https://wiki.asterisk.org/wiki/display/AST/OpenSIPit+2021<br><br>Change-Id: Ia00b20835f5f976e3603797f2f2fb19672d8114d<br>---<br>M configs/samples/stir_shaken.conf.sample<br>M res/res_stir_shaken.c<br>M res/res_stir_shaken/curl.c<br>M res/res_stir_shaken/curl.h<br>M res/res_stir_shaken/stir_shaken.c<br>M res/res_stir_shaken/stir_shaken.h<br>6 files changed, 203 insertions(+), 45 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/22/15822/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/stir_shaken.conf.sample b/configs/samples/stir_shaken.conf.sample</span><br><span>index 957fd14..d77e37a 100644</span><br><span>--- a/configs/samples/stir_shaken.conf.sample</span><br><span>+++ b/configs/samples/stir_shaken.conf.sample</span><br><span>@@ -35,7 +35,7 @@</span><br><span> ;</span><br><span> ; URL to the public key(s). Must contain variable '${CERTIFICATE}' used for</span><br><span> ; substitution</span><br><span style="color: hsl(0, 100%, 40%);">-;public_key_url=http://mycompany.com/${CERTIFICATE}.pub</span><br><span style="color: hsl(120, 100%, 40%);">+;public_key_url=http://mycompany.com/${CERTIFICATE}.pem</span><br><span> ;</span><br><span> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span><br><span> ;</span><br><span>@@ -45,11 +45,11 @@</span><br><span> ; type must be "certificate"</span><br><span> ;type=certificate</span><br><span> ;</span><br><span style="color: hsl(0, 100%, 40%);">-; File path to a certificate</span><br><span style="color: hsl(0, 100%, 40%);">-;path=/etc/asterisk/stir/alice.crt</span><br><span style="color: hsl(120, 100%, 40%);">+; File path to a certificate. This can be RSA or ECDSA, but eventually only ECDSA will be supported.</span><br><span style="color: hsl(120, 100%, 40%);">+;path=/etc/asterisk/stir/alice.pem</span><br><span> ;</span><br><span style="color: hsl(0, 100%, 40%);">-; URL to the public key</span><br><span style="color: hsl(0, 100%, 40%);">-;public_key_url=http://mycompany.com/alice.pub</span><br><span style="color: hsl(120, 100%, 40%);">+; URL to the public key. Must be of type X509.</span><br><span style="color: hsl(120, 100%, 40%);">+;public_key_url=http://mycompany.com/alice.pem</span><br><span> ;</span><br><span> ; The caller ID number to match on</span><br><span> ;caller_id_number=1234567</span><br><span>diff --git a/res/res_stir_shaken.c b/res/res_stir_shaken.c</span><br><span>index a9f861b..f25eae3 100644</span><br><span>--- a/res/res_stir_shaken.c</span><br><span>+++ b/res/res_stir_shaken.c</span><br><span>@@ -559,29 +559,31 @@</span><br><span>  * \param public_key_url The public key URL</span><br><span>  * \param path The path to download the file to</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval -1 on failure</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval full path filename on success</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static int run_curl(const char *public_key_url, const char *path)</span><br><span style="color: hsl(120, 100%, 40%);">+static char *run_curl(const char *public_key_url, const char *path)</span><br><span> {</span><br><span>     struct curl_cb_data *data;</span><br><span style="color: hsl(120, 100%, 40%);">+    char *filename;</span><br><span> </span><br><span>  data = curl_cb_data_create();</span><br><span>        if (!data) {</span><br><span>                 ast_log(LOG_ERROR, "Failed to create CURL callback data\n");</span><br><span style="color: hsl(0, 100%, 40%);">-          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (curl_public_key(public_key_url, path, data)) {</span><br><span style="color: hsl(120, 100%, 40%);">+    filename = curl_public_key(public_key_url, path, data);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!filename) {</span><br><span>             ast_log(LOG_ERROR, "Could not retrieve public key for '%s'\n", public_key_url);</span><br><span>            curl_cb_data_free(data);</span><br><span style="color: hsl(0, 100%, 40%);">-                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span>         }</span><br><span> </span><br><span>        set_public_key_expiration(public_key_url, data);</span><br><span>     curl_cb_data_free(data);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     return filename;</span><br><span> }</span><br><span> </span><br><span> /*!</span><br><span>@@ -592,29 +594,33 @@</span><br><span>  * \param path The path to download the file to</span><br><span>  * \param curl Flag signaling if we have run CURL or not</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval -1 on failure</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval full path filename on success</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-static int curl_and_check_expiration(const char *public_key_url, const char *path, int *curl)</span><br><span style="color: hsl(120, 100%, 40%);">+static char *curl_and_check_expiration(const char *public_key_url, const char *path, int *curl)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+  char *filename;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    if (curl) {</span><br><span>          ast_log(LOG_ERROR, "Already downloaded public key '%s'\n", path);</span><br><span style="color: hsl(0, 100%, 40%);">-             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (run_curl(public_key_url, path)) {</span><br><span style="color: hsl(0, 100%, 40%);">-           return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    filename = run_curl(public_key_url, path);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!filename) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span>         }</span><br><span> </span><br><span>        if (public_key_is_expired(public_key_url)) {</span><br><span>                 ast_log(LOG_ERROR, "Newly downloaded public key '%s' is expired\n", path);</span><br><span style="color: hsl(0, 100%, 40%);">-            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_free(filename);</span><br><span style="color: hsl(120, 100%, 40%);">+           return NULL;</span><br><span>         }</span><br><span> </span><br><span>        *curl = 1;</span><br><span style="color: hsl(0, 100%, 40%);">-      add_public_key_to_astdb(public_key_url, path);</span><br><span style="color: hsl(120, 100%, 40%);">+        add_public_key_to_astdb(public_key_url, filename);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     return filename;</span><br><span> }</span><br><span> </span><br><span> struct ast_stir_shaken_payload *ast_stir_shaken_verify(const char *header, const char *payload, const char *signature,</span><br><span>@@ -622,9 +628,9 @@</span><br><span> {</span><br><span>       struct ast_stir_shaken_payload *ret_payload;</span><br><span>         EVP_PKEY *public_key;</span><br><span style="color: hsl(0, 100%, 40%);">-   char *filename;</span><br><span>      int curl = 0;</span><br><span>        RAII_VAR(char *, file_path, NULL, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+  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> </span><br><span>@@ -664,6 +670,9 @@</span><br><span>       * The only thing that would be left to do is pull from the configuration.</span><br><span>    */</span><br><span>  file_path = get_path_to_public_key(public_key_url);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (ast_asprintf(&dir_path, "%s/keys/%s", ast_config_AST_DATA_DIR, STIR_SHAKEN_DIR_NAME) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span> </span><br><span>        /* If we don't have an entry in AstDB, CURL from the provided URL */</span><br><span>     if (ast_strlen_zero(file_path)) {</span><br><span>@@ -675,14 +684,9 @@</span><br><span>             /* Go ahead and free file_path, in case anything was allocated above */</span><br><span>              ast_free(file_path);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-                /* Set up the default path */</span><br><span style="color: hsl(0, 100%, 40%);">-           filename = basename(public_key_url);</span><br><span style="color: hsl(0, 100%, 40%);">-            if (ast_asprintf(&file_path, "%s/keys/%s/%s", ast_config_AST_DATA_DIR, STIR_SHAKEN_DIR_NAME, filename) < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>            /* Download to the default path */</span><br><span style="color: hsl(0, 100%, 40%);">-              if (run_curl(public_key_url, file_path)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            file_path = run_curl(public_key_url, dir_path);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!file_path) {</span><br><span>                    return NULL;</span><br><span>                 }</span><br><span> </span><br><span>@@ -703,7 +707,9 @@</span><br><span>          remove_public_key_from_astdb(public_key_url);</span><br><span> </span><br><span>            /* If this fails, then there's nothing we can do */</span><br><span style="color: hsl(0, 100%, 40%);">-         if (curl_and_check_expiration(public_key_url, file_path, &curl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_free(file_path);</span><br><span style="color: hsl(120, 100%, 40%);">+          file_path = curl_and_check_expiration(public_key_url, dir_path, &curl);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!file_path) {</span><br><span>                    return NULL;</span><br><span>                 }</span><br><span>    }</span><br><span>@@ -717,7 +723,9 @@</span><br><span> </span><br><span>          remove_public_key_from_astdb(public_key_url);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-               if (curl_and_check_expiration(public_key_url, file_path, &curl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_free(file_path);</span><br><span style="color: hsl(120, 100%, 40%);">+          file_path = curl_and_check_expiration(public_key_url, dir_path, &curl);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!file_path) {</span><br><span>                    return NULL;</span><br><span>                 }</span><br><span> </span><br><span>diff --git a/res/res_stir_shaken/curl.c b/res/res_stir_shaken/curl.c</span><br><span>index ab29e3d..ab821b0 100644</span><br><span>--- a/res/res_stir_shaken/curl.c</span><br><span>+++ b/res/res_stir_shaken/curl.c</span><br><span>@@ -22,8 +22,10 @@</span><br><span> #include "asterisk/logger.h"</span><br><span> #include "curl.h"</span><br><span> #include "general.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "stir_shaken.h"</span><br><span> </span><br><span> #include <curl/curl.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h></span><br><span> </span><br><span> /* Used to check CURL headers */</span><br><span> #define MAX_HEADER_LENGTH 1023</span><br><span>@@ -148,9 +150,45 @@</span><br><span>     return curl;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int curl_public_key(const char *public_key_url, const char *path, struct curl_cb_data *data)</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Create a temporary file located at path</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note This function assumes path does not end with a '/'</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param path The directory path to create the file in</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param filename Function allocates memory and stores full filename (including path) here</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 file descriptor on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int create_temp_file(const char *path, char **filename)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *template_name = "certXXXXXX";</span><br><span style="color: hsl(120, 100%, 40%);">+   int fd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (ast_asprintf(filename, "%s/%s", path, template_name) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_log(LOG_ERROR, "Failed to set up temporary file path for CURL\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_mkdir(path, 0644);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if ((fd = mkstemp(*filename)) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_NOTICE, "Failed to create temporary file for CURL\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          ast_free(*filename);</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 fd;</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_key_url, const char *path, struct curl_cb_data *data)</span><br><span> {</span><br><span>         FILE *public_key_file;</span><br><span style="color: hsl(120, 100%, 40%);">+        RAII_VAR(char *, tmp_filename, NULL, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+       char *filename;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *serial;</span><br><span style="color: hsl(120, 100%, 40%);">+ int fd;</span><br><span>      long http_code;</span><br><span>      CURL *curl;</span><br><span>  char curl_errbuf[CURL_ERROR_SIZE + 1];</span><br><span>@@ -160,18 +198,32 @@</span><br><span> </span><br><span>   curl_errbuf[CURL_ERROR_SIZE] = '\0';</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-        public_key_file = fopen(path, "wb");</span><br><span style="color: hsl(120, 100%, 40%);">+        /* For now, it's fine to pass in path as is - it shouldn't end with a '/'. However,</span><br><span style="color: hsl(120, 100%, 40%);">+    * if we decide to change how certificates are stored in the future (configurable paths),</span><br><span style="color: hsl(120, 100%, 40%);">+      * then we will need to check to see if path ends with '/', copy everything up to the '/',</span><br><span style="color: hsl(120, 100%, 40%);">+     * and use this new variable for create_temp_file as well as for ast_asprintf below.</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span style="color: hsl(120, 100%, 40%);">+   fd = create_temp_file(path, &tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (fd == -1) {</span><br><span style="color: hsl(120, 100%, 40%);">+               ast_log(LOG_ERROR, "Failed to get temporary file descriptor for CURL\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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   public_key_file = fdopen(fd, "wb");</span><br><span>        if (!public_key_file) {</span><br><span>              ast_log(LOG_ERROR, "Failed to open file '%s' to write public key from '%s': %s (%d)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                       path, public_key_url, strerror(errno), errno);</span><br><span style="color: hsl(0, 100%, 40%);">-          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    tmp_filename, public_key_url, strerror(errno), errno);</span><br><span style="color: hsl(120, 100%, 40%);">+                close(fd);</span><br><span style="color: hsl(120, 100%, 40%);">+            remove(tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span>         }</span><br><span> </span><br><span>        curl = get_curl_instance(data);</span><br><span>      if (!curl) {</span><br><span>                 ast_log(LOG_ERROR, "Failed to set up CURL isntance for '%s'\n", public_key_url);</span><br><span>           fclose(public_key_file);</span><br><span style="color: hsl(0, 100%, 40%);">-                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            remove(tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span>         }</span><br><span> </span><br><span>        curl_easy_setopt(curl, CURLOPT_URL, public_key_url);</span><br><span>@@ -182,7 +234,8 @@</span><br><span>           ast_log(LOG_ERROR, "%s\n", curl_errbuf);</span><br><span>           curl_easy_cleanup(curl);</span><br><span>             fclose(public_key_file);</span><br><span style="color: hsl(0, 100%, 40%);">-                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            remove(tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span>         }</span><br><span> </span><br><span>        curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);</span><br><span>@@ -192,8 +245,33 @@</span><br><span> </span><br><span>  if (http_code / 100 != 2) {</span><br><span>          ast_log(LOG_ERROR, "Failed to retrieve URL '%s': code %ld\n", public_key_url, http_code);</span><br><span style="color: hsl(0, 100%, 40%);">-             return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+            remove(tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     serial = stir_shaken_get_serial_number_x509(tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!serial) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Failed to get serial from cert %s\n", tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+            remove(tmp_filename);</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 (ast_asprintf(&filename, "%s/%s.pem", path, serial) < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Failed to allocate memory for new filename for temporary "</span><br><span style="color: hsl(120, 100%, 40%);">+                      "file %s after CURL\n", tmp_filename);</span><br><span style="color: hsl(120, 100%, 40%);">+              ast_free(serial);</span><br><span style="color: hsl(120, 100%, 40%);">+             remove(tmp_filename);</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%);">+   ast_free(serial);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rename(tmp_filename, filename)) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "Failed to rename temporary file %s to %s after CURL\n", tmp_filename, filename);</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_free(filename);</span><br><span style="color: hsl(120, 100%, 40%);">+           remove(tmp_filename);</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 filename;</span><br><span> }</span><br><span>diff --git a/res/res_stir_shaken/curl.h b/res/res_stir_shaken/curl.h</span><br><span>index d587327..3d6927e 100644</span><br><span>--- a/res/res_stir_shaken/curl.h</span><br><span>+++ b/res/res_stir_shaken/curl.h</span><br><span>@@ -65,9 +65,9 @@</span><br><span>  * \param path The path to download the file to</span><br><span>  * \param data The curl_cb_data</span><br><span>  *</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval 1 on failure</span><br><span style="color: hsl(0, 100%, 40%);">- * \retval 0 on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval full path filename on success</span><br><span>  */</span><br><span style="color: hsl(0, 100%, 40%);">-int curl_public_key(const char *public_key_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_key_url, const char *path, struct curl_cb_data *data);</span><br><span> </span><br><span> #endif /* _STIR_SHAKEN_CURL_H */</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 0b38732..1232e2c 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,6 +90,7 @@</span><br><span> {</span><br><span>        EVP_PKEY *key = NULL;</span><br><span>        FILE *fp;</span><br><span style="color: hsl(120, 100%, 40%);">+     X509 *cert = NULL;</span><br><span> </span><br><span>       fp = fopen(path, "r");</span><br><span>     if (!fp) {</span><br><span>@@ -97,10 +98,20 @@</span><br><span>             return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* If this is to get the private key, the file will be ECDSA or RSA, with the former eventually</span><br><span style="color: hsl(120, 100%, 40%);">+        * replacing the latter. For the public key, the file will be X.509.</span><br><span style="color: hsl(120, 100%, 40%);">+   */</span><br><span>  if (priv) {</span><br><span>          key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);</span><br><span>     } else {</span><br><span style="color: hsl(0, 100%, 40%);">-                key = PEM_read_PUBKEY(fp, NULL, NULL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+          cert = PEM_read_X509(fp, NULL, NULL, NULL);</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 read X.509 cert from file '%s'\n", path);</span><br><span style="color: hsl(120, 100%, 40%);">+                     fclose(fp);</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%);">+             key = X509_get_pubkey(cert);</span><br><span style="color: hsl(120, 100%, 40%);">+          X509_free(cert);</span><br><span>     }</span><br><span> </span><br><span>        if (!key) {</span><br><span>@@ -109,8 +120,9 @@</span><br><span>            return NULL;</span><br><span>         }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (EVP_PKEY_id(key) != EVP_PKEY_EC) {</span><br><span style="color: hsl(0, 100%, 40%);">-          ast_log(LOG_ERROR, "%s key from '%s' must be of type EVP_PKEY_EC\n", priv ? "private" : "public", path);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (EVP_PKEY_id(key) != EVP_PKEY_EC && EVP_PKEY_id(key) != EVP_PKEY_RSA) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "%s key from '%s' must be of type EVP_PKEY_EC or EVP_PKEY_RSA\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                        priv ? "Private" : "Public", path);</span><br><span>              fclose(fp);</span><br><span>          EVP_PKEY_free(key);</span><br><span>          return NULL;</span><br><span>@@ -120,3 +132,53 @@</span><br><span> </span><br><span>      return key;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+char *stir_shaken_get_serial_number_x509(const char *path)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     FILE *fp;</span><br><span style="color: hsl(120, 100%, 40%);">+     X509 *cert;</span><br><span style="color: hsl(120, 100%, 40%);">+   ASN1_INTEGER *serial;</span><br><span style="color: hsl(120, 100%, 40%);">+ BIGNUM *bignum;</span><br><span style="color: hsl(120, 100%, 40%);">+       char *serial_hex;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   fp = fopen(path, "r");</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!fp) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Failed to open file %s\n", path);</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%);">+   cert = PEM_read_X509(fp, NULL, NULL, NULL);</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 read X.509 cert from file %s\n", path);</span><br><span style="color: hsl(120, 100%, 40%);">+               fclose(fp);</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%);">+   serial = X509_get_serialNumber(cert);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!serial) {</span><br><span style="color: hsl(120, 100%, 40%);">+                ast_log(LOG_ERROR, "Failed to get serial number from certificate %s\n", path);</span><br><span style="color: hsl(120, 100%, 40%);">+              X509_free(cert);</span><br><span style="color: hsl(120, 100%, 40%);">+              fclose(fp);</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%);">+   bignum = ASN1_INTEGER_to_BN(serial, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (bignum == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+         ast_log(LOG_ERROR, "Failed to convert serial to bignum\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         X509_free(cert);</span><br><span style="color: hsl(120, 100%, 40%);">+              fclose(fp);</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%);">+   serial_hex = BN_bn2hex(bignum);</span><br><span style="color: hsl(120, 100%, 40%);">+       X509_free(cert);</span><br><span style="color: hsl(120, 100%, 40%);">+      fclose(fp);</span><br><span style="color: hsl(120, 100%, 40%);">+   BN_free(bignum);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!serial_hex) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ast_log(LOG_ERROR, "Failed to convert bignum to hex\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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return serial_hex;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/res/res_stir_shaken/stir_shaken.h b/res/res_stir_shaken/stir_shaken.h</span><br><span>index a49050e..df87a5f 100644</span><br><span>--- a/res/res_stir_shaken/stir_shaken.h</span><br><span>+++ b/res/res_stir_shaken/stir_shaken.h</span><br><span>@@ -52,4 +52,14 @@</span><br><span>  */</span><br><span> EVP_PKEY *stir_shaken_read_key(const char *path, int priv);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Gets the serial number in hex form from the X509 certificate at path</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param path The full path of the X509 certificate</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval serial number on success</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *stir_shaken_get_serial_number_x509(const char *path);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif /* _STIR_SHAKEN_H */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/15822">change 15822</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/+/15822"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16 </div>
<div style="display:none"> Gerrit-Change-Id: Ia00b20835f5f976e3603797f2f2fb19672d8114d </div>
<div style="display:none"> Gerrit-Change-Number: 15822 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>