Asterisk - The Open Source Telephony Project GIT-master-97770a9
verification_config.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2023, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19#include "asterisk.h"
20
21#include "asterisk/cli.h"
22#include "stir_shaken.h"
23
24#define CONFIG_TYPE "verification"
25
26#define DEFAULT_global_disable 0
27
28#define DEFAULT_ca_file NULL
29#define DEFAULT_ca_path NULL
30#define DEFAULT_crl_file NULL
31#define DEFAULT_crl_path NULL
32#define DEFAULT_untrusted_cert_file NULL
33#define DEFAULT_untrusted_cert_path NULL
35
36#define DEFAULT_curl_timeout 2
37#define DEFAULT_max_iat_age 15
38#define DEFAULT_max_date_header_age 15
39#define DEFAULT_max_cache_entry_age 3600
40#define DEFAULT_max_cache_size 1000
41#define DEFAULT_stir_shaken_failure_action stir_shaken_failure_action_CONTINUE
42#define DEFAULT_use_rfc9410_responses use_rfc9410_responses_NO
43#define DEFAULT_relax_x5u_port_scheme_restrictions relax_x5u_port_scheme_restrictions_NO
44#define DEFAULT_relax_x5u_path_restrictions relax_x5u_path_restrictions_NO
45#define DEFAULT_load_system_certs load_system_certs_NO
46
48
49#define STIR_SHAKEN_DIR_NAME "stir_shaken"
50
52{
55 if (cfg) {
56 return cfg;
57 }
58
59 return empty_cfg ? ao2_bump(empty_cfg) : NULL;
60}
61
63{
66 ao2_cleanup(cfg);
67
68 return !!cfg;
69}
70
72
74{
75 if (!vcfg_common) {
76 return;
77 }
79 if (vcfg_common->tcs) {
81 }
83}
84
85static void verification_destructor(void *obj)
86{
87 struct verification_cfg *cfg = obj;
90}
91
92static void *verification_alloc(const char *name)
93{
94 struct verification_cfg *cfg;
95
97 if (!cfg) {
98 return NULL;
99 }
100
101 if (ast_string_field_init(cfg, 1024)) {
102 ao2_ref(cfg, -1);
103 return NULL;
104 }
105
106 /*
107 * The memory for vcfg_common actually comes from cfg
108 * due to the weirdness of the STRFLDSET macro used with
109 * sorcery. We just use a token amount of memory in
110 * this call so the initialize doesn't fail.
111 */
112 if (ast_string_field_init(&cfg->vcfg_common, 8)) {
113 ao2_ref(cfg, -1);
114 return NULL;
115 }
116
117 return cfg;
118}
119
120int vs_copy_cfg_common(const char *id, struct verification_cfg_common *cfg_dst,
121 struct verification_cfg_common *cfg_src)
122{
123 int rc = 0;
124
125 if (!cfg_dst || !cfg_src) {
126 return -1;
127 }
128
129 if (!cfg_dst->tcs && cfg_src->tcs) {
130 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, ca_file);
131 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, ca_path);
132 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, crl_file);
133 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, crl_path);
134 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, untrusted_cert_file);
135 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, untrusted_cert_path);
136 ao2_bump(cfg_src->tcs);
137 cfg_dst->tcs = cfg_src->tcs;
138 }
139
140 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, cert_cache_dir);
141
142 cfg_uint_copy(cfg_dst, cfg_src, curl_timeout);
143 cfg_uint_copy(cfg_dst, cfg_src, max_iat_age);
144 cfg_uint_copy(cfg_dst, cfg_src, max_date_header_age);
145 cfg_uint_copy(cfg_dst, cfg_src, max_cache_entry_age);
146 cfg_uint_copy(cfg_dst, cfg_src, max_cache_size);
147
148 cfg_enum_copy(cfg_dst, cfg_src, stir_shaken_failure_action);
149 cfg_enum_copy(cfg_dst, cfg_src, use_rfc9410_responses);
150 cfg_enum_copy(cfg_dst, cfg_src, relax_x5u_port_scheme_restrictions);
151 cfg_enum_copy(cfg_dst, cfg_src, relax_x5u_path_restrictions);
152 cfg_enum_copy(cfg_dst, cfg_src, load_system_certs);
153
154 if (cfg_src->acl) {
155 ast_free_acl_list(cfg_dst->acl);
156 cfg_dst->acl = ast_duplicate_acl_list(cfg_src->acl);
157 }
158
159 return rc;
160}
161
162int vs_check_common_config(const char *id,
164{
165 SCOPE_ENTER(3, "%s: Checking common config\n", id);
166
170 "%s: ca_file '%s' not found, or is unreadable\n",
171 id, vcfg_common->ca_file);
172 }
173
177 "%s: ca_path '%s' not found, or is unreadable\n",
178 id, vcfg_common->ca_path);
179 }
180
184 "%s: crl_file '%s' not found, or is unreadable\n",
185 id, vcfg_common->crl_file);
186 }
187
191 "%s: crl_path '%s' not found, or is unreadable\n",
192 id, vcfg_common->crl_path);
193 }
194
198 "%s: untrusted_cert_file '%s' not found, or is unreadable\n",
200 }
201
205 "%s: untrusted_cert_path '%s' not found, or is unreadable\n",
207 }
208
211 int rc = 0;
212
213 if (!vcfg_common->tcs) {
215 if (!vcfg_common->tcs) {
217 "%s: Unable to create CA cert store\n", id);
218 }
219 }
222 if (rc != 0) {
224 "%s: Unable to load CA cert store from '%s' or '%s'\n",
226 }
227 }
228
231 int rc = 0;
232
233 if (!vcfg_common->tcs) {
235 if (!vcfg_common->tcs) {
237 "%s: Unable to create CA cert store\n", id);
238 }
239 }
242 if (rc != 0) {
244 "%s: Unable to load CA CRL store from '%s' or '%s'\n",
246 }
247 }
248
251 int rc = 0;
252
253 if (!vcfg_common->tcs) {
255 if (!vcfg_common->tcs) {
257 "%s: Unable to create CA cert store\n", id);
258 }
259 }
262 if (rc != 0) {
264 "%s: Unable to load CA CRL store from '%s' or '%s'\n",
266 }
267 }
268
269 if (vcfg_common->tcs) {
270 if (ENUM_BOOL(vcfg_common->load_system_certs, load_system_certs)) {
271 X509_STORE_set_default_paths(vcfg_common->tcs->certs);
272 }
273
276 X509_STORE_set_flags(vcfg_common->tcs->certs, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_EXTENDED_CRL_SUPPORT);
277 }
278 }
279
281 FILE *fp;
282 char *testfile;
283
284 if (ast_asprintf(&testfile, "%s/testfile", vcfg_common->cert_cache_dir) <= 0) {
286 "%s: Unable to allocate memory for testfile\n", id);
287 }
288
289 fp = fopen(testfile, "w+");
290 if (!fp) {
291 ast_free(testfile);
293 "%s: cert_cache_dir '%s' was not writable\n",
295 }
296 fclose(fp);
297 remove(testfile);
298 ast_free(testfile);
299 }
300
301 SCOPE_EXIT_RTN_VALUE(0, "%s: Done\n", id);
302}
303
304static char *special_addresses[] = {
305 "0.0.0.0/8",
306 "10.0.0.0/8",
307 "100.64.0.0/10",
308 "127.0.0.0/8",
309 "169.254.0.0/16",
310 "172.16.0.0/12",
311 "192.0.0.0/24",
312 "192.0.0.0/29",
313 "192.88.99.0/24",
314 "192.168.0.0/16",
315 "198.18.0.0/15",
316 "198.51.100.0/24",
317 "203.0.113.0/24",
318 "240.0.0.0/4",
319 "255.255.255.255/32",
320 "::1/128",
321 "::/128",
322/* "64:ff9b::/96", IPv4-IPv6 translation addresses should probably not be blocked by default */
323/* "::ffff:0:0/96", IPv4 mapped addresses should probably not be blocked by default */
324 "100::/64",
325 "2001::/23",
326 "2001::/32",
327 "2001:2::/48",
328 "2001:db8::/32",
329 "2001:10::/28",
330/* "2002::/16", 6to4 should problably not be blocked by default */
331 "fc00::/7",
332 "fe80::/10",
333};
334
335static int verification_apply(const struct ast_sorcery *sorcery, void *obj)
336{
337 struct verification_cfg *cfg = obj;
338 const char *id = ast_sorcery_object_get_id(cfg);
339
340 if (vs_check_common_config("verification", &cfg->vcfg_common) !=0) {
341 return -1;
342 }
343
344 if (!cfg->vcfg_common.acl) {
345 int error = 0;
346 int ignore;
347 int i;
348
349 ast_append_acl("permit", "0.0.0.0/0", &cfg->vcfg_common.acl, &error, &ignore);
350 if (error) {
352 cfg->vcfg_common.acl = NULL;
353 ast_log(LOG_ERROR, "%s: Unable to create default acl rule for '%s: %s'\n",
354 id, "permit", "0.0.0.0/0");
355 return -1;
356 }
357
358 for (i = 0; i < ARRAY_LEN(special_addresses); i++) {
360 if (error) {
362 cfg->vcfg_common.acl = NULL;
363 ast_log(LOG_ERROR, "%s: Unable to create default acl rule for '%s: %s'\n",
364 id, "deny", special_addresses[i]);
365 return -1;
366 }
367 }
368 }
369
370 return 0;
371}
372
373static char *cli_verification_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
374{
375 struct verification_cfg *cfg;
376 struct config_object_cli_data data = {
377 .title = "Default Verification",
378 .object_type = config_object_type_verification,
379 };
380
381 switch(cmd) {
382 case CLI_INIT:
383 e->command = "stir_shaken show verification";
384 e->usage =
385 "Usage: stir_shaken show verification\n"
386 " Show the stir/shaken verification settings\n";
387 return NULL;
388 case CLI_GENERATE:
389 return NULL;
390 }
391
392 if (a->argc != 3) {
393 return CLI_SHOWUSAGE;
394 }
395
396 if (!vs_is_config_loaded()) {
397 ast_log(LOG_WARNING,"Stir/Shaken verification service disabled. Either there were errors in the 'verification' object in stir_shaken.conf or it was missing altogether.\n");
398 return CLI_FAILURE;
399 }
400
401 cfg = vs_get_cfg();
402 config_object_cli_show(cfg, a, &data, 0);
403
404 ao2_cleanup(cfg);
405
406 return CLI_SUCCESS;
407}
408
410 AST_CLI_DEFINE(cli_verification_show, "Show stir/shaken verification configuration"),
411};
412
414{
415 struct ast_sorcery *sorcery = get_sorcery();
417
418 if (!vs_is_config_loaded()) {
419 ast_log(LOG_WARNING,"Stir/Shaken verification service disabled. Either there were errors in the 'verification' object in stir_shaken.conf or it was missing altogether.\n");
420 }
421 if (!empty_cfg) {
423 if (!empty_cfg) {
424 return -1;
425 }
427 }
428
429 return 0;
430}
431
433{
437
438 return 0;
439}
440
442{
443 struct ast_sorcery *sorcery = get_sorcery();
444
445 snprintf(DEFAULT_cert_cache_dir, sizeof(DEFAULT_cert_cache_dir), "%s/keys/%s/cache",
447
449 "stir_shaken.conf,criteria=type=" CONFIG_TYPE ",single_object=yes,explicit_name=" CONFIG_TYPE);
450
453 ast_log(LOG_ERROR, "stir/shaken - failed to register '%s' sorcery object\n", CONFIG_TYPE);
454 return -1;
455 }
456
458 OPT_NOOP_T, 0, 0);
459
461 DEFAULT_global_disable ? "yes" : "no",
462 OPT_YESNO_T, 1, FLDSET(struct verification_cfg, global_disable));
463
465
467
468 if (!vs_is_config_loaded()) {
469 ast_log(LOG_WARNING,"Stir/Shaken verification service disabled. Either there were errors in the 'verification' object in stir_shaken.conf or it was missing altogether.\n");
470 }
471 if (!empty_cfg) {
473 if (!empty_cfg) {
474 return -1;
475 }
477 }
478
481
482 return 0;
483}
void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
Add a rule to an ACL struct.
Definition: acl.c:429
struct ast_acl_list * ast_free_acl_list(struct ast_acl_list *acl)
Free a list of ACLs.
Definition: acl.c:233
struct ast_acl_list * ast_duplicate_acl_list(struct ast_acl_list *original)
Duplicates the contests of a list of lists of host access rules.
Definition: acl.c:315
Asterisk main include file. File version handling, generic pbx functions.
#define PATH_MAX
Definition: asterisk.h:40
#define ast_free(a)
Definition: astmm.h:180
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
int config_object_cli_show(void *obj, void *arg, void *data, int flags)
Output configuration settings to the Asterisk CLI.
struct ast_sorcery * get_sorcery(void)
Retrieve the stir/shaken sorcery context.
Definition: common_config.c:34
@ config_object_type_verification
#define cfg_uint_copy(__cfg_dst, __cfg_src, __field)
cfg_uint_copy
#define cfg_sf_copy_wrapper(id, __cfg_dst, __cfg_src, __field)
cfg_copy_wrapper
#define register_common_verification_fields(sorcery, object, CONFIG_TYPE, nodoc)
#define ENUM_BOOL(__enum1, __field)
#define cfg_enum_copy(__cfg_dst, __cfg_src, __field)
cfg_enum_copy
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
int crypto_load_crl_store(struct crypto_cert_store *store, const char *file, const char *path)
Load an X509 Store with certificate revocation lists.
Definition: crypto_utils.c:619
int crypto_load_untrusted_cert_store(struct crypto_cert_store *store, const char *file, const char *path)
Load an X509 Store with untrusted certificates.
Definition: crypto_utils.c:576
struct crypto_cert_store * crypto_create_cert_store(void)
Create an empty X509 store.
Definition: crypto_utils.c:390
int crypto_load_cert_store(struct crypto_cert_store *store, const char *file, const char *path)
Load an X509 Store with either certificates or CRLs.
Definition: crypto_utils.c:560
#define crypto_free_cert_store(store)
Free an X509 store.
Definition: crypto_utils.h:195
static const char name[]
Definition: format_mp3.c:68
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
#define SCOPE_ENTER(level,...)
#define LOG_ERROR
#define LOG_WARNING
#define remove
def ignore(key=None, val=None, section=None, pjsip=None, nmapped=None, type='endpoint')
Definition: sip_to_pjsip.py:48
const char * ast_config_AST_DATA_DIR
Definition: options.c:158
static struct ast_sorcery * sorcery
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
#define ast_sorcery_object_field_register_nodoc(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object without documentation.
Definition: sorcery.h:987
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
Definition: sorcery.c:1393
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
void ast_sorcery_force_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects even if no changes determin...
Definition: sorcery.c:1457
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Full structure for sorcery.
Definition: sorcery.c:230
X509_STORE * certs
Definition: crypto_utils.h:180
Verification Service configuration for stir/shaken.
struct crypto_cert_store * tcs
const ast_string_field cert_cache_dir
const ast_string_field ca_path
const ast_string_field crl_file
const ast_string_field crl_path
enum load_system_certs_enum load_system_certs
const ast_string_field ca_file
const ast_string_field untrusted_cert_file
struct ast_acl_list * acl
const ast_string_field untrusted_cert_path
struct verification_cfg_common vcfg_common
static struct test_val a
int error(const char *format,...)
Definition: utils/frame.c:999
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
Definition: utils.c:3107
#define ARRAY_LEN(a)
Definition: utils.h:666
static int verification_apply(const struct ast_sorcery *sorcery, void *obj)
void vcfg_cleanup(struct verification_cfg_common *vcfg_common)
int vs_config_reload(void)
static struct ast_cli_entry verification_cli[]
generate_vcfg_common_sorcery_handlers(verification_cfg)
int vs_is_config_loaded(void)
static void verification_destructor(void *obj)
#define STIR_SHAKEN_DIR_NAME
static char * cli_verification_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
struct verification_cfg * vs_get_cfg(void)
static void * verification_alloc(const char *name)
int vs_copy_cfg_common(const char *id, struct verification_cfg_common *cfg_dst, struct verification_cfg_common *cfg_src)
static char DEFAULT_cert_cache_dir[PATH_MAX]
#define DEFAULT_global_disable
int vs_config_load(void)
static struct verification_cfg * empty_cfg
int vs_config_unload(void)
int vs_check_common_config(const char *id, struct verification_cfg_common *vcfg_common)
static char * special_addresses[]
#define CONFIG_TYPE