[Asterisk-code-review] STIR/SHAKEN: Add Date header, dest->tn, and URL checking. (asterisk[master])

Benjamin Keith Ford asteriskteam at digium.com
Thu May 20 14:46:08 CDT 2021


Benjamin Keith Ford has uploaded this change for review. ( https://gerrit.asterisk.org/c/asterisk/+/15900 )


Change subject: STIR/SHAKEN: Add Date header, dest->tn, and URL checking.
......................................................................

STIR/SHAKEN: Add Date header, dest->tn, and URL checking.

STIR/SHAKEN requires a Date header alongside the Identity header, so
that has been added. Still on the outgoing side, we were missing the
dest->tn section of the JSON payload, so that has been added as well.
Moving to the incoming side, URL checking has been added to the public
cert URL to ensure that it starts with http.

https://wiki.asterisk.org/wiki/display/AST/OpenSIPit+2021

Change-Id: Idee5b1b5e45bc3b483b3070e46ce322dca5b3f1c
---
M include/asterisk/res_pjsip.h
M res/res_pjsip.c
M res/res_pjsip_registrar.c
M res/res_pjsip_stir_shaken.c
4 files changed, 84 insertions(+), 20 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/00/15900/1

diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 2020ca8..93d9cab 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -1024,6 +1024,12 @@
 };
 
 /*!
+ * \brief Adds a Date header to the tdata, formatted like:
+ * Date: Wed, 01 Jan 2021 14:53:01 GMT
+ */
+void ast_sip_add_date_header(pjsip_tx_data *tdata);
+
+/*!
  * \brief Register a SIP service in Asterisk.
  *
  * This is more-or-less a wrapper around pjsip_endpt_register_module().
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 775b63f..0abf803 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -3261,6 +3261,18 @@
 /*! Local host address for IPv6 (string form) */
 static char host_ip_ipv6_string[PJ_INET6_ADDRSTRLEN];
 
+void ast_sip_add_date_header(pjsip_tx_data *tdata)
+{
+	char date[256];
+	struct tm tm;
+	time_t t = time(NULL);
+
+	gmtime_r(&t, &tm);
+	strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);
+
+	ast_sip_add_header(tdata, "Date", date);
+}
+
 static int register_service(void *data)
 {
 	pjsip_module **module = data;
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index c4c091f..5fc8c1a 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -250,14 +250,7 @@
 /*! \brief Helper function which adds a Date header to a response */
 static void registrar_add_date_header(pjsip_tx_data *tdata)
 {
-	char date[256];
-	struct tm tm;
-	time_t t = time(NULL);
-
-	gmtime_r(&t, &tm);
-	strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm);
-
-	ast_sip_add_header(tdata, "Date", date);
+	ast_sip_add_date_header(tdata);
 }
 
 static const pj_str_t path_hdr_name = { "Path", 4 };
diff --git a/res/res_pjsip_stir_shaken.c b/res/res_pjsip_stir_shaken.c
index a90b821..df2aaf0 100644
--- a/res/res_pjsip_stir_shaken.c
+++ b/res/res_pjsip_stir_shaken.c
@@ -166,7 +166,7 @@
 		return 0;
 	}
 
-	/* Trim "info=<" to get public key URL */
+	/* Trim "info=<" to get public cert URL */
 	strtok_r(identity_hdr_val, "<", &identity_hdr_val);
 	public_cert_url = strtok_r(identity_hdr_val, ">", &identity_hdr_val);
 	if (ast_strlen_zero(public_cert_url)) {
@@ -174,6 +174,12 @@
 		return 0;
 	}
 
+	/* Make sure the public URL is actually a URL */
+	if (!ast_begins_with(public_cert_url, "http")) {
+		ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
+		return 0;
+	}
+
 	algorithm = strtok_r(identity_hdr_val, ";", &identity_hdr_val);
 	if (ast_strlen_zero(algorithm)) {
 		ast_stir_shaken_add_verification(chan, caller_id, "", AST_STIR_SHAKEN_VERIFY_SIGNATURE_FAILED);
@@ -202,17 +208,20 @@
 	return 0;
 }
 
-static void add_identity_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)
+static int add_identity_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)
 {
 	static const pj_str_t identity_str = { "Identity", 8 };
 	pjsip_generic_string_hdr *identity_hdr;
 	pj_str_t identity_val;
 	pjsip_fromto_hdr *old_identity;
+	pjsip_fromto_hdr *to;
+	pjsip_sip_uri *uri;
 	char *signature;
 	char *public_cert_url;
 	struct ast_json *header;
 	struct ast_json *payload;
 	char *dumped_string;
+	RAII_VAR(char *, dest_tn, NULL, ast_free);
 	RAII_VAR(struct ast_json *, json, NULL, ast_json_free);
 	RAII_VAR(struct ast_stir_shaken_payload *, ss_payload, NULL, ast_stir_shaken_payload_free);
 	RAII_VAR(char *, encoded_header, NULL, ast_free);
@@ -222,21 +231,43 @@
 
 	old_identity = pjsip_msg_find_hdr_by_name(tdata->msg, &identity_str, NULL);
 	if (old_identity) {
-		return;
+		return 0;
 	}
 
+	to = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_TO, NULL);
+	if (!to) {
+		ast_log(LOG_ERROR, "Failed to find To header while adding STIR/SHAKEN Identity header\n");
+		return -1;
+	}
+
+	uri = pjsip_uri_get_uri(to->uri);
+	if (!uri) {
+		ast_log(LOG_ERROR, "Failed to retrieve URI from To header while adding STIR/SHAKEN Identity header\n");
+		return -1;
+	}
+
+	dest_tn = ast_malloc(uri->user.slen + 1);
+	if (!dest_tn) {
+		ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN dest->tn\n");
+		return -1;
+	}
+
+	ast_copy_pj_str(dest_tn, &uri->user, uri->user.slen + 1);
+
 	/* x5u (public key URL), attestation, and origid will be added by ast_stir_shaken_sign */
-	json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}}}", "header", "alg", "ES256", "ppt", "shaken", "typ", "passport",
-		"payload", "orig", "tn", session->id.number.str);
+	json = ast_json_pack("{s: {s: s, s: s, s: s}, s: {s: {s: s}, s: {s: s}}}",
+		"header", "alg", "ES256", "ppt", "shaken", "typ", "passport",
+		"payload", "dest", "tn", dest_tn, "orig", "tn",
+		session->id.number.str);
 	if (!json) {
 		ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN JSON\n");
-		return;
+		return -1;
 	}
 
 	ss_payload = ast_stir_shaken_sign(json);
 	if (!ss_payload) {
 		ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN payload\n");
-		return;
+		return -1;
 	}
 
 	header = ast_json_object_get(json, "header");
@@ -245,7 +276,7 @@
 	ast_json_free(dumped_string);
 	if (!encoded_header) {
 		ast_log(LOG_ERROR, "Failed to encode STIR/SHAKEN header\n");
-		return;
+		return -1;
 	}
 
 	payload = ast_json_object_get(json, "payload");
@@ -254,7 +285,7 @@
 	ast_json_free(dumped_string);
 	if (!encoded_payload) {
 		ast_log(LOG_ERROR, "Failed to encode STIR/SHAKEN payload\n");
-		return;
+		return -1;
 	}
 
 	signature = (char *)ast_stir_shaken_payload_get_signature(ss_payload);
@@ -269,7 +300,7 @@
 	combined_str = ast_calloc(1, combined_size);
 	if (!combined_str) {
 		ast_log(LOG_ERROR, "Failed to allocate memory for STIR/SHAKEN identity string\n");
-		return;
+		return -1;
 	}
 	snprintf(combined_str, combined_size, "%s.%s.%s;info=<%s>alg=%s;ppt=%s", encoded_header,
 		encoded_payload, signature, public_cert_url, STIR_SHAKEN_ENCRYPTION_ALGORITHM, STIR_SHAKEN_PPT);
@@ -278,10 +309,26 @@
 	identity_hdr = pjsip_generic_string_hdr_create(tdata->pool, &identity_str, &identity_val);
 	if (!identity_hdr) {
 		ast_log(LOG_ERROR, "Failed to create STIR/SHAKEN Identity header\n");
-		return;
+		return -1;
 	}
 
 	pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)identity_hdr);
+
+	return 0;
+}
+
+static void add_date_header(const struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+	static const pj_str_t date_str = { "Date", 4 };
+	pjsip_fromto_hdr *old_date;
+
+	old_date = pjsip_msg_find_hdr_by_name(tdata->msg, &date_str, NULL);
+	if (old_date) {
+		ast_debug(3, "Found old STIR/SHAKEN date header, no need to add one\n");
+		return;
+	}
+
+	ast_sip_add_date_header(tdata);
 }
 
 static void stir_shaken_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
@@ -294,7 +341,13 @@
 		return;
 	}
 
-	add_identity_header(session, tdata);
+	/* If adding the Identity header fails for some reason, there's no point
+	 * adding the Date header.
+	 */
+	if ((add_identity_header(session, tdata)) != 0) {
+		return;
+	}
+	add_date_header(session, tdata);
 }
 
 static struct ast_sip_session_supplement stir_shaken_supplement = {

-- 
To view, visit https://gerrit.asterisk.org/c/asterisk/+/15900
To unsubscribe, or for help writing mail filters, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Change-Id: Idee5b1b5e45bc3b483b3070e46ce322dca5b3f1c
Gerrit-Change-Number: 15900
Gerrit-PatchSet: 1
Gerrit-Owner: Benjamin Keith Ford <bford at digium.com>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20210520/8ef7d279/attachment.html>


More information about the asterisk-code-review mailing list