2 * Copyright (C) 2012 Martin Storsjo
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"
29 static int _gnutls_srtp_recv_params (gnutls_session_t session
,
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
= {
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
,
57 gnutls_srtp_profile_t id
;
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
,
71 GNUTLS_SRTP_NULL_SHA1_80
,
75 GNUTLS_SRTP_NULL_SHA1_32
,
83 static gnutls_srtp_profile_t
find_profile (const char *str
, const char *end
)
85 const srtp_profile_st
*prof
= profile_names
;
96 while (prof
->name
!= NULL
)
98 if (strlen (prof
->name
) == len
&& !strncmp (str
, prof
->name
, len
))
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.
119 int gnutls_srtp_get_profile_by_name (const char *name
,
120 gnutls_srtp_profile_t
*profile
)
122 *profile
= find_profile (name
, NULL
);
125 return GNUTLS_E_ILLEGAL_PARAMETER
;
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,
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
)
155 _gnutls_srtp_recv_params (gnutls_session_t session
,
156 const uint8_t *data
, size_t _data_size
)
160 const uint8_t *p
= data
;
162 ssize_t data_size
= _data_size
;
164 extension_priv_data_t epriv
;
165 uint16_t profiles
[MAX_SRTP_PROFILES
];
166 unsigned int profiles_size
= 0;
169 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
176 DECR_LENGTH_RET (data_size
, 2, 0);
177 len
= _gnutls_read_uint16 (p
);
182 DECR_LENGTH_RET (data_size
, 2, 0);
183 if (profiles_size
< MAX_SRTP_PROFILES
)
185 profiles
[profiles_size
- 1] = _gnutls_read_uint16 (p
);
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
];
206 _gnutls_srtp_send_params (gnutls_session_t session
,
207 gnutls_buffer_st
* extdata
)
210 int total_size
= 0, ret
;
212 extension_priv_data_t epriv
;
215 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
222 if (priv
->profiles_size
== 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)
231 ret
= _gnutls_buffer_append_prefix(extdata
, 16, 2);
233 return gnutls_assert_val(ret
);
234 ret
= _gnutls_buffer_append_prefix(extdata
, 16, priv
->selected_profile
);
236 return gnutls_assert_val(ret
);
241 ret
= _gnutls_buffer_append_prefix(extdata
, 16, 2 * priv
->profiles_size
);
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
]);
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);
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.
275 gnutls_srtp_get_selected_profile (gnutls_session_t session
,
276 gnutls_srtp_profile_t
*profile
)
280 extension_priv_data_t epriv
;
283 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
288 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
293 if (priv
->selected_profile
== 0)
295 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
298 *profile
= priv
->selected_profile
;
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.
317 gnutls_srtp_set_profile (gnutls_session_t session
,
318 gnutls_srtp_profile_t profile
)
322 extension_priv_data_t epriv
;
325 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
329 priv
= gnutls_calloc (1, sizeof (*priv
));
333 return GNUTLS_E_MEMORY_ERROR
;
336 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
342 if (priv
->profiles_size
< MAX_SRTP_PROFILES
)
343 priv
->profiles_size
++;
344 priv
->profiles
[priv
->profiles_size
- 1] = profile
;
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.
365 gnutls_srtp_set_profile_direct (gnutls_session_t session
,
366 const char *profiles
, const char **err_pos
)
370 extension_priv_data_t epriv
;
373 gnutls_srtp_profile_t id
;
376 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
381 priv
= gnutls_calloc (1, sizeof (*priv
));
387 return GNUTLS_E_MEMORY_ERROR
;
396 col
= strchr (profiles
, ':');
397 id
= find_profile (profiles
, col
);
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
;
413 } while (col
!= NULL
);
416 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
423 _gnutls_srtp_deinit_data (extension_priv_data_t priv
)
425 gnutls_free (priv
.ptr
);
429 _gnutls_srtp_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
431 srtp_ext_st
*priv
= epriv
.ptr
;
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
);
445 _gnutls_srtp_unpack (gnutls_buffer_st
* ps
,
446 extension_priv_data_t
* _priv
)
451 extension_priv_data_t epriv
;
453 priv
= gnutls_calloc (1, sizeof (*priv
));
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
);