Asterisk - The Open Source Telephony Project GIT-master-7e7a603
attestation_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#include "asterisk.h"
19
20#include "asterisk/cli.h"
21#include "asterisk/sorcery.h"
22#include "asterisk/paths.h"
23
24#include "stir_shaken.h"
25
26#define CONFIG_TYPE "attestation"
27
28#define DEFAULT_global_disable 0
29
30#define DEFAULT_check_tn_cert_public_url check_tn_cert_public_url_NO
31#define DEFAULT_private_key_file NULL
32#define DEFAULT_public_cert_url NULL
33#define DEFAULT_attest_level attest_level_NOT_SET
34#define DEFAULT_send_mky send_mky_NO
35
37
39{
42 if (cfg) {
43 return cfg;
44 }
45
46 return empty_cfg ? ao2_bump(empty_cfg) : NULL;
47}
48
50{
53 ao2_cleanup(cfg);
54
55 return !!cfg;
56}
57
59
61{
62 if (!acfg_common) {
63 return;
64 }
67}
68
69static void attestation_destructor(void *obj)
70{
71 struct attestation_cfg *cfg = obj;
72
75}
76
77static void *attestation_alloc(const char *name)
78{
79 struct attestation_cfg *cfg;
80
82 if (!cfg) {
83 return NULL;
84 }
85
86 if (ast_string_field_init(cfg, 1024)) {
87 ao2_ref(cfg, -1);
88 return NULL;
89 }
90
91 /*
92 * The memory for acfg_common actually comes from cfg
93 * due to the weirdness of the STRFLDSET macro used with
94 * sorcery. We just use a token amount of memory in
95 * this call so the initialize doesn't fail.
96 */
97 if (ast_string_field_init(&cfg->acfg_common, 8)) {
98 ao2_ref(cfg, -1);
99 return NULL;
100 }
101
102 return cfg;
103}
104
105int as_copy_cfg_common(const char *id, struct attestation_cfg_common *cfg_dst,
106 struct attestation_cfg_common *cfg_src)
107{
108 int rc = 0;
109
110 if (!cfg_dst || !cfg_src) {
111 return -1;
112 }
113
114 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, private_key_file);
115 cfg_sf_copy_wrapper(id, cfg_dst, cfg_src, public_cert_url);
116
117 cfg_enum_copy(cfg_dst, cfg_src, attest_level);
118 cfg_enum_copy(cfg_dst, cfg_src, check_tn_cert_public_url);
119 cfg_enum_copy(cfg_dst, cfg_src, send_mky);
120
121 if (cfg_src->raw_key) {
122 /* Free and overwrite the destination */
123 ao2_cleanup(cfg_dst->raw_key);
124 cfg_dst->raw_key = ao2_bump(cfg_src->raw_key);
125 cfg_dst->raw_key_length = cfg_src->raw_key_length;
126 }
127
128 return rc;
129}
130
132{
133 SCOPE_ENTER(3, "%s: Checking common config\n", id);
134
137 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: default_private_key_path %s is missing or not readable\n", id,
139 }
140
142 check_tn_cert_public_url)
144 RAII_VAR(char *, public_cert_data, NULL, ast_std_free);
145 X509 *public_cert;
146 size_t public_cert_len;
147 int rc = 0;
148 long http_code;
149 SCOPE_ENTER(3 , "%s: Checking public cert url '%s'\n",
151
153 &public_cert_len, &public_cert_data, NULL);
154 if (http_code / 100 != 2) {
155 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: public_cert '%s' could not be downloaded\n", id,
157 }
158
159 public_cert = crypto_load_cert_from_memory(public_cert_data,
160 public_cert_len);
161 if (!public_cert) {
162 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: public_cert '%s' could not be parsed as a certificate\n", id,
164 }
165 rc = crypto_is_cert_time_valid(public_cert, 0);
166 X509_free(public_cert);
167 if (!rc) {
168 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: public_cert '%s' is not valid yet or has expired\n", id,
170 }
171
172 rc = crypto_has_private_key_from_memory(public_cert_data, public_cert_len);
173 if (rc) {
174 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: DANGER!!! public_cert_url '%s' has a private key in the file!!!\n", id,
176 }
177 SCOPE_EXIT("%s: Done\n", id);
178 }
179
181 EVP_PKEY *private_key;
182 RAII_VAR(unsigned char *, raw_key, NULL, ast_free);
183
185 if (!private_key) {
186 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Could not extract raw private key from file '%s'\n", id,
188 }
189
190 acfg_common->raw_key_length = crypto_extract_raw_privkey(private_key, &raw_key);
191 EVP_PKEY_free(private_key);
192 if (acfg_common->raw_key_length == 0 || raw_key == NULL) {
193 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "%s: Could not extract raw private key from file '%s'\n", id,
195 }
196
197 /*
198 * We're making this an ao2 object so it can be referenced
199 * by a profile instead of having to copy it.
200 */
202 if (!acfg_common->raw_key) {
204 "%s: Could not allocate memory for raw private key\n", id);
205 }
206 memcpy(acfg_common->raw_key, raw_key, acfg_common->raw_key_length);
207
208 }
209
210 SCOPE_EXIT_RTN_VALUE(0, "%s: Done\n", id);
211}
212
213static int attestation_apply(const struct ast_sorcery *sorcery, void *obj)
214{
215 struct attestation_cfg *cfg = obj;
216 const char *id = ast_sorcery_object_get_id(cfg);
217
218 if (as_check_common_config(id, &cfg->acfg_common) != 0) {
219 return -1;
220 }
221
222 return 0;
223}
224
225static char *attestation_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
226{
227 struct attestation_cfg *cfg;
228 struct config_object_cli_data data = {
229 .title = "Default Attestation",
230 .object_type = config_object_type_attestation,
231 };
232
233 switch(cmd) {
234 case CLI_INIT:
235 e->command = "stir_shaken show attestation";
236 e->usage =
237 "Usage: stir_shaken show attestation\n"
238 " Show the stir/shaken attestation settings\n";
239 return NULL;
240 case CLI_GENERATE:
241 return NULL;
242 }
243
244 if (a->argc != 3) {
245 return CLI_SHOWUSAGE;
246 }
247
248 cfg = as_get_cfg();
249 config_object_cli_show(cfg, a, &data, 0);
250 ao2_cleanup(cfg);
251
252 return CLI_SUCCESS;
253}
254
256 AST_CLI_DEFINE(attestation_show, "Show stir/shaken attestation configuration"),
257};
258
260{
261 struct ast_sorcery *sorcery = get_sorcery();
263
264 if (!as_is_config_loaded()) {
265 ast_log(LOG_WARNING,"Stir/Shaken attestation service disabled. Either there were errors in the 'attestation' object in stir_shaken.conf or it was missing altogether.\n");
266 }
267 if (!empty_cfg) {
269 if (!empty_cfg) {
270 return -1;
271 }
273 }
274
275 return 0;
276}
277
279{
283
284 return 0;
285}
286
288{
289 struct ast_sorcery *sorcery = get_sorcery();
290
292 "stir_shaken.conf,criteria=type=" CONFIG_TYPE ",single_object=yes,explicit_name=" CONFIG_TYPE);
293
296 ast_log(LOG_ERROR, "stir/shaken - failed to register '%s' sorcery object\n", CONFIG_TYPE);
297 return -1;
298 }
299
301 "", OPT_NOOP_T, 0, 0);
302
304 DEFAULT_global_disable ? "yes" : "no",
305 OPT_YESNO_T, 1, FLDSET(struct attestation_cfg, global_disable));
306
308
310
311 if (!as_is_config_loaded()) {
312 ast_log(LOG_WARNING,"Stir/Shaken attestation service disabled. Either there were errors in the 'attestation' object in stir_shaken.conf or it was missing altogether.\n");
313 }
314 if (!empty_cfg) {
316 if (!empty_cfg) {
317 return -1;
318 }
320 }
321
324
325 return 0;
326}
Asterisk main include file. File version handling, generic pbx functions.
void ast_std_free(void *ptr)
Definition: astmm.c:1734
#define ast_free(a)
Definition: astmm.h:180
#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
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
int as_config_unload(void)
int as_config_reload(void)
static struct ast_cli_entry attestation_cli[]
struct attestation_cfg * as_get_cfg(void)
static struct attestation_cfg * empty_cfg
static void attestation_destructor(void *obj)
int as_check_common_config(const char *id, struct attestation_cfg_common *acfg_common)
void acfg_cleanup(struct attestation_cfg_common *acfg_common)
int as_config_load(void)
#define DEFAULT_global_disable
int as_is_config_loaded(void)
generate_acfg_common_sorcery_handlers(attestation_cfg)
static void * attestation_alloc(const char *name)
static char * attestation_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
int as_copy_cfg_common(const char *id, struct attestation_cfg_common *cfg_dst, struct attestation_cfg_common *cfg_src)
#define CONFIG_TYPE
static int attestation_apply(const struct ast_sorcery *sorcery, void *obj)
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 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_attestation
#define cfg_sf_copy_wrapper(id, __cfg_dst, __cfg_src, __field)
cfg_copy_wrapper
#define register_common_attestation_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)
X509 * crypto_load_cert_from_memory(const char *buffer, size_t size)
Load an X509 Cert from a NULL terminated buffer.
Definition: crypto_utils.c:185
EVP_PKEY * crypto_load_privkey_from_file(const char *filename)
Load a private key from a file.
Definition: crypto_utils.c:137
int crypto_extract_raw_privkey(EVP_PKEY *key, unsigned char **buffer)
Extract raw private key from EVP_PKEY.
Definition: crypto_utils.c:292
int crypto_is_cert_time_valid(X509 *cert, time_t reftime)
Check if the reftime is within the cert's valid dates.
Definition: crypto_utils.c:383
int crypto_has_private_key_from_memory(const char *buffer, size_t size)
Check if the supplied buffer has a private key.
Definition: crypto_utils.c:238
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 SCOPE_EXIT(...)
long curl_download_to_memory(const char *url, size_t *returned_length, char **returned_data, struct ast_variable **headers)
Really simple document retrieval to memory.
Definition: curl_utils.c:300
#define LOG_ERROR
#define LOG_WARNING
Asterisk file paths, configured in asterisk.conf.
static struct ast_sorcery * sorcery
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
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
Attestation Service configuration for stir/shaken.
enum check_tn_cert_public_url_enum check_tn_cert_public_url
unsigned char * raw_key
const ast_string_field public_cert_url
const ast_string_field private_key_file
struct attestation_cfg_common acfg_common
static struct test_val a
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
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