documented update and set the copyright to Martin until the formal papers are received.
[gnutls.git] / lib / ext / srtp.c
blobc7b0e8663d231b6404603f243e14576276bec7ea
1 /*
2 * Copyright (C) 2012 Martin Storsjo
3 *
4 * Author: Martin Storsjo
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include "gnutls_int.h"
24 #include "gnutls_auth.h"
25 #include "gnutls_errors.h"
26 #include "gnutls_num.h"
27 #include <ext/srtp.h>
29 static int _gnutls_srtp_recv_params (gnutls_session_t session,
30 const uint8_t * data,
31 size_t data_size);
32 static int _gnutls_srtp_send_params (gnutls_session_t session,
33 gnutls_buffer_st* extdata);
35 static int _gnutls_srtp_unpack (gnutls_buffer_st * ps,
36 extension_priv_data_t * _priv);
37 static int _gnutls_srtp_pack (extension_priv_data_t _priv,
38 gnutls_buffer_st * ps);
39 static void _gnutls_srtp_deinit_data (extension_priv_data_t priv);
42 extension_entry_st ext_mod_srtp = {
43 .name = "SRTP",
44 .type = GNUTLS_EXTENSION_SRTP,
45 .parse_type = GNUTLS_EXT_APPLICATION,
47 .recv_func = _gnutls_srtp_recv_params,
48 .send_func = _gnutls_srtp_send_params,
49 .pack_func = _gnutls_srtp_pack,
50 .unpack_func = _gnutls_srtp_unpack,
51 .deinit_func = _gnutls_srtp_deinit_data,
54 typedef struct
56 const char *name;
57 gnutls_srtp_profile_t id;
58 } srtp_profile_st;
60 static const srtp_profile_st profile_names[] = {
62 "SRTP_AES128_CM_SHA1_80",
63 GNUTLS_SRTP_AES128_CM_SHA1_80,
66 "SRTP_AES128_CM_SHA1_32",
67 GNUTLS_SRTP_AES128_CM_SHA1_32,
70 "SRTP_NULL_SHA1_80",
71 GNUTLS_SRTP_NULL_SHA1_80,
74 "SRTP_NULL_SHA1_32",
75 GNUTLS_SRTP_NULL_SHA1_32,
78 NULL,
83 static gnutls_srtp_profile_t find_profile (const char *str, const char *end)
85 const srtp_profile_st *prof = profile_names;
86 unsigned int len;
87 if (end != NULL)
89 len = end - str;
91 else
93 len = strlen (str);
96 while (prof->name != NULL)
98 if (strlen (prof->name) == len && !strncmp (str, prof->name, len))
100 return prof->id;
102 prof++;
104 return 0;
108 * gnutls_srtp_get_profile_by_name
109 * @name: The name of the profile to look up
110 * @profile: Will hold the profile id
112 * This function allows you to look up a profile based on a string.
114 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
115 * otherwise a negative error code is returned.
117 * Since 3.1.4
119 int gnutls_srtp_get_profile_by_name (const char *name,
120 gnutls_srtp_profile_t *profile)
122 *profile = find_profile (name, NULL);
123 if (*profile == 0)
125 return GNUTLS_E_ILLEGAL_PARAMETER;
127 return 0;
131 * gnutls_srtp_get_profile_name
132 * @profile: The profile to look up a string for
134 * This function allows you to get the corresponding name for a
135 * SRTP protection profile.
137 * Returns: On success, the name of a SRTP profile as a string,
138 * otherwise NULL.
140 * Since 3.1.4
142 const char *gnutls_srtp_get_profile_name (gnutls_srtp_profile_t profile)
144 const srtp_profile_st *p = profile_names;
145 while (p->name != NULL)
147 if (p->id == profile)
148 return p->name;
149 p++;
151 return NULL;
154 static int
155 _gnutls_srtp_recv_params (gnutls_session_t session,
156 const uint8_t *data, size_t _data_size)
158 unsigned int i, j;
159 int ret;
160 const uint8_t *p = data;
161 int len;
162 ssize_t data_size = _data_size;
163 srtp_ext_st *priv;
164 extension_priv_data_t epriv;
165 uint16_t profiles[MAX_SRTP_PROFILES];
166 unsigned int profiles_size = 0;
168 ret =
169 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SRTP,
170 &epriv);
171 if (ret < 0)
172 return 0;
174 priv = epriv.ptr;
176 DECR_LENGTH_RET (data_size, 2, 0);
177 len = _gnutls_read_uint16 (p);
178 p += 2;
180 while (len > 0)
182 DECR_LENGTH_RET (data_size, 2, 0);
183 if (profiles_size < MAX_SRTP_PROFILES)
184 profiles_size++;
185 profiles[profiles_size - 1] = _gnutls_read_uint16 (p);
186 p += 2;
187 len -= 2;
190 for (i = 0; i < priv->profiles_size && priv->selected_profile == 0; i++)
192 for (j = 0; j < profiles_size; j++)
194 if (priv->profiles[i] == profiles[j])
196 priv->selected_profile = profiles[j];
197 break;
202 return 0;
205 static int
206 _gnutls_srtp_send_params (gnutls_session_t session,
207 gnutls_buffer_st* extdata)
209 unsigned i;
210 int total_size = 0, ret;
211 srtp_ext_st *priv;
212 extension_priv_data_t epriv;
214 ret =
215 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SRTP,
216 &epriv);
217 if (ret < 0)
218 return 0;
220 priv = epriv.ptr;
222 if (priv->profiles_size == 0)
223 return 0;
225 if (session->security_parameters.entity == GNUTLS_SERVER)
227 /* Don't send anything if no matching profile was found */
228 if (priv->selected_profile == 0)
229 return 0;
231 ret = _gnutls_buffer_append_prefix(extdata, 16, 2);
232 if (ret < 0)
233 return gnutls_assert_val(ret);
234 ret = _gnutls_buffer_append_prefix(extdata, 16, priv->selected_profile);
235 if (ret < 0)
236 return gnutls_assert_val(ret);
237 total_size = 4;
239 else
241 ret = _gnutls_buffer_append_prefix(extdata, 16, 2 * priv->profiles_size);
242 if (ret < 0)
243 return gnutls_assert_val(ret);
245 for (i = 0; i < priv->profiles_size; i++)
247 ret = _gnutls_buffer_append_prefix(extdata, 16, priv->profiles[i]);
248 if (ret < 0)
249 return gnutls_assert_val(ret);
251 total_size = 2 + 2 * priv->profiles_size;
254 /* use_mki, not supported yet */
255 ret = _gnutls_buffer_append_prefix(extdata, 8, 0);
256 if (ret < 0)
257 return gnutls_assert_val(ret);
259 return total_size + 1;
263 * gnutls_srtp_get_selected_profile:
264 * @session: is a #gnutls_session_t structure.
265 * @profile: will hold the profile
267 * This function allows you to get the negotiated SRTP profile.
269 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
270 * otherwise a negative error code is returned.
272 * Since 3.1.4
275 gnutls_srtp_get_selected_profile (gnutls_session_t session,
276 gnutls_srtp_profile_t *profile)
278 srtp_ext_st *priv;
279 int ret;
280 extension_priv_data_t epriv;
282 ret =
283 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SRTP,
284 &epriv);
285 if (ret < 0)
287 gnutls_assert ();
288 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
291 priv = epriv.ptr;
293 if (priv->selected_profile == 0)
295 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
298 *profile = priv->selected_profile;
300 return 0;
304 * gnutls_srtp_set_profile:
305 * @session: is a #gnutls_session_t structure.
306 * @profile: is the profile id to add.
308 * This function is to be used by both clients and servers, to declare
309 * what SRTP profiles they support, to negotiate with the peer.
311 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
312 * otherwise a negative error code is returned.
314 * Since 3.1.4
317 gnutls_srtp_set_profile (gnutls_session_t session,
318 gnutls_srtp_profile_t profile)
320 int ret;
321 srtp_ext_st *priv;
322 extension_priv_data_t epriv;
324 ret =
325 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SRTP,
326 &epriv);
327 if (ret < 0)
329 priv = gnutls_calloc (1, sizeof (*priv));
330 if (priv == NULL)
332 gnutls_assert ();
333 return GNUTLS_E_MEMORY_ERROR;
335 epriv.ptr = priv;
336 _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_SRTP,
337 epriv);
339 else
340 priv = epriv.ptr;
342 if (priv->profiles_size < MAX_SRTP_PROFILES)
343 priv->profiles_size++;
344 priv->profiles[priv->profiles_size - 1] = profile;
346 return 0;
350 * gnutls_srtp_set_profile_direct:
351 * @session: is a #gnutls_session_t structure.
352 * @profiles: is a string that contains the supported SRTP profiles,
353 * separated by colons.
354 * @err_pos: In case of an error this will have the position in the string the error occured, may be NULL.
356 * This function is to be used by both clients and servers, to declare
357 * what SRTP profiles they support, to negotiate with the peer.
359 * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
360 * %GNUTLS_E_SUCCESS on success, or an error code.
362 * Since 3.1.4
365 gnutls_srtp_set_profile_direct (gnutls_session_t session,
366 const char *profiles, const char **err_pos)
368 int ret;
369 srtp_ext_st *priv;
370 extension_priv_data_t epriv;
371 int set = 0;
372 const char *col;
373 gnutls_srtp_profile_t id;
375 ret =
376 _gnutls_ext_get_session_data (session, GNUTLS_EXTENSION_SRTP,
377 &epriv);
378 if (ret < 0)
380 set = 1;
381 priv = gnutls_calloc (1, sizeof (*priv));
382 if (priv == NULL)
384 if (err_pos != NULL)
385 *err_pos = profiles;
386 gnutls_assert ();
387 return GNUTLS_E_MEMORY_ERROR;
389 epriv.ptr = priv;
391 else
392 priv = epriv.ptr;
396 col = strchr (profiles, ':');
397 id = find_profile (profiles, col);
398 if (id == 0)
400 if (set != 0)
401 gnutls_free (priv);
402 if (err_pos != NULL)
403 *err_pos = profiles;
404 return GNUTLS_E_INVALID_REQUEST;
407 if (priv->profiles_size < MAX_SRTP_PROFILES)
409 priv->profiles_size++;
411 priv->profiles[priv->profiles_size - 1] = id;
412 profiles = col + 1;
413 } while (col != NULL);
415 if (set != 0)
416 _gnutls_ext_set_session_data (session, GNUTLS_EXTENSION_SRTP,
417 epriv);
419 return 0;
422 static void
423 _gnutls_srtp_deinit_data (extension_priv_data_t priv)
425 gnutls_free (priv.ptr);
428 static int
429 _gnutls_srtp_pack (extension_priv_data_t epriv, gnutls_buffer_st * ps)
431 srtp_ext_st *priv = epriv.ptr;
432 unsigned int i;
433 int ret;
435 BUFFER_APPEND_NUM (ps, priv->profiles_size);
436 for (i = 0; i < priv->profiles_size; i++)
438 BUFFER_APPEND_NUM (ps, priv->profiles[i]);
440 BUFFER_APPEND_NUM (ps, priv->selected_profile);
441 return 0;
444 static int
445 _gnutls_srtp_unpack (gnutls_buffer_st * ps,
446 extension_priv_data_t * _priv)
448 srtp_ext_st *priv;
449 unsigned int i;
450 int ret;
451 extension_priv_data_t epriv;
453 priv = gnutls_calloc (1, sizeof (*priv));
454 if (priv == NULL)
456 gnutls_assert ();
457 return GNUTLS_E_MEMORY_ERROR;
460 BUFFER_POP_NUM (ps, priv->profiles_size);
461 for (i = 0; i < priv->profiles_size; i++)
463 BUFFER_POP_NUM (ps, priv->profiles[i]);
465 BUFFER_POP_NUM (ps, priv->selected_profile);
467 epriv.ptr = priv;
468 *_priv = epriv;
470 return 0;
472 error:
473 gnutls_free (priv);
474 return ret;