2 * Copyright (C) 2012 Free Software Foundation
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
;
58 unsigned int key_length
;
59 unsigned int salt_length
;
62 static const srtp_profile_st profile_names
[] = {
64 "SRTP_AES128_CM_HMAC_SHA1_80",
65 GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80
,
69 "SRTP_AES128_CM_HMAC_SHA1_32",
70 GNUTLS_SRTP_AES128_CM_HMAC_SHA1_32
,
74 "SRTP_NULL_HMAC_SHA1_80",
75 GNUTLS_SRTP_NULL_HMAC_SHA1_80
,
80 GNUTLS_SRTP_NULL_HMAC_SHA1_32
,
89 static const srtp_profile_st
*get_profile (gnutls_srtp_profile_t profile
)
91 const srtp_profile_st
*p
= profile_names
;
92 while (p
->name
!= NULL
)
101 static gnutls_srtp_profile_t
find_profile (const char *str
, const char *end
)
103 const srtp_profile_st
*prof
= profile_names
;
114 while (prof
->name
!= NULL
)
116 if (strlen (prof
->name
) == len
&& !strncmp (str
, prof
->name
, len
))
126 * gnutls_srtp_get_profile_id
127 * @name: The name of the profile to look up
128 * @profile: Will hold the profile id
130 * This function allows you to look up a profile based on a string.
132 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
133 * otherwise a negative error code is returned.
137 int gnutls_srtp_get_profile_id (const char *name
,
138 gnutls_srtp_profile_t
*profile
)
140 *profile
= find_profile (name
, NULL
);
143 return GNUTLS_E_ILLEGAL_PARAMETER
;
148 #define MAX_PROFILES_IN_SRTP_EXTENSION 256
151 * gnutls_srtp_get_profile_name
152 * @profile: The profile to look up a string for
154 * This function allows you to get the corresponding name for a
155 * SRTP protection profile.
157 * Returns: On success, the name of a SRTP profile as a string,
162 const char *gnutls_srtp_get_profile_name (gnutls_srtp_profile_t profile
)
164 const srtp_profile_st
*p
= get_profile(profile
);
173 _gnutls_srtp_recv_params (gnutls_session_t session
,
174 const uint8_t *data
, size_t _data_size
)
178 const uint8_t *p
= data
;
180 ssize_t data_size
= _data_size
;
182 extension_priv_data_t epriv
;
186 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
193 DECR_LENGTH_RET (data_size
, 2, 0);
194 len
= _gnutls_read_uint16 (p
);
197 if (len
+1 > data_size
)
198 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
200 if (session
->security_parameters
.entity
== GNUTLS_SERVER
)
202 if (len
> MAX_PROFILES_IN_SRTP_EXTENSION
*2)
208 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
213 DECR_LEN (data_size
, 2);
214 profile
= _gnutls_read_uint16 (p
);
216 for (i
= 0; i
< priv
->profiles_size
;i
++)
218 if (priv
->profiles
[i
] == profile
)
220 priv
->selected_profile
= profile
;
228 DECR_LEN (data_size
, 1);
232 if (priv
->mki_size
> 0)
234 DECR_LEN (data_size
, priv
->mki_size
);
235 memcpy(priv
->mki
, p
, priv
->mki_size
);
236 priv
->mki_received
= 1;
243 _gnutls_srtp_send_params (gnutls_session_t session
,
244 gnutls_buffer_st
* extdata
)
247 int total_size
= 0, ret
;
249 extension_priv_data_t epriv
;
252 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
259 if (priv
->profiles_size
== 0)
262 if (session
->security_parameters
.entity
== GNUTLS_SERVER
)
264 /* Don't send anything if no matching profile was found */
265 if (priv
->selected_profile
== 0)
268 ret
= _gnutls_buffer_append_prefix(extdata
, 16, 2);
270 return gnutls_assert_val(ret
);
271 ret
= _gnutls_buffer_append_prefix(extdata
, 16, priv
->selected_profile
);
273 return gnutls_assert_val(ret
);
278 ret
= _gnutls_buffer_append_prefix(extdata
, 16, 2 * priv
->profiles_size
);
280 return gnutls_assert_val(ret
);
282 for (i
= 0; i
< priv
->profiles_size
; i
++)
284 ret
= _gnutls_buffer_append_prefix(extdata
, 16, priv
->profiles
[i
]);
286 return gnutls_assert_val(ret
);
288 total_size
= 2 + 2 * priv
->profiles_size
;
292 ret
= _gnutls_buffer_append_data_prefix(extdata
, 8, priv
->mki
, priv
->mki_size
);
294 return gnutls_assert_val(ret
);
296 return total_size
+ 1;
300 * gnutls_srtp_get_selected_profile:
301 * @session: is a #gnutls_session_t structure.
302 * @profile: will hold the profile
304 * This function allows you to get the negotiated SRTP profile.
306 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
307 * otherwise a negative error code is returned.
312 gnutls_srtp_get_selected_profile (gnutls_session_t session
,
313 gnutls_srtp_profile_t
*profile
)
317 extension_priv_data_t epriv
;
320 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
325 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
330 if (priv
->selected_profile
== 0)
332 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
335 *profile
= priv
->selected_profile
;
341 * gnutls_srtp_get_mki:
342 * @session: is a #gnutls_session_t structure.
343 * @mki: will hold the MKI
345 * This function exports the negotiated Master Key Identifier,
346 * received by the peer if any. The returned value in @mki should be
347 * treated as constant and valid only during the session's lifetime.
349 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
350 * otherwise a negative error code is returned.
355 gnutls_srtp_get_mki (gnutls_session_t session
,
360 extension_priv_data_t epriv
;
363 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
366 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
370 if (priv
->mki_received
== 0)
371 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
373 mki
->data
= priv
->mki
;
374 mki
->size
= priv
->mki_size
;
380 * gnutls_srtp_set_mki:
381 * @session: is a #gnutls_session_t structure.
382 * @mki: holds the MKI
384 * This function sets the Master Key Identifier, to be
385 * used by this session (if any).
387 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
388 * otherwise a negative error code is returned.
393 gnutls_srtp_set_mki (gnutls_session_t session
,
394 const gnutls_datum_t
*mki
)
398 extension_priv_data_t epriv
;
401 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
405 priv
= gnutls_calloc (1, sizeof (*priv
));
409 return GNUTLS_E_MEMORY_ERROR
;
412 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
418 if (mki
->size
> 0 && mki
->size
<= sizeof(priv
->mki
))
420 priv
->mki_size
= mki
->size
;
421 memcpy(priv
->mki
, mki
->data
, mki
->size
);
424 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
430 * gnutls_srtp_set_profile:
431 * @session: is a #gnutls_session_t structure.
432 * @profile: is the profile id to add.
434 * This function is to be used by both clients and servers, to declare
435 * what SRTP profiles they support, to negotiate with the peer.
437 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
438 * otherwise a negative error code is returned.
443 gnutls_srtp_set_profile (gnutls_session_t session
,
444 gnutls_srtp_profile_t profile
)
448 extension_priv_data_t epriv
;
451 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
455 priv
= gnutls_calloc (1, sizeof (*priv
));
459 return GNUTLS_E_MEMORY_ERROR
;
462 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
468 if (priv
->profiles_size
< MAX_SRTP_PROFILES
)
469 priv
->profiles_size
++;
470 priv
->profiles
[priv
->profiles_size
- 1] = profile
;
476 * gnutls_srtp_set_profile_direct:
477 * @session: is a #gnutls_session_t structure.
478 * @profiles: is a string that contains the supported SRTP profiles,
479 * separated by colons.
480 * @err_pos: In case of an error this will have the position in the string the error occured, may be NULL.
482 * This function is to be used by both clients and servers, to declare
483 * what SRTP profiles they support, to negotiate with the peer.
485 * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
486 * %GNUTLS_E_SUCCESS on success, or an error code.
491 gnutls_srtp_set_profile_direct (gnutls_session_t session
,
492 const char *profiles
, const char **err_pos
)
496 extension_priv_data_t epriv
;
499 gnutls_srtp_profile_t id
;
502 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
507 priv
= gnutls_calloc (1, sizeof (*priv
));
513 return GNUTLS_E_MEMORY_ERROR
;
522 col
= strchr (profiles
, ':');
523 id
= find_profile (profiles
, col
);
530 return GNUTLS_E_INVALID_REQUEST
;
533 if (priv
->profiles_size
< MAX_SRTP_PROFILES
)
535 priv
->profiles_size
++;
537 priv
->profiles
[priv
->profiles_size
- 1] = id
;
539 } while (col
!= NULL
);
542 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
549 * gnutls_srtp_get_keys:
550 * @session: is a #gnutls_session_t structure.
551 * @key_material: Space to hold the generated key material
552 * @key_material_size: The maximum size of the key material
553 * @client_key: The master client write key, pointing inside the key material
554 * @server_key: The master server write key, pointing inside the key material
555 * @client_salt: The master client write salt, pointing inside the key material
556 * @server_salt: The master server write salt, pointing inside the key material
558 * This is a helper function to generate the keying material for SRTP.
559 * It requires the space of the key material to be pre-allocated (should be at least
560 * 2x the maximum key size and salt size). The @client_key, @client_salt, @server_key
561 * and @server_salt are convenience datums that point inside the key material. They may
564 * Returns: On success the size of the key material is returned,
565 * otherwise, %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
566 * sufficient, or a negative error code.
571 gnutls_srtp_get_keys (gnutls_session_t session
,
573 unsigned int key_material_size
,
574 gnutls_datum_t
*client_key
,
575 gnutls_datum_t
*client_salt
,
576 gnutls_datum_t
*server_key
,
577 gnutls_datum_t
*server_salt
)
580 const srtp_profile_st
*p
;
581 gnutls_srtp_profile_t profile
;
583 uint8_t *km
= key_material
;
585 ret
= gnutls_srtp_get_selected_profile (session
, &profile
);
587 return gnutls_assert_val(ret
);
589 p
= get_profile(profile
);
591 return gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM
);
593 msize
= 2*(p
->key_length
+p
->salt_length
);
594 if (msize
> key_material_size
)
595 return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER
);
598 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
600 ret
= gnutls_prf(session
, sizeof("EXTRACTOR-dtls_srtp")-1, "EXTRACTOR-dtls_srtp", 0, 0,
601 NULL
, msize
, key_material
);
603 return gnutls_assert_val(ret
);
607 client_key
->data
= km
;
608 client_key
->size
= p
->key_length
;
613 server_key
->data
= km
+ p
->key_length
;
614 server_key
->size
= p
->key_length
;
619 client_salt
->data
= km
+ 2*p
->key_length
;
620 client_salt
->size
= p
->salt_length
;
625 server_salt
->data
= km
+ 2*p
->key_length
+ p
->salt_length
;
626 server_salt
->size
= p
->salt_length
;
633 _gnutls_srtp_deinit_data (extension_priv_data_t priv
)
635 gnutls_free (priv
.ptr
);
639 _gnutls_srtp_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
641 srtp_ext_st
*priv
= epriv
.ptr
;
645 BUFFER_APPEND_NUM (ps
, priv
->profiles_size
);
646 for (i
= 0; i
< priv
->profiles_size
; i
++)
648 BUFFER_APPEND_NUM (ps
, priv
->profiles
[i
]);
651 BUFFER_APPEND_NUM (ps
, priv
->mki_received
);
652 if (priv
->mki_received
)
654 BUFFER_APPEND_NUM (ps
, priv
->selected_profile
);
655 BUFFER_APPEND_PFX4 (ps
, priv
->mki
, priv
->mki_size
);
661 _gnutls_srtp_unpack (gnutls_buffer_st
* ps
,
662 extension_priv_data_t
* _priv
)
667 extension_priv_data_t epriv
;
669 priv
= gnutls_calloc (1, sizeof (*priv
));
673 return GNUTLS_E_MEMORY_ERROR
;
676 BUFFER_POP_NUM (ps
, priv
->profiles_size
);
677 for (i
= 0; i
< priv
->profiles_size
; i
++)
679 BUFFER_POP_NUM (ps
, priv
->profiles
[i
]);
681 BUFFER_POP_NUM (ps
, priv
->selected_profile
);
683 BUFFER_POP_NUM (ps
, priv
->mki_received
);
684 if (priv
->mki_received
)
686 BUFFER_POP_NUM (ps
, priv
->mki_size
);
687 BUFFER_POP (ps
, priv
->mki
, priv
->mki_size
);