Asterisk - The Open Source Telephony Project GIT-master-f36a736
security_agreements.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2022, Commend International
5 *
6 * Maximilian Fridrich <m.fridrich@commend.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/*!
20 * \file
21 *
22 * \brief Interact with security agreement negotiations and mechanisms
23 *
24 * \author Maximilian Fridrich <m.fridrich@commend.com>
25 */
26
27#include "asterisk.h"
28
29#include <pjsip.h>
30
31#include "asterisk/res_pjsip.h"
32
34{
35 struct ast_sip_security_mechanism *mech;
36
37 mech = ast_calloc(1, sizeof(struct ast_sip_security_mechanism));
38 if (mech == NULL) {
39 return NULL;
40 }
41 mech->qvalue = 0.0;
42 if (AST_VECTOR_INIT(&mech->mechanism_parameters, n_params) != 0) {
43 ast_free(mech);
44 return NULL;
45 }
46
47 return mech;
48}
49
51 const struct ast_sip_security_mechanism *src)
52{
53 struct ast_sip_security_mechanism *dst = NULL;
54 int i, n_params;
55 char *param;
56
57 n_params = AST_VECTOR_SIZE(&src->mechanism_parameters);
58
59 dst = security_mechanisms_alloc(n_params);
60 if (dst == NULL) {
61 return NULL;
62 }
63 dst->type = src->type;
64 dst->qvalue = src->qvalue;
65
66 for (i = 0; i < n_params; i++) {
69 }
70
71 return dst;
72}
73
75{
78 ast_free(mech);
79}
80
82 const struct ast_sip_security_mechanism_vector *src)
83{
84 struct ast_sip_security_mechanism *mech;
85 int i;
86
88 for (i = 0; i < AST_VECTOR_SIZE(src); i++) {
89 mech = AST_VECTOR_GET(src, i);
91 }
92};
93
95{
96 if (!security_mechanisms) {
97 return;
98 }
99
100 AST_VECTOR_RESET(security_mechanisms, security_mechanism_destroy);
101 AST_VECTOR_FREE(security_mechanisms);
102}
103
104static char *mechanism_str[] = {
106 [AST_SIP_SECURITY_MECH_MSRP_TLS] = "msrp-tls",
107 [AST_SIP_SECURITY_MECH_SDES_SRTP] = "sdes-srtp",
108 [AST_SIP_SECURITY_MECH_DTLS_SRTP] = "dtls-srtp",
109};
110
111
112static int str_to_security_mechanism_type(const char *security_mechanism) {
113 int i = 0;
114
115 for (i = 0; i < ARRAY_LEN(mechanism_str); i++) {
116 if (!strcasecmp(security_mechanism, mechanism_str[i])) {
117 return i;
118 }
119 }
120
121 return -1;
122}
123
124static int security_mechanism_to_str(const struct ast_sip_security_mechanism *security_mechanism, int add_qvalue, char **buf)
125{
126 size_t size;
127 int i;
128 int rc = 0;
130
131 if (str == NULL) {
132 return ENOMEM;
133 }
134
135 if (security_mechanism == NULL) {
136 return EINVAL;
137 }
138
139 rc = ast_str_set(&str, 0, "%s", mechanism_str[security_mechanism->type]);
140 if (rc <= 0) {
141 return ENOMEM;
142 }
143 if (add_qvalue) {
144 rc = ast_str_append(&str, 0, ";q=%f.4", security_mechanism->qvalue);
145 if (rc <= 0) {
146 return ENOMEM;
147 }
148 }
149
150 size = AST_VECTOR_SIZE(&security_mechanism->mechanism_parameters);
151 for (i = 0; i < size; ++i) {
152 rc = ast_str_append(&str, 0, ";%s", AST_VECTOR_GET(&security_mechanism->mechanism_parameters, i));
153 if (rc <= 0) {
154 return ENOMEM;
155 }
156 }
157
159 return 0;
160}
161
162int ast_sip_security_mechanisms_to_str(const struct ast_sip_security_mechanism_vector *security_mechanisms, int add_qvalue, char **buf)
163{
164 size_t vec_size;
165 struct ast_sip_security_mechanism *mech;
166 char *tmp_buf;
168 size_t i;
169 int rc = 0;
170
171 if (str == NULL) {
172 return ENOMEM;
173 }
174
175 if (!security_mechanisms) {
176 return -1;
177 }
178
179 vec_size = AST_VECTOR_SIZE(security_mechanisms);
180 if (vec_size == 0) {
181 return -1;
182 }
183
184 for (i = 0; i < vec_size; ++i) {
185 mech = AST_VECTOR_GET(security_mechanisms, i);
186 rc = security_mechanism_to_str(mech, add_qvalue, &tmp_buf);
187 if (rc) {
188 return rc;
189 }
190 rc = ast_str_append(&str, 0, "%s, ", tmp_buf);
192 if (rc <= 0) {
193 return ENOMEM;
194 }
195 }
196
197 /* ast_str_truncate removes the trailing ", " on the last mechanism */
199
200 return 0;
201}
202
203void ast_sip_remove_headers_by_name_and_value(pjsip_msg *msg, const pj_str_t *hdr_name, const char* value)
204{
205 struct pjsip_generic_string_hdr *hdr = pjsip_msg_find_hdr_by_name(msg, hdr_name, NULL);
206 for (; hdr; hdr = pjsip_msg_find_hdr_by_name(msg, hdr_name, hdr->next)) {
207 if (value == NULL || !pj_strcmp2(&hdr->hvalue, value)) {
208 pj_list_erase(hdr);
209 }
210 if (hdr->next == hdr) {
211 break;
212 }
213 }
214}
215
216/*!
217 * \internal
218 * \brief Parses a string representing a q_value to a float.
219 *
220 * Valid q values must be in the range from 0.0 to 1.0 inclusively.
221 *
222 * \param q_value
223 * \retval The parsed qvalue or -1.0 on failure.
224 */
225static float parse_qvalue(const char *q_value) {
226 char *end;
227 float ret = strtof(q_value, &end);
228
229 if (end == q_value) {
230 /* Not a number. */
231 return -1.0;
232 } else if ('\0' != *end) {
233 /* Extra character at end of input. */
234 return -1.0;
235 } else if (ret > 1.0 || ret < 0.0) {
236 /* Out of valid range. */
237 return -1.0;
238 }
239 return ret;
240}
241
242int ast_sip_str_to_security_mechanism(struct ast_sip_security_mechanism **security_mechanism, const char *value) {
243 struct ast_sip_security_mechanism *mech;
244 char *param;
245 char *tmp;
246 char *mechanism = ast_strdupa(value);
247 int err = 0;
248 int type = -1;
249
251 if (!mech) {
252 err = ENOMEM;
253 goto out;
254 }
255
256 tmp = ast_strsep(&mechanism, ';', AST_STRSEP_ALL);
258 if (type == -1) {
259 err = EINVAL;
260 goto out;
261 }
262
263 mech->type = type;
264 while ((param = ast_strsep(&mechanism, ';', AST_STRSEP_ALL))) {
265 if (!param) {
266 err = EINVAL;
267 goto out;
268 }
269 if (!strncmp(param, "q=", 2)) {
270 mech->qvalue = parse_qvalue(&param[2]);
271 if (mech->qvalue < 0.0) {
272 err = EINVAL;
273 goto out;
274 }
275 continue;
276 }
277 param = ast_strdup(param);
279 }
280
281 *security_mechanism = mech;
282
283out:
284 if (err && (mech != NULL)) {
286 }
287 return err;
288}
289
291 const char *header_name, int add_qval, pjsip_tx_data *tdata) {
292 struct ast_sip_security_mechanism *mech;
293 char *buf;
294 int mech_cnt;
295 int i;
296 int add_qvalue = 1;
297 static const pj_str_t proxy_require = { "Proxy-Require", 13 };
298 static const pj_str_t require = { "Require", 7 };
299
300 if (!security_mechanisms || !tdata) {
301 return EINVAL;
302 }
303
304 if (!strcmp(header_name, "Security-Client")) {
305 add_qvalue = 0;
306 } else if (strcmp(header_name, "Security-Server") &&
307 strcmp(header_name, "Security-Verify")) {
308 return EINVAL;
309 }
310 /* If we're adding Security-Client headers, don't add q-value
311 * even if the function caller requested it. */
312 add_qvalue = add_qvalue && add_qval;
313
314 mech_cnt = AST_VECTOR_SIZE(security_mechanisms);
315 for (i = 0; i < mech_cnt; ++i) {
316 mech = AST_VECTOR_GET(security_mechanisms, i);
317 if (security_mechanism_to_str(mech, add_qvalue, &buf)) {
318 continue;
319 }
320 ast_sip_add_header(tdata, header_name, buf);
321 ast_free(buf);
322 }
323
324 if (pjsip_msg_find_hdr_by_name(tdata->msg, &require, NULL) == NULL) {
325 ast_sip_add_header(tdata, "Require", "mediasec");
326 }
327 if (pjsip_msg_find_hdr_by_name(tdata->msg, &proxy_require, NULL) == NULL) {
328 ast_sip_add_header(tdata, "Proxy-Require", "mediasec");
329 }
330 return 0;
331}
332
333void ast_sip_header_to_security_mechanism(const pjsip_generic_string_hdr *hdr,
334 struct ast_sip_security_mechanism_vector *security_mechanisms) {
335
336 struct ast_sip_security_mechanism *mech;
337 char buf[512];
338 char *hdr_val;
339 char *mechanism;
340
341 if (!security_mechanisms || !hdr) {
342 return;
343 }
344
345 if (pj_stricmp2(&hdr->name, "Security-Client") && pj_stricmp2(&hdr->name, "Security-Server") &&
346 pj_stricmp2(&hdr->name, "Security-Verify")) {
347 return;
348 }
349
350 ast_copy_pj_str(buf, &hdr->hvalue, sizeof(buf));
351 hdr_val = ast_skip_blanks(buf);
352
353 while ((mechanism = ast_strsep(&hdr_val, ',', AST_STRSEP_ALL))) {
354 if (!ast_sip_str_to_security_mechanism(&mech, mechanism)) {
355 AST_VECTOR_APPEND(security_mechanisms, mech);
356 }
357 }
358}
359
361{
362 char *val = value ? ast_strdupa(value) : NULL;
363 struct ast_sip_security_mechanism *mech;
364 char *mechanism;
365
367 if (AST_VECTOR_INIT(security_mechanisms, 1)) {
368 return -1;
369 }
370
371 if (!val) {
372 return 0;
373 }
374
375 while ((mechanism = ast_strsep(&val, ',', AST_STRSEP_ALL))) {
376 if (!ast_sip_str_to_security_mechanism(&mech, mechanism)) {
377 AST_VECTOR_APPEND(security_mechanisms, mech);
378 }
379 }
380
381 return 0;
382}
const char * str
Definition: app_jack.c:147
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
static int tmp()
Definition: bt_open.c:389
static const char type[]
Definition: chan_ooh323.c:109
char * end
Definition: eagi_proxy.c:73
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct ast_threadstorage tmp_buf
Definition: func_strings.c:48
@ AST_SIP_SECURITY_MECH_DTLS_SRTP
Definition: res_pjsip.h:368
@ AST_SIP_SECURITY_MECH_SDES_SRTP
Definition: res_pjsip.h:366
@ AST_SIP_SECURITY_MECH_MSRP_TLS
Definition: res_pjsip.h:364
@ AST_SIP_SECURITY_MECH_NONE
Definition: res_pjsip.h:362
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition: res_pjsip.c:2008
#define NULL
Definition: resample.c:96
void ast_sip_header_to_security_mechanism(const pjsip_generic_string_hdr *hdr, struct ast_sip_security_mechanism_vector *security_mechanisms)
Append to security mechanism vector from SIP header.
void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst, const struct ast_sip_security_mechanism_vector *src)
Duplicate a security mechanism.
static struct ast_sip_security_mechanism * security_mechanisms_copy(const struct ast_sip_security_mechanism *src)
static struct ast_sip_security_mechanism * security_mechanisms_alloc(size_t n_params)
void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms)
Free contents of a security mechanism vector.
static int security_mechanism_to_str(const struct ast_sip_security_mechanism *security_mechanism, int add_qvalue, char **buf)
static int str_to_security_mechanism_type(const char *security_mechanism)
int ast_sip_security_mechanism_vector_init(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *value)
Initialize security mechanism vector from string of security mechanisms.
static void security_mechanism_destroy(struct ast_sip_security_mechanism *mech)
int ast_sip_security_mechanisms_to_str(const struct ast_sip_security_mechanism_vector *security_mechanisms, int add_qvalue, char **buf)
Writes the security mechanisms of an endpoint into a buffer as a string and returns the buffer.
int ast_sip_str_to_security_mechanism(struct ast_sip_security_mechanism **security_mechanism, const char *value)
Allocate a security mechanism from a string.
static float parse_qvalue(const char *q_value)
void ast_sip_remove_headers_by_name_and_value(pjsip_msg *msg, const pj_str_t *hdr_name, const char *value)
Removes all headers of a specific name and value from a pjsip_msg.
static char * mechanism_str[]
int ast_sip_add_security_headers(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *header_name, int add_qval, pjsip_tx_data *tdata)
Add security headers to transmission data.
#define MAX_OBJECT_FIELD
Maximum length of an object field name.
Definition: sorcery.h:110
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
@ AST_STRSEP_ALL
Definition: strings.h:258
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1835
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161
Structure representing a security mechanism as defined in RFC 3329.
Definition: res_pjsip.h:375
struct ast_vector_string mechanism_parameters
Definition: res_pjsip.h:381
enum ast_sip_security_mechanism_type type
Definition: res_pjsip.h:377
Support for dynamic strings.
Definition: strings.h:623
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
FILE * out
Definition: utils/frame.c:33
#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
#define ARRAY_LEN(a)
Definition: utils.h:666
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680