<p>Benjamin Keith Ford has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/15920">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">STIR/SHAKEN: Add Date header, dest->tn, and URL checking.<br><br>STIR/SHAKEN requires a Date header alongside the Identity header, so<br>that has been added. Still on the outgoing side, we were missing the<br>dest->tn section of the JSON payload, so that has been added as well.<br>Moving to the incoming side, URL checking has been added to the public<br>cert URL to ensure that it starts with http.<br><br>https://wiki.asterisk.org/wiki/display/AST/OpenSIPit+2021<br><br>Change-Id: Idee5b1b5e45bc3b483b3070e46ce322dca5b3f1c<br>---<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip.c<br>M res/res_pjsip_registrar.c<br>M res/res_pjsip_stir_shaken.c<br>4 files changed, 84 insertions(+), 20 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/20/15920/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index a094205..cfb1027 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -948,6 +948,12 @@</span><br><span> };</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Adds a Date header to the tdata, formatted like:</span><br><span style="color: hsl(120, 100%, 40%);">+ * Date: Wed, 01 Jan 2021 14:53:01 GMT</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_add_date_header(pjsip_tx_data *tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Register a SIP service in Asterisk.</span><br><span> *</span><br><span> * This is more-or-less a wrapper around pjsip_endpt_register_module().</span><br><span>diff --git a/res/res_pjsip.c b/res/res_pjsip.c</span><br><span>index 0df0e1d..2004524 100644</span><br><span>--- a/res/res_pjsip.c</span><br><span>+++ b/res/res_pjsip.c</span><br><span>@@ -2944,6 +2944,18 @@</span><br><span> /*! Local host address for IPv6 (string form) */</span><br><span> static char host_ip_ipv6_string[PJ_INET6_ADDRSTRLEN];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_add_date_header(pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ char date[256];</span><br><span style="color: hsl(120, 100%, 40%);">+ struct tm tm;</span><br><span style="color: hsl(120, 100%, 40%);">+ time_t t = time(NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ gmtime_r(&t, &tm);</span><br><span style="color: hsl(120, 100%, 40%);">+ strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_header(tdata, "Date", date);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int register_service(void *data)</span><br><span> {</span><br><span> pjsip_module **module = data;</span><br><span>diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c</span><br><span>index c4c091f..5fc8c1a 100644</span><br><span>--- a/res/res_pjsip_registrar.c</span><br><span>+++ b/res/res_pjsip_registrar.c</span><br><span>@@ -250,14 +250,7 @@</span><br><span> /*! \brief Helper function which adds a Date header to a response */</span><br><span> static void registrar_add_date_header(pjsip_tx_data *tdata)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- char date[256];</span><br><span style="color: hsl(0, 100%, 40%);">- struct tm tm;</span><br><span style="color: hsl(0, 100%, 40%);">- time_t t = time(NULL);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- gmtime_r(&t, &tm);</span><br><span style="color: hsl(0, 100%, 40%);">- strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- ast_sip_add_header(tdata, "Date", date);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_date_header(tdata);</span><br><span> }</span><br><span> </span><br><span> static const pj_str_t path_hdr_name = { "Path", 4 };</span><br><span>diff --git a/res/res_pjsip_stir_shaken.c b/res/res_pjsip_stir_shaken.c</span><br><span>index 5a38073..ea9f35a 100644</span><br><span>--- a/res/res_pjsip_stir_shaken.c</span><br><span>+++ b/res/res_pjsip_stir_shaken.c</span><br><span>@@ -169,7 +169,7 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* Trim "info=<" to get public key URL */</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Trim "info=<" to get public cert URL */</span><br><span> strtok_r(identity_hdr_val, "<", &identity_hdr_val);</span><br><span> public_cert_url = strtok_r(identity_hdr_val, ">", &identity_hdr_val);</span><br><span> if (ast_strlen_zero(public_cert_url)) {</span><br><span>@@ -177,6 +177,12 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Make sure the public URL is actually a URL */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_begins_with(public_cert_url, "http")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);</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> algorithm = strtok_r(identity_hdr_val, ";", &identity_hdr_val);</span><br><span> if (ast_strlen_zero(algorithm)) {</span><br><span> ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);</span><br><span>@@ -205,17 +211,20 @@</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static void add_identity_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_identity_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)</span><br><span> {</span><br><span> static const pj_str_t identity_str = { "Identity", 8 };</span><br><span> pjsip_generic_string_hdr *identity_hdr;</span><br><span> pj_str_t identity_val;</span><br><span> pjsip_fromto_hdr *old_identity;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_fromto_hdr *to;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_sip_uri *uri;</span><br><span> char *signature;</span><br><span> char *public_cert_url;</span><br><span> struct ast_json *header;</span><br><span> struct ast_json *payload;</span><br><span> char *dumped_string;</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(char *, dest_tn, NULL, ast_free);</span><br><span> RAII_VAR(struct ast_json *, json, NULL, ast_json_free);</span><br><span> RAII_VAR(struct ast_stir_shaken_payload *, ss_payload, NULL, ast_stir_shaken_payload_free);</span><br><span> RAII_VAR(char *, encoded_header, NULL, ast_free);</span><br><span>@@ -225,21 +234,43 @@</span><br><span> </span><br><span> old_identity = pjsip_msg_find_hdr_by_name(tdata->msg, &identity_str, NULL);</span><br><span> if (old_identity) {</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ to = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!to) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to find To header while adding STIR/SHAKEN Identity header\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%);">+ uri = pjsip_uri_get_uri(to->uri);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!uri) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to retrieve URI from To header while adding STIR/SHAKEN Identity header\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%);">+ dest_tn = ast_malloc(uri->user.slen + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!dest_tn) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN dest->tn\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_copy_pj_str(dest_tn, &uri->user, uri->user.slen + 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* x5u (public key URL), attestation, and origid will be added by ast_stir_shaken_sign */</span><br><span style="color: hsl(0, 100%, 40%);">- json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg", "ES256", "ppt", "shaken", "typ", "passport",</span><br><span style="color: hsl(0, 100%, 40%);">- "payload", "orig", "tn", session->id.number.str);</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: s}}}",</span><br><span style="color: hsl(120, 100%, 40%);">+ "header", "alg", "ES256", "ppt", "shaken", "typ", "passport",</span><br><span style="color: hsl(120, 100%, 40%);">+ "payload", "dest", "tn", dest_tn, "orig", "tn",</span><br><span style="color: hsl(120, 100%, 40%);">+ session->id.number.str);</span><br><span> if (!json) {</span><br><span> ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN JSON\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> </span><br><span> ss_payload = ast_stir_shaken_sign(json);</span><br><span> if (!ss_payload) {</span><br><span> ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN payload\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> </span><br><span> header = ast_json_object_get(json, "header");</span><br><span>@@ -248,7 +279,7 @@</span><br><span> ast_json_free(dumped_string);</span><br><span> if (!encoded_header) {</span><br><span> ast_log(LOG_ERROR, "Failed to encode STIR/SHAKEN header\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> </span><br><span> payload = ast_json_object_get(json, "payload");</span><br><span>@@ -257,7 +288,7 @@</span><br><span> ast_json_free(dumped_string);</span><br><span> if (!encoded_payload) {</span><br><span> ast_log(LOG_ERROR, "Failed to encode STIR/SHAKEN payload\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> </span><br><span> signature = (char *)ast_stir_shaken_payload_get_signature(ss_payload);</span><br><span>@@ -272,7 +303,7 @@</span><br><span> combined_str = ast_calloc(1, combined_size);</span><br><span> if (!combined_str) {</span><br><span> ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN identity string\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> snprintf(combined_str, combined_size, "%s.%s.%s;info=<%s>alg=%s;ppt=%s", encoded_header,</span><br><span> encoded_payload, signature, public_cert_url, STIR_SHAKEN_ENCRYPTION_ALGORITHM, STIR_SHAKEN_PPT);</span><br><span>@@ -281,10 +312,26 @@</span><br><span> identity_hdr = pjsip_generic_string_hdr_create(tdata->pool, &identity_str, &identity_val);</span><br><span> if (!identity_hdr) {</span><br><span> ast_log(LOG_ERROR, "Failed to create STIR/SHAKEN Identity header\n");</span><br><span style="color: hsl(0, 100%, 40%);">- return;</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> </span><br><span> pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)identity_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void add_date_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t date_str = { "Date", 4 };</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_fromto_hdr *old_date;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ old_date = pjsip_msg_find_hdr_by_name(tdata->msg, &date_str, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (old_date) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(3, "Found old STIR/SHAKEN date header, no need to add one\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_add_date_header(tdata);</span><br><span> }</span><br><span> </span><br><span> static void stir_shaken_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)</span><br><span>@@ -297,7 +344,13 @@</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- add_identity_header(session, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If adding the Identity header fails for some reason, there's no point</span><br><span style="color: hsl(120, 100%, 40%);">+ * adding the Date header.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((add_identity_header(session, tdata)) != 0) {</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%);">+ add_date_header(session, tdata);</span><br><span> }</span><br><span> </span><br><span> static struct ast_sip_session_supplement stir_shaken_supplement = {</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/15920">change 15920</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/+/15920"/><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: Idee5b1b5e45bc3b483b3070e46ce322dca5b3f1c </div>
<div style="display:none"> Gerrit-Change-Number: 15920 </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>