diff --git a/configs/samples/stir_shaken.conf.sample b/configs/samples/stir_shaken.conf.sample
index 3fe9d7e955..afe4bc024f 100644
--- a/configs/samples/stir_shaken.conf.sample
+++ b/configs/samples/stir_shaken.conf.sample
@@ -330,6 +330,13 @@ considered "failed".
Default: 15
+-- ignore_sip_date_header ---------------------------------------------
+When set to true, will cause the verification process to not consider a
+missing or invalid SIP "Date" header to be a failure. This will make
+the IAT the sole "truth" for Date in the verification process.
+
+Default: no
+
-- max_date_header_age ------------------------------------------------
The sender MUST also send a SIP Date header in their request. If we
receive one that is older than the current time by the number of seconds
diff --git a/res/res_pjsip_stir_shaken.c b/res/res_pjsip_stir_shaken.c
index ea498942eb..bd4e030c63 100644
--- a/res/res_pjsip_stir_shaken.c
+++ b/res/res_pjsip_stir_shaken.c
@@ -277,22 +277,13 @@ static int stir_shaken_incoming_request(struct ast_sip_session *session, pjsip_r
}
date_hdr_val = ast_sip_rdata_get_header_value(rdata, date_hdr_str);
- if (ast_strlen_zero(date_hdr_val)) {
- p_rc = process_failure(ctx, caller_id, session, rdata,
- AST_STIR_SHAKEN_VS_NO_DATE_HDR);
- if (p_rc == PROCESS_FAILURE_CONTINUE) {
- SCOPE_EXIT_RTN_VALUE(0, "%s: No Date header found. Call continuing\n",
+ if (!ast_strlen_zero(date_hdr_val)) {
+ vs_rc = ast_stir_shaken_vs_ctx_add_date_hdr(ctx, date_hdr_val);
+ if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
+ reject_incoming_call(session, 500);
+ SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Unable to add Date header. Call terminated.\n",
session_name);
}
- SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: No Date header found. Call terminated\n",
- session_name);
- }
-
- ast_stir_shaken_vs_ctx_add_date_hdr(ctx, date_hdr_val);
- if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
- reject_incoming_call(session, 500);
- SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_ERROR, "%s: Unable to add Date header. Call terminated.\n",
- session_name);
}
vs_rc = ast_stir_shaken_vs_verify(ctx);
diff --git a/res/res_stir_shaken/common_config.c b/res/res_stir_shaken/common_config.c
index b669762ec3..0cbd9b5035 100644
--- a/res/res_stir_shaken/common_config.c
+++ b/res/res_stir_shaken/common_config.c
@@ -62,6 +62,7 @@ const char *param_name ## _to_str(enum param_name ## _enum value) \
}
generate_bool_handler_functions(use_rfc9410_responses);
+generate_bool_handler_functions(ignore_sip_date_header);
generate_bool_handler_functions(send_mky);
generate_bool_handler_functions(check_tn_cert_public_url);
generate_bool_handler_functions(relax_x5u_port_scheme_restrictions);
diff --git a/res/res_stir_shaken/common_config.h b/res/res_stir_shaken/common_config.h
index e390b548b6..4eb9e5e02f 100644
--- a/res/res_stir_shaken/common_config.h
+++ b/res/res_stir_shaken/common_config.h
@@ -79,6 +79,8 @@ generate_bool_string_prototypes(relax_x5u_path_restrictions);
generate_bool_string_prototypes(load_system_certs);
+generate_bool_string_prototypes(ignore_sip_date_header);
+
generate_bool_string_prototypes(check_tn_cert_public_url);
generate_bool_string_prototypes(send_mky);
@@ -365,7 +367,7 @@ struct verification_cfg_common {
enum relax_x5u_path_restrictions_enum
relax_x5u_path_restrictions;
enum load_system_certs_enum load_system_certs;
-
+ enum ignore_sip_date_header_enum ignore_sip_date_header;
struct ast_acl_list *acl;
struct crypto_cert_store *tcs;
};
@@ -381,6 +383,8 @@ struct verification_cfg_common {
generate_sorcery_enum_to_str(object, vcfg_common.,relax_x5u_path_restrictions); \
generate_sorcery_enum_from_str(object, vcfg_common.,load_system_certs, UNKNOWN); \
generate_sorcery_enum_to_str(object, vcfg_common.,load_system_certs); \
+ generate_sorcery_enum_from_str(object, vcfg_common.,ignore_sip_date_header, UNKNOWN); \
+ generate_sorcery_enum_to_str(object, vcfg_common.,ignore_sip_date_header); \
generate_sorcery_acl_from_str(object, acl, NULL); \
generate_sorcery_acl_to_str(object, acl);
@@ -533,6 +537,7 @@ int tn_config_unload(void);
relax_x5u_path_restrictions, nodoc); \
enum_option_register(sorcery, CONFIG_TYPE, \
load_system_certs, nodoc); \
+ enum_option_register(sorcery, CONFIG_TYPE, ignore_sip_date_header, nodoc); \
\
ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, "x5u_deny", "", sorcery_acl_from_str, NULL, NULL, 0, 0); \
ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, "x5u_permit", "", sorcery_acl_from_str, NULL, NULL, 0, 0); \
diff --git a/res/res_stir_shaken/profile_config.c b/res/res_stir_shaken/profile_config.c
index e3379ebe3b..1a6a76cf96 100644
--- a/res/res_stir_shaken/profile_config.c
+++ b/res/res_stir_shaken/profile_config.c
@@ -49,6 +49,7 @@
#define DEFAULT_relax_x5u_port_scheme_restrictions relax_x5u_port_scheme_restrictions_NOT_SET
#define DEFAULT_relax_x5u_path_restrictions relax_x5u_path_restrictions_NOT_SET
#define DEFAULT_load_system_certs load_system_certs_NOT_SET
+#define DEFAULT_ignore_sip_date_header ignore_sip_date_header_NOT_SET
#define DEFAULT_check_tn_cert_public_url check_tn_cert_public_url_NOT_SET
#define DEFAULT_private_key_file NULL
diff --git a/res/res_stir_shaken/stir_shaken_doc.xml b/res/res_stir_shaken/stir_shaken_doc.xml
index 18af72a5ed..2f648e6f16 100644
--- a/res/res_stir_shaken/stir_shaken_doc.xml
+++ b/res/res_stir_shaken/stir_shaken_doc.xml
@@ -350,6 +350,16 @@
RFC9410 uses the STIR protocol on Reason headers
instead of the SIP protocol
+
+
+ 20.15.0
+ 21.10.0
+ 22.5.0
+
+ When set to true, will cause the verification process to not consider a
+ missing or invalid SIP "Date" header to be a failure. This will make the
+ IAT the sole "truth" for Date in the verification process.
+
18.22.0
@@ -422,6 +432,7 @@
+
diff --git a/res/res_stir_shaken/verification.c b/res/res_stir_shaken/verification.c
index f6609e6236..04f003504e 100644
--- a/res/res_stir_shaken/verification.c
+++ b/res/res_stir_shaken/verification.c
@@ -733,6 +733,15 @@ static enum ast_stir_shaken_vs_response_code check_date_header(
SCOPE_ENTER(3, "%s: Checking date header: '%s'\n",
ctx->tag, ctx->date_hdr);
+ if (ast_strlen_zero(ctx->date_hdr)) {
+ if (ctx->eprofile->vcfg_common.ignore_sip_date_header) {
+ SCOPE_EXIT_RTN_VALUE(AST_STIR_SHAKEN_VS_SUCCESS,
+ "%s: ignore_sip_date_header set\n", ctx->tag);
+ }
+ SCOPE_EXIT_LOG_RTN_VALUE(AST_STIR_SHAKEN_VS_NO_DATE_HDR,
+ LOG_ERROR, "%s: No date header provided\n", ctx->tag);
+ }
+
if (!(remainder = ast_strptime(ctx->date_hdr, "%a, %d %b %Y %T", &date_hdr_tm))) {
SCOPE_EXIT_LOG_RTN_VALUE(AST_STIR_SHAKEN_VS_DATE_HDR_PARSE_FAILURE,
LOG_ERROR, "%s: Failed to parse: '%s'\n",
@@ -853,7 +862,7 @@ static int check_x5u_url(struct ast_stir_shaken_vs_ctx * ctx,
}
if (!ast_strlen_zero(port)) {
if (!ast_strings_equal(port, "443")
- || !ast_strings_equal(port, "8443")) {
+ && !ast_strings_equal(port, "8443")) {
DUMP_X5U_MATCH();
SCOPE_EXIT_LOG_RTN_VALUE(AST_STIR_SHAKEN_VS_INVALID_OR_NO_X5U, LOG_ERROR,
"%s: x5u '%s': port '%s' not port 443 or 8443\n",
@@ -940,8 +949,8 @@ enum ast_stir_shaken_vs_response_code
"%s: No x5u in Identity header\n", ctx->tag);
}
- rc = check_x5u_url(ctx, x5u);
- if (rc != AST_STIR_SHAKEN_VS_SUCCESS) {
+ vs_rc = check_x5u_url(ctx, x5u);
+ if (vs_rc != AST_STIR_SHAKEN_VS_SUCCESS) {
SCOPE_EXIT_RTN_VALUE(vs_rc,
"%s: x5u URL verification failed\n", ctx->tag);
}
@@ -957,8 +966,9 @@ enum ast_stir_shaken_vs_response_code
SCOPE_EXIT_LOG_RTN_VALUE(AST_STIR_SHAKEN_VS_NO_IAT, LOG_ERROR,
"%s: No 'iat' in Identity header\n", ctx->tag);
}
- ast_trace(1, "date_hdr: %zu iat: %zu diff: %zu\n",
- ctx->date_hdr_time, iat, ctx->date_hdr_time - iat);
+ ast_trace(1, "date_hdr: %zu iat: %zu\n",
+ ctx->date_hdr_time, iat);
+
if (iat + ctx->eprofile->vcfg_common.max_iat_age < now_s) {
SCOPE_EXIT_RTN_VALUE(AST_STIR_SHAKEN_VS_IAT_EXPIRED,
"%s: iat %ld older than %u seconds\n", ctx->tag,
diff --git a/res/res_stir_shaken/verification_config.c b/res/res_stir_shaken/verification_config.c
index 81199747c3..b0ed7d4f32 100644
--- a/res/res_stir_shaken/verification_config.c
+++ b/res/res_stir_shaken/verification_config.c
@@ -46,6 +46,7 @@ static char DEFAULT_cert_cache_dir[PATH_MAX];
#define DEFAULT_relax_x5u_port_scheme_restrictions relax_x5u_port_scheme_restrictions_NO
#define DEFAULT_relax_x5u_path_restrictions relax_x5u_path_restrictions_NO
#define DEFAULT_load_system_certs load_system_certs_NO
+#define DEFAULT_ignore_sip_date_header ignore_sip_date_header_NO
static struct verification_cfg *empty_cfg = NULL;
@@ -153,6 +154,7 @@ int vs_copy_cfg_common(const char *id, struct verification_cfg_common *cfg_dst,
cfg_enum_copy(cfg_dst, cfg_src, relax_x5u_port_scheme_restrictions);
cfg_enum_copy(cfg_dst, cfg_src, relax_x5u_path_restrictions);
cfg_enum_copy(cfg_dst, cfg_src, load_system_certs);
+ cfg_enum_copy(cfg_dst, cfg_src, ignore_sip_date_header);
if (cfg_src->acl) {
ast_free_acl_list(cfg_dst->acl);