mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	res_stir_shaken: Allow sending Identity headers for unknown TNs
Added a new option "unknown_tn_attest_level" to allow Identity headers to be sent when a callerid TN isn't explicitly configured in stir_shaken.conf. Since there's no TN object, a private_key_file and public_cert_url must be configured in the attestation or profile objects. Since "unknown_tn_attest_level" uses the same enum as attest_level, some of the sorcery macros had to be refactored to allow sharing the enum and to/from string conversion functions. Also fixed a memory leak in crypto_utils:pem_file_cb(). Resolves: #921 UserNote: You can now set the "unknown_tn_attest_level" option in the attestation and/or profile objects in stir_shaken.conf to enable sending Identity headers for callerid TNs not explicitly configured.
This commit is contained in:
		| @@ -99,6 +99,20 @@ One of "A", "B", "C" | |||||||
|  |  | ||||||
| Default: none | Default: none | ||||||
|  |  | ||||||
|  | -- unknown_tn_attest_level -------------------------------------------- | ||||||
|  | Attestation level to use for unknown TNs. | ||||||
|  | One of "A", "B", "C" | ||||||
|  |  | ||||||
|  | Normally if a callerid TN isn't configured in stir_shaken.conf | ||||||
|  | no Identity header will be created. If this option is set, | ||||||
|  | however, an Identity header will be sent using this | ||||||
|  | attestation level.  Since there's no TN object, you must | ||||||
|  | ensure that a private_key_file and public_cert_url are | ||||||
|  | configured in the attestation or profile objects for | ||||||
|  | this to work. | ||||||
|  |  | ||||||
|  | Default: none | ||||||
|  |  | ||||||
| -- send_mky ----------------------------------------------------------- | -- send_mky ----------------------------------------------------------- | ||||||
| If set and an outgoing call uses DTLS, an "mky" Media Key grant will | If set and an outgoing call uses DTLS, an "mky" Media Key grant will | ||||||
| be added to the Identity header.  Although RFC8224/8225 require this, | be added to the Identity header.  Although RFC8224/8225 require this, | ||||||
| @@ -116,6 +130,7 @@ Example "attestation" object: | |||||||
| ;private_key_file = /var/lib/asterisk/keys/stir_shaken/tns/multi-tns-key.pem | ;private_key_file = /var/lib/asterisk/keys/stir_shaken/tns/multi-tns-key.pem | ||||||
| ;public_cert_url = https://example.com/tncerts/multi-tns-cert.pem | ;public_cert_url = https://example.com/tncerts/multi-tns-cert.pem | ||||||
| ;attest_level = C | ;attest_level = C | ||||||
|  | ;unknown_tn_attest_level = C | ||||||
|  |  | ||||||
| ;-- | ;-- | ||||||
| ======================================================================= | ======================================================================= | ||||||
|   | |||||||
| @@ -15,9 +15,13 @@ | |||||||
|  * the GNU General Public License Version 2. See the LICENSE file |  * the GNU General Public License Version 2. See the LICENSE file | ||||||
|  * at the top of the source tree. |  * at the top of the source tree. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | #define _TRACE_PREFIX_ "ac",__LINE__, "" | ||||||
|  |  | ||||||
| #include "asterisk.h" | #include "asterisk.h" | ||||||
|  |  | ||||||
| #include "asterisk/cli.h" | #include "asterisk/cli.h" | ||||||
|  | #include "asterisk/logger.h" | ||||||
| #include "asterisk/sorcery.h" | #include "asterisk/sorcery.h" | ||||||
| #include "asterisk/paths.h" | #include "asterisk/paths.h" | ||||||
|  |  | ||||||
| @@ -31,6 +35,7 @@ | |||||||
| #define DEFAULT_private_key_file NULL | #define DEFAULT_private_key_file NULL | ||||||
| #define DEFAULT_public_cert_url NULL | #define DEFAULT_public_cert_url NULL | ||||||
| #define DEFAULT_attest_level attest_level_NOT_SET | #define DEFAULT_attest_level attest_level_NOT_SET | ||||||
|  | #define DEFAULT_unknown_tn_attest_level attest_level_NOT_SET | ||||||
| #define DEFAULT_send_mky send_mky_NO | #define DEFAULT_send_mky send_mky_NO | ||||||
|  |  | ||||||
| static struct attestation_cfg *empty_cfg = NULL; | static struct attestation_cfg *empty_cfg = NULL; | ||||||
| @@ -57,6 +62,9 @@ int as_is_config_loaded(void) | |||||||
|  |  | ||||||
| generate_acfg_common_sorcery_handlers(attestation_cfg); | generate_acfg_common_sorcery_handlers(attestation_cfg); | ||||||
|  |  | ||||||
|  | generate_sorcery_enum_from_str_ex(attestation_cfg,,unknown_tn_attest_level, attest_level, UNKNOWN); | ||||||
|  | generate_sorcery_enum_to_str_ex(attestation_cfg,,unknown_tn_attest_level, attest_level); | ||||||
|  |  | ||||||
| void acfg_cleanup(struct attestation_cfg_common *acfg_common) | void acfg_cleanup(struct attestation_cfg_common *acfg_common) | ||||||
| { | { | ||||||
| 	if (!acfg_common) { | 	if (!acfg_common) { | ||||||
| @@ -309,6 +317,9 @@ int as_config_load(void) | |||||||
| 		DEFAULT_global_disable ? "yes" : "no", | 		DEFAULT_global_disable ? "yes" : "no", | ||||||
| 		OPT_YESNO_T, 1, FLDSET(struct attestation_cfg, global_disable)); | 		OPT_YESNO_T, 1, FLDSET(struct attestation_cfg, global_disable)); | ||||||
|  |  | ||||||
|  | 	enum_option_register_ex(sorcery, CONFIG_TYPE, unknown_tn_attest_level, | ||||||
|  | 		unknown_tn_attest_level, attest_level,); | ||||||
|  |  | ||||||
| 	register_common_attestation_fields(sorcery, attestation_cfg, CONFIG_TYPE,); | 	register_common_attestation_fields(sorcery, attestation_cfg, CONFIG_TYPE,); | ||||||
|  |  | ||||||
| 	ast_sorcery_load_object(sorcery, CONFIG_TYPE); | 	ast_sorcery_load_object(sorcery, CONFIG_TYPE); | ||||||
|   | |||||||
| @@ -116,6 +116,12 @@ generate_enum_string_prototypes(attest_level, | |||||||
| 	attest_level_C, | 	attest_level_C, | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * unknown_tn_attest_level uses the same enum as attest_level. | ||||||
|  |  */ | ||||||
|  | enum attest_level_enum unknown_tn_attest_level_from_str(const char *value); | ||||||
|  | const char *unknown_tn_attest_level_to_str(enum attest_level_enum value); | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * enum stir_shaken_failure_action is defined in |  * enum stir_shaken_failure_action is defined in | ||||||
|  * res_stir_shaken.h because res_pjsip_stir_shaken needs it |  * res_stir_shaken.h because res_pjsip_stir_shaken needs it | ||||||
| @@ -136,20 +142,23 @@ const char *stir_shaken_failure_action_to_str( | |||||||
|  * are _to_str and _from_str functions defined elsewhere. |  * are _to_str and _from_str functions defined elsewhere. | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| #define generate_sorcery_enum_to_str(__struct, __substruct, __lc_param) \ | #define generate_sorcery_enum_to_str_ex(__struct, __substruct, __lc_param, __base_enum) \ | ||||||
| static int sorcery_ ## __lc_param ## _to_str(const void *obj, const intptr_t *args, char **buf) \ | static int sorcery_ ## __lc_param ## _to_str(const void *obj, const intptr_t *args, char **buf) \ | ||||||
| { \ | { \ | ||||||
| 	const struct __struct *cfg = obj; \ | 	const struct __struct *cfg = obj; \ | ||||||
| 	*buf = ast_strdup(__lc_param ## _to_str(cfg->__substruct __lc_param)); \ | 	*buf = ast_strdup(__base_enum ## _to_str(cfg->__substruct __lc_param)); \ | ||||||
| 	return *buf ? 0 : -1; \ | 	return *buf ? 0 : -1; \ | ||||||
| } | } | ||||||
|  |  | ||||||
| #define generate_sorcery_enum_from_str_ex(__struct, __substruct, __lc_param, __unknown) \ | #define generate_sorcery_enum_to_str(__struct, __substruct, __lc_param) \ | ||||||
|  | 	generate_sorcery_enum_to_str_ex(__struct, __substruct, __lc_param, __lc_param) | ||||||
|  |  | ||||||
|  | #define generate_sorcery_enum_from_str_ex(__struct, __substruct, __lc_param, __base_enum, __unknown) \ | ||||||
| static int sorcery_ ## __lc_param ## _from_str(const struct aco_option *opt, struct ast_variable *var, void *obj) \ | static int sorcery_ ## __lc_param ## _from_str(const struct aco_option *opt, struct ast_variable *var, void *obj) \ | ||||||
| { \ | { \ | ||||||
| 	struct __struct *cfg = obj; \ | 	struct __struct *cfg = obj; \ | ||||||
| 	cfg->__substruct __lc_param = __lc_param ## _from_str (var->value); \ | 	cfg->__substruct __lc_param = __base_enum ## _from_str (var->value); \ | ||||||
| 	if (cfg->__substruct __lc_param == __unknown) { \ | 	if (cfg->__substruct __lc_param == __base_enum ## _ ## __unknown) { \ | ||||||
| 		ast_log(LOG_WARNING, "Unknown value '%s' specified for %s\n", \ | 		ast_log(LOG_WARNING, "Unknown value '%s' specified for %s\n", \ | ||||||
| 			var->value, var->name); \ | 			var->value, var->name); \ | ||||||
| 		return -1; \ | 		return -1; \ | ||||||
| @@ -158,7 +167,7 @@ static int sorcery_ ## __lc_param ## _from_str(const struct aco_option *opt, str | |||||||
| } | } | ||||||
|  |  | ||||||
| #define generate_sorcery_enum_from_str(__struct, __substruct, __lc_param, __unknown) \ | #define generate_sorcery_enum_from_str(__struct, __substruct, __lc_param, __unknown) \ | ||||||
| 	generate_sorcery_enum_from_str_ex(__struct, __substruct, __lc_param, __lc_param ## _ ## __unknown) \ | 	generate_sorcery_enum_from_str_ex(__struct, __substruct, __lc_param, __lc_param, __unknown) \ | ||||||
|  |  | ||||||
|  |  | ||||||
| #define generate_sorcery_acl_to_str(__struct, __lc_param) \ | #define generate_sorcery_acl_to_str(__struct, __lc_param) \ | ||||||
| @@ -263,14 +272,18 @@ struct ast_acl_list *get_default_acl_list(void); | |||||||
|  * Copy an enum from the source to the dest only if the source is |  * Copy an enum from the source to the dest only if the source is | ||||||
|  * neither NOT_SET nor UNKNOWN |  * neither NOT_SET nor UNKNOWN | ||||||
|  */ |  */ | ||||||
| #define cfg_enum_copy(__cfg_dst, __cfg_src, __field) \ | #define cfg_enum_copy_ex(__cfg_dst, __cfg_src, __field, __not_set, __unknown) \ | ||||||
| ({ \ | ({ \ | ||||||
| 	if (__cfg_src->__field != __field ## _NOT_SET \ | 	if (__cfg_src->__field != __not_set \ | ||||||
| 		&& __cfg_src->__field != __field ## _UNKNOWN) { \ | 		&& __cfg_src->__field != __unknown) { \ | ||||||
| 		__cfg_dst->__field = __cfg_src->__field; \ | 		__cfg_dst->__field = __cfg_src->__field; \ | ||||||
| 	} \ | 	} \ | ||||||
| }) | }) | ||||||
|  |  | ||||||
|  | #define cfg_enum_copy(__cfg_dst, __cfg_src, __field) \ | ||||||
|  | 	cfg_enum_copy_ex(__cfg_dst, __cfg_src, __field, __field ## _NOT_SET, __field ## _UNKNOWN) | ||||||
|  |  | ||||||
|  |  | ||||||
| /*! | /*! | ||||||
|  * \brief Attestation Service configuration for stir/shaken |  * \brief Attestation Service configuration for stir/shaken | ||||||
|  * |  * | ||||||
| @@ -314,6 +327,7 @@ struct attestation_cfg { | |||||||
| 	 */ | 	 */ | ||||||
| 	AST_DECLARE_STRING_FIELDS(); | 	AST_DECLARE_STRING_FIELDS(); | ||||||
| 	struct attestation_cfg_common acfg_common; | 	struct attestation_cfg_common acfg_common; | ||||||
|  | 	enum attest_level_enum unknown_tn_attest_level; | ||||||
| 	int global_disable; | 	int global_disable; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -412,6 +426,7 @@ struct profile_cfg { | |||||||
| 	struct attestation_cfg_common acfg_common; | 	struct attestation_cfg_common acfg_common; | ||||||
| 	struct verification_cfg_common vcfg_common; | 	struct verification_cfg_common vcfg_common; | ||||||
| 	enum endpoint_behavior_enum endpoint_behavior; | 	enum endpoint_behavior_enum endpoint_behavior; | ||||||
|  | 	enum attest_level_enum unknown_tn_attest_level; | ||||||
| 	struct profile_cfg *eprofile; | 	struct profile_cfg *eprofile; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -486,13 +501,13 @@ int tn_config_unload(void); | |||||||
| 		__stringify(DEFAULT_ ## name), OPT_UINT_T, 0, \ | 		__stringify(DEFAULT_ ## name), OPT_UINT_T, 0, \ | ||||||
| 		FLDSET(struct object, field)) | 		FLDSET(struct object, field)) | ||||||
|  |  | ||||||
| #define enum_option_register_ex(sorcery, CONFIG_TYPE, name, field, nodoc) \ | #define enum_option_register_ex(sorcery, CONFIG_TYPE, name, field, function_prefix, nodoc) \ | ||||||
| 	ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, \ | 	ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, \ | ||||||
| 		#name, field ## _to_str(DEFAULT_ ## field), \ | 		#name, function_prefix ## _to_str(DEFAULT_ ## field), \ | ||||||
| 		sorcery_ ## field ## _from_str, sorcery_ ## field ## _to_str, NULL, 0, 0) | 		sorcery_ ## field ## _from_str, sorcery_ ## field ## _to_str, NULL, 0, 0) | ||||||
|  |  | ||||||
| #define enum_option_register(sorcery, CONFIG_TYPE, name, nodoc) \ | #define enum_option_register(sorcery, CONFIG_TYPE, name, nodoc) \ | ||||||
| 	enum_option_register_ex(sorcery, CONFIG_TYPE, name, name, nodoc) | 	enum_option_register_ex(sorcery, CONFIG_TYPE, name, name, name, nodoc) | ||||||
|  |  | ||||||
| #define register_common_verification_fields(sorcery, object, CONFIG_TYPE, nodoc) \ | #define register_common_verification_fields(sorcery, object, CONFIG_TYPE, nodoc) \ | ||||||
| ({ \ | ({ \ | ||||||
| @@ -510,7 +525,7 @@ int tn_config_unload(void); | |||||||
| 	uint_option_register(sorcery, CONFIG_TYPE, object, max_cache_entry_age, vcfg_common.max_cache_entry_age, nodoc);\ | 	uint_option_register(sorcery, CONFIG_TYPE, object, max_cache_entry_age, vcfg_common.max_cache_entry_age, nodoc);\ | ||||||
| 	uint_option_register(sorcery, CONFIG_TYPE, object, max_cache_size, vcfg_common.max_cache_size, nodoc);\ | 	uint_option_register(sorcery, CONFIG_TYPE, object, max_cache_size, vcfg_common.max_cache_size, nodoc);\ | ||||||
| \ | \ | ||||||
| 	enum_option_register_ex(sorcery, CONFIG_TYPE, failure_action, stir_shaken_failure_action, nodoc); \ | 	enum_option_register_ex(sorcery, CONFIG_TYPE, failure_action, stir_shaken_failure_action, stir_shaken_failure_action, nodoc); \ | ||||||
| 	enum_option_register(sorcery, CONFIG_TYPE, use_rfc9410_responses, nodoc); \ | 	enum_option_register(sorcery, CONFIG_TYPE, use_rfc9410_responses, nodoc); \ | ||||||
| 	enum_option_register(sorcery, CONFIG_TYPE, \ | 	enum_option_register(sorcery, CONFIG_TYPE, \ | ||||||
| 		relax_x5u_port_scheme_restrictions, nodoc); \ | 		relax_x5u_port_scheme_restrictions, nodoc); \ | ||||||
|   | |||||||
| @@ -498,11 +498,13 @@ static int pem_file_cb(const char *dir_name, const char *filename, void *obj) | |||||||
| 	if (lstat(filename_merged, &statbuf)) { | 	if (lstat(filename_merged, &statbuf)) { | ||||||
| 		printf("Error reading path stats - %s: %s\n", | 		printf("Error reading path stats - %s: %s\n", | ||||||
| 					filename_merged, strerror(errno)); | 					filename_merged, strerror(errno)); | ||||||
|  | 		ast_free(filename_merged); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* We only want the symlinks from the directory */ | 	/* We only want the symlinks from the directory */ | ||||||
| 	if (!S_ISLNK(statbuf.st_mode)) { | 	if (!S_ISLNK(statbuf.st_mode)) { | ||||||
|  | 		ast_free(filename_merged); | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -512,6 +514,7 @@ static int pem_file_cb(const char *dir_name, const char *filename, void *obj) | |||||||
| 		rc = crypto_load_store_from_cert_file(data->store, filename_merged); | 		rc = crypto_load_store_from_cert_file(data->store, filename_merged); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	ast_free(filename_merged); | ||||||
| 	return rc; | 	return rc; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -54,6 +54,7 @@ | |||||||
| #define DEFAULT_private_key_file NULL | #define DEFAULT_private_key_file NULL | ||||||
| #define DEFAULT_public_cert_url NULL | #define DEFAULT_public_cert_url NULL | ||||||
| #define DEFAULT_attest_level attest_level_NOT_SET | #define DEFAULT_attest_level attest_level_NOT_SET | ||||||
|  | #define DEFAULT_unknown_tn_attest_level attest_level_NOT_SET | ||||||
| #define DEFAULT_send_mky send_mky_NOT_SET | #define DEFAULT_send_mky send_mky_NOT_SET | ||||||
|  |  | ||||||
| static void profile_destructor(void *obj) | static void profile_destructor(void *obj) | ||||||
| @@ -167,6 +168,9 @@ static struct profile_cfg *create_effective_profile( | |||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	cfg_enum_copy_ex(eprofile, acfg, unknown_tn_attest_level, | ||||||
|  | 		attest_level_NOT_SET, attest_level_UNKNOWN); | ||||||
|  |  | ||||||
| 	rc = as_copy_cfg_common(id, &eprofile->acfg_common, | 	rc = as_copy_cfg_common(id, &eprofile->acfg_common, | ||||||
| 		&base_profile->acfg_common); | 		&base_profile->acfg_common); | ||||||
| 	if (rc != 0) { | 	if (rc != 0) { | ||||||
| @@ -174,6 +178,10 @@ static struct profile_cfg *create_effective_profile( | |||||||
| 		return NULL; | 		return NULL; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	cfg_enum_copy_ex(eprofile, base_profile, unknown_tn_attest_level, | ||||||
|  | 		attest_level_NOT_SET, attest_level_UNKNOWN); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	eprofile->endpoint_behavior = base_profile->endpoint_behavior; | 	eprofile->endpoint_behavior = base_profile->endpoint_behavior; | ||||||
|  |  | ||||||
| 	if (eprofile->endpoint_behavior == endpoint_behavior_ON) { | 	if (eprofile->endpoint_behavior == endpoint_behavior_ON) { | ||||||
| @@ -252,6 +260,9 @@ generate_vcfg_common_sorcery_handlers(profile_cfg); | |||||||
| generate_sorcery_enum_from_str(profile_cfg, , endpoint_behavior, UNKNOWN); | generate_sorcery_enum_from_str(profile_cfg, , endpoint_behavior, UNKNOWN); | ||||||
| generate_sorcery_enum_to_str(profile_cfg, , endpoint_behavior); | generate_sorcery_enum_to_str(profile_cfg, , endpoint_behavior); | ||||||
|  |  | ||||||
|  | generate_sorcery_enum_from_str_ex(profile_cfg,,unknown_tn_attest_level, attest_level, UNKNOWN); | ||||||
|  | generate_sorcery_enum_to_str_ex(profile_cfg,,unknown_tn_attest_level, attest_level); | ||||||
|  |  | ||||||
| static char *cli_profile_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | static char *cli_profile_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) | ||||||
| { | { | ||||||
| 	struct profile_cfg *profile; | 	struct profile_cfg *profile; | ||||||
| @@ -445,6 +456,9 @@ int profile_load(void) | |||||||
|  |  | ||||||
| 	ast_sorcery_object_field_register_nodoc(sorcery, "eprofile", "type", "", OPT_NOOP_T, 0, 0); | 	ast_sorcery_object_field_register_nodoc(sorcery, "eprofile", "type", "", OPT_NOOP_T, 0, 0); | ||||||
| 	enum_option_register(sorcery, "eprofile", endpoint_behavior, _nodoc); | 	enum_option_register(sorcery, "eprofile", endpoint_behavior, _nodoc); | ||||||
|  | 	enum_option_register_ex(sorcery, "eprofile", unknown_tn_attest_level, | ||||||
|  | 		unknown_tn_attest_level, attest_level,_nodoc); | ||||||
|  |  | ||||||
| 	register_common_verification_fields(sorcery, profile_cfg, "eprofile", _nodoc); | 	register_common_verification_fields(sorcery, profile_cfg, "eprofile", _nodoc); | ||||||
| 	register_common_attestation_fields(sorcery, profile_cfg, "eprofile", _nodoc); | 	register_common_attestation_fields(sorcery, profile_cfg, "eprofile", _nodoc); | ||||||
|  |  | ||||||
| @@ -460,6 +474,9 @@ int profile_load(void) | |||||||
|  |  | ||||||
| 	ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "type", "", OPT_NOOP_T, 0, 0); | 	ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "type", "", OPT_NOOP_T, 0, 0); | ||||||
| 	enum_option_register(sorcery, CONFIG_TYPE, endpoint_behavior,); | 	enum_option_register(sorcery, CONFIG_TYPE, endpoint_behavior,); | ||||||
|  | 	enum_option_register_ex(sorcery, CONFIG_TYPE, unknown_tn_attest_level, | ||||||
|  | 		unknown_tn_attest_level, attest_level,); | ||||||
|  |  | ||||||
| 	register_common_verification_fields(sorcery, profile_cfg, CONFIG_TYPE,); | 	register_common_verification_fields(sorcery, profile_cfg, CONFIG_TYPE,); | ||||||
| 	register_common_attestation_fields(sorcery, profile_cfg, CONFIG_TYPE,); | 	register_common_attestation_fields(sorcery, profile_cfg, CONFIG_TYPE,); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -21,6 +21,18 @@ | |||||||
| 				<configOption name="attest_level"> | 				<configOption name="attest_level"> | ||||||
| 					<synopsis>Attestation level</synopsis> | 					<synopsis>Attestation level</synopsis> | ||||||
| 				</configOption> | 				</configOption> | ||||||
|  | 				<configOption name="unknown_tn_attest_level"> | ||||||
|  | 					<synopsis>Attestation level to use for unknown TNs</synopsis> | ||||||
|  | 					<description><para> | ||||||
|  | 					Normally if a callerid TN isn't configured in stir_shaken.conf | ||||||
|  | 					no Identity header will be created. If this option is set, | ||||||
|  | 					however, an Identity header will be sent using this | ||||||
|  | 					attestation level.  Since there's no TN object, you must | ||||||
|  | 					ensure that a private_key_file and public_cert_url are | ||||||
|  | 					configured in the attestation or profile objects for | ||||||
|  | 					this to work. | ||||||
|  | 					</para></description> | ||||||
|  | 				</configOption> | ||||||
| 				<configOption name="check_tn_cert_public_url" default="false"> | 				<configOption name="check_tn_cert_public_url" default="false"> | ||||||
| 					<synopsis>On load, Retrieve all TN's certificates and validate their dates</synopsis> | 					<synopsis>On load, Retrieve all TN's certificates and validate their dates</synopsis> | ||||||
| 				</configOption> | 				</configOption> | ||||||
| @@ -228,6 +240,7 @@ | |||||||
| 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='private_key_file'])" /> | 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='private_key_file'])" /> | ||||||
| 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='public_cert_url'])" /> | 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='public_cert_url'])" /> | ||||||
| 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='attest_level'])" /> | 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='attest_level'])" /> | ||||||
|  | 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='unknown_tn_attest_level'])" /> | ||||||
| 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='send_mky'])" /> | 				<xi:include xpointer="xpointer(/docs/configInfo[@name='res_stir_shaken']/configFile[@name='stir_shaken.conf']/configObject[@name='attestation']/configOption[@name='send_mky'])" /> | ||||||
| 				<configOption name="endpoint_behavior" default="off"> | 				<configOption name="endpoint_behavior" default="off"> | ||||||
| 					<synopsis>Actions performed when an endpoint references this profile</synopsis> | 					<synopsis>Actions performed when an endpoint references this profile</synopsis> | ||||||
|   | |||||||
| @@ -16,6 +16,8 @@ | |||||||
|  * at the top of the source tree. |  * at the top of the source tree. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | #define _TRACE_PREFIX_ "tc",__LINE__, "" | ||||||
|  |  | ||||||
| #include "asterisk.h" | #include "asterisk.h" | ||||||
|  |  | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
| @@ -108,31 +110,46 @@ static void *etn_alloc(const char *name) | |||||||
|  |  | ||||||
| struct tn_cfg *tn_get_etn(const char *id, struct profile_cfg *eprofile) | struct tn_cfg *tn_get_etn(const char *id, struct profile_cfg *eprofile) | ||||||
| { | { | ||||||
|  | 	const char *profile_id = eprofile ? ast_sorcery_object_get_id(eprofile) : "unknown"; | ||||||
| 	RAII_VAR(struct tn_cfg *, tn, | 	RAII_VAR(struct tn_cfg *, tn, | ||||||
| 		ast_sorcery_retrieve_by_id(get_sorcery(), CONFIG_TYPE, S_OR(id, "")), | 		ast_sorcery_retrieve_by_id(get_sorcery(), CONFIG_TYPE, S_OR(id, "")), | ||||||
| 		ao2_cleanup); | 		ao2_cleanup); | ||||||
| 	struct tn_cfg *etn = etn_alloc(id); | 	RAII_VAR(struct tn_cfg *, etn, etn_alloc(id), ao2_cleanup); | ||||||
|  | 	enum attest_level_enum effective_al = attest_level_NOT_SET; | ||||||
| 	int rc = 0; | 	int rc = 0; | ||||||
|  | 	SCOPE_ENTER(3, "%s:%s: Getting effective TN\n", profile_id, S_OR(id, "")); | ||||||
|  |  | ||||||
| 	if (!tn || !eprofile || !etn) { | 	if (ast_strlen_zero(id) || !eprofile || !etn) { | ||||||
| 		ao2_cleanup(etn); | 		SCOPE_EXIT_RTN_VALUE(NULL, "Missing params\n"); | ||||||
| 		return NULL; | 	} | ||||||
|  |  | ||||||
|  | 	if (!tn) { | ||||||
|  | 		if (eprofile->unknown_tn_attest_level != attest_level_NOT_SET | ||||||
|  | 			&& eprofile->unknown_tn_attest_level != attest_level_UNKNOWN) { | ||||||
|  | 			effective_al = eprofile->unknown_tn_attest_level; | ||||||
|  | 			ast_trace(-1, "%s:%s: TN not found. Using unknown_tn_attest_level %s\n", | ||||||
|  | 				profile_id, id, attest_level_to_str(effective_al)); | ||||||
|  | 		} else { | ||||||
|  | 			SCOPE_EXIT_RTN_VALUE(NULL, "%s:%s: TN not found and unknown_tn_attest_level not set\n", profile_id, id); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Initialize with the acfg from the eprofile first */ | 	/* Initialize with the acfg from the eprofile first */ | ||||||
| 	rc = as_copy_cfg_common(id, &etn->acfg_common, | 	rc = as_copy_cfg_common(id, &etn->acfg_common, | ||||||
| 		&eprofile->acfg_common); | 		&eprofile->acfg_common); | ||||||
| 	if (rc != 0) { | 	if (rc != 0) { | ||||||
| 		ao2_cleanup(etn); | 		SCOPE_EXIT_RTN_VALUE(NULL, "%s:%s: Couldn't copy from eprofile\n", profile_id, id); | ||||||
| 		return NULL; |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Overwrite with anything in the TN itself */ | 	/* Overwrite with anything in the TN itself */ | ||||||
| 	rc = as_copy_cfg_common(id, &etn->acfg_common, | 	if (tn) { | ||||||
| 		&tn->acfg_common); | 		rc = as_copy_cfg_common(id, &etn->acfg_common, | ||||||
| 	if (rc != 0) { | 			&tn->acfg_common); | ||||||
| 		ao2_cleanup(etn); | 		if (rc != 0) { | ||||||
| 		return NULL; | 			SCOPE_EXIT_RTN_VALUE(NULL, "%s:%s: Couldn't copy from tn\n", profile_id, id); | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		etn->acfg_common.attest_level = effective_al; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| @@ -141,7 +158,7 @@ struct tn_cfg *tn_get_etn(const char *id, struct profile_cfg *eprofile) | |||||||
| 	 * the same TN could be used with multiple profiles. | 	 * the same TN could be used with multiple profiles. | ||||||
| 	 */ | 	 */ | ||||||
|  |  | ||||||
| 	return etn; | 	SCOPE_EXIT_RTN_VALUE(ao2_bump(etn), "%s:%s: Done\n", profile_id, id); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int tn_apply(const struct ast_sorcery *sorcery, void *obj) | static int tn_apply(const struct ast_sorcery *sorcery, void *obj) | ||||||
|   | |||||||
| @@ -16,9 +16,12 @@ | |||||||
|  * at the top of the source tree. |  * at the top of the source tree. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  | #define _TRACE_PREFIX_ "vc",__LINE__, "" | ||||||
|  |  | ||||||
| #include "asterisk.h" | #include "asterisk.h" | ||||||
|  |  | ||||||
| #include "asterisk/cli.h" | #include "asterisk/cli.h" | ||||||
|  | #include "asterisk/logger.h" | ||||||
| #include "stir_shaken.h" | #include "stir_shaken.h" | ||||||
|  |  | ||||||
| #define CONFIG_TYPE "verification" | #define CONFIG_TYPE "verification" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user