2 * Copyright (C) 2012 Martin Storsjo
3 * Copyright (C) 2012 Free Software Foundation
5 * Author: Martin Storsjo
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 3 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>
24 #include "gnutls_int.h"
25 #include "gnutls_auth.h"
26 #include "gnutls_errors.h"
27 #include "gnutls_num.h"
30 static int _gnutls_srtp_recv_params (gnutls_session_t session
,
33 static int _gnutls_srtp_send_params (gnutls_session_t session
,
34 gnutls_buffer_st
* extdata
);
36 static int _gnutls_srtp_unpack (gnutls_buffer_st
* ps
,
37 extension_priv_data_t
* _priv
);
38 static int _gnutls_srtp_pack (extension_priv_data_t _priv
,
39 gnutls_buffer_st
* ps
);
40 static void _gnutls_srtp_deinit_data (extension_priv_data_t priv
);
43 extension_entry_st ext_mod_srtp
= {
45 .type
= GNUTLS_EXTENSION_SRTP
,
46 .parse_type
= GNUTLS_EXT_APPLICATION
,
48 .recv_func
= _gnutls_srtp_recv_params
,
49 .send_func
= _gnutls_srtp_send_params
,
50 .pack_func
= _gnutls_srtp_pack
,
51 .unpack_func
= _gnutls_srtp_unpack
,
52 .deinit_func
= _gnutls_srtp_deinit_data
,
58 gnutls_srtp_profile_t id
;
59 unsigned int key_length
;
60 unsigned int salt_length
;
63 static const srtp_profile_st profile_names
[] = {
65 "SRTP_AES128_CM_HMAC_SHA1_80",
66 GNUTLS_SRTP_AES128_CM_HMAC_SHA1_80
,
70 "SRTP_AES128_CM_HMAC_SHA1_32",
71 GNUTLS_SRTP_AES128_CM_HMAC_SHA1_32
,
75 "SRTP_NULL_HMAC_SHA1_80",
76 GNUTLS_SRTP_NULL_HMAC_SHA1_80
,
81 GNUTLS_SRTP_NULL_HMAC_SHA1_32
,
90 static const srtp_profile_st
*get_profile (gnutls_srtp_profile_t profile
)
92 const srtp_profile_st
*p
= profile_names
;
93 while (p
->name
!= NULL
)
102 static gnutls_srtp_profile_t
find_profile (const char *str
, const char *end
)
104 const srtp_profile_st
*prof
= profile_names
;
115 while (prof
->name
!= NULL
)
117 if (strlen (prof
->name
) == len
&& !strncmp (str
, prof
->name
, len
))
127 * gnutls_srtp_get_profile_id
128 * @name: The name of the profile to look up
129 * @profile: Will hold the profile id
131 * This function allows you to look up a profile based on a string.
133 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
134 * otherwise a negative error code is returned.
138 int gnutls_srtp_get_profile_id (const char *name
,
139 gnutls_srtp_profile_t
*profile
)
141 *profile
= find_profile (name
, NULL
);
144 return GNUTLS_E_ILLEGAL_PARAMETER
;
149 #define MAX_PROFILES_IN_SRTP_EXTENSION 256
152 * gnutls_srtp_get_profile_name
153 * @profile: The profile to look up a string for
155 * This function allows you to get the corresponding name for a
156 * SRTP protection profile.
158 * Returns: On success, the name of a SRTP profile as a string,
163 const char *gnutls_srtp_get_profile_name (gnutls_srtp_profile_t profile
)
165 const srtp_profile_st
*p
= get_profile(profile
);
174 _gnutls_srtp_recv_params (gnutls_session_t session
,
175 const uint8_t *data
, size_t _data_size
)
179 const uint8_t *p
= data
;
181 ssize_t data_size
= _data_size
;
183 extension_priv_data_t epriv
;
187 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
194 DECR_LENGTH_RET (data_size
, 2, 0);
195 len
= _gnutls_read_uint16 (p
);
198 if (len
+1 > data_size
)
199 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
201 if (session
->security_parameters
.entity
== GNUTLS_SERVER
)
203 if (len
> MAX_PROFILES_IN_SRTP_EXTENSION
*2)
209 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
214 DECR_LEN (data_size
, 2);
215 profile
= _gnutls_read_uint16 (p
);
217 for (i
= 0; i
< priv
->profiles_size
;i
++)
219 if (priv
->profiles
[i
] == profile
)
221 priv
->selected_profile
= profile
;
229 DECR_LEN (data_size
, 1);
233 if (priv
->mki_size
> 0)
235 DECR_LEN (data_size
, priv
->mki_size
);
236 memcpy(priv
->mki
, p
, priv
->mki_size
);
237 priv
->mki_received
= 1;
244 _gnutls_srtp_send_params (gnutls_session_t session
,
245 gnutls_buffer_st
* extdata
)
248 int total_size
= 0, ret
;
250 extension_priv_data_t epriv
;
253 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
260 if (priv
->profiles_size
== 0)
263 if (session
->security_parameters
.entity
== GNUTLS_SERVER
)
265 /* Don't send anything if no matching profile was found */
266 if (priv
->selected_profile
== 0)
269 ret
= _gnutls_buffer_append_prefix(extdata
, 16, 2);
271 return gnutls_assert_val(ret
);
272 ret
= _gnutls_buffer_append_prefix(extdata
, 16, priv
->selected_profile
);
274 return gnutls_assert_val(ret
);
279 ret
= _gnutls_buffer_append_prefix(extdata
, 16, 2 * priv
->profiles_size
);
281 return gnutls_assert_val(ret
);
283 for (i
= 0; i
< priv
->profiles_size
; i
++)
285 ret
= _gnutls_buffer_append_prefix(extdata
, 16, priv
->profiles
[i
]);
287 return gnutls_assert_val(ret
);
289 total_size
= 2 + 2 * priv
->profiles_size
;
293 ret
= _gnutls_buffer_append_data_prefix(extdata
, 8, priv
->mki
, priv
->mki_size
);
295 return gnutls_assert_val(ret
);
297 return total_size
+ 1;
301 * gnutls_srtp_get_selected_profile:
302 * @session: is a #gnutls_session_t structure.
303 * @profile: will hold the profile
305 * This function allows you to get the negotiated SRTP profile.
307 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
308 * otherwise a negative error code is returned.
313 gnutls_srtp_get_selected_profile (gnutls_session_t session
,
314 gnutls_srtp_profile_t
*profile
)
318 extension_priv_data_t epriv
;
321 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
326 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
331 if (priv
->selected_profile
== 0)
333 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
336 *profile
= priv
->selected_profile
;
342 * gnutls_srtp_get_mki:
343 * @session: is a #gnutls_session_t structure.
344 * @mki: will hold the MKI
346 * This function exports the negotiated Master Key Identifier,
347 * received by the peer if any. The returned value in @mki should be
348 * treated as constant and valid only during the session's lifetime.
350 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
351 * otherwise a negative error code is returned.
356 gnutls_srtp_get_mki (gnutls_session_t session
,
361 extension_priv_data_t epriv
;
364 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
367 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
371 if (priv
->mki_received
== 0)
372 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
374 mki
->data
= priv
->mki
;
375 mki
->size
= priv
->mki_size
;
381 * gnutls_srtp_set_mki:
382 * @session: is a #gnutls_session_t structure.
383 * @mki: holds the MKI
385 * This function sets the Master Key Identifier, to be
386 * used by this session (if any).
388 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
389 * otherwise a negative error code is returned.
394 gnutls_srtp_set_mki (gnutls_session_t session
,
395 const gnutls_datum_t
*mki
)
399 extension_priv_data_t epriv
;
402 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
406 priv
= gnutls_calloc (1, sizeof (*priv
));
410 return GNUTLS_E_MEMORY_ERROR
;
413 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
419 if (mki
->size
> 0 && mki
->size
<= sizeof(priv
->mki
))
421 priv
->mki_size
= mki
->size
;
422 memcpy(priv
->mki
, mki
->data
, mki
->size
);
425 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
431 * gnutls_srtp_set_profile:
432 * @session: is a #gnutls_session_t structure.
433 * @profile: is the profile id to add.
435 * This function is to be used by both clients and servers, to declare
436 * what SRTP profiles they support, to negotiate with the peer.
438 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
439 * otherwise a negative error code is returned.
444 gnutls_srtp_set_profile (gnutls_session_t session
,
445 gnutls_srtp_profile_t profile
)
449 extension_priv_data_t epriv
;
452 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
456 priv
= gnutls_calloc (1, sizeof (*priv
));
460 return GNUTLS_E_MEMORY_ERROR
;
463 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
469 if (priv
->profiles_size
< MAX_SRTP_PROFILES
)
470 priv
->profiles_size
++;
471 priv
->profiles
[priv
->profiles_size
- 1] = profile
;
477 * gnutls_srtp_set_profile_direct:
478 * @session: is a #gnutls_session_t structure.
479 * @profiles: is a string that contains the supported SRTP profiles,
480 * separated by colons.
481 * @err_pos: In case of an error this will have the position in the string the error occured, may be NULL.
483 * This function is to be used by both clients and servers, to declare
484 * what SRTP profiles they support, to negotiate with the peer.
486 * Returns: On syntax error %GNUTLS_E_INVALID_REQUEST is returned,
487 * %GNUTLS_E_SUCCESS on success, or an error code.
492 gnutls_srtp_set_profile_direct (gnutls_session_t session
,
493 const char *profiles
, const char **err_pos
)
497 extension_priv_data_t epriv
;
500 gnutls_srtp_profile_t id
;
503 _gnutls_ext_get_session_data (session
, GNUTLS_EXTENSION_SRTP
,
508 priv
= gnutls_calloc (1, sizeof (*priv
));
514 return GNUTLS_E_MEMORY_ERROR
;
523 col
= strchr (profiles
, ':');
524 id
= find_profile (profiles
, col
);
531 return GNUTLS_E_INVALID_REQUEST
;
534 if (priv
->profiles_size
< MAX_SRTP_PROFILES
)
536 priv
->profiles_size
++;
538 priv
->profiles
[priv
->profiles_size
- 1] = id
;
540 } while (col
!= NULL
);
543 _gnutls_ext_set_session_data (session
, GNUTLS_EXTENSION_SRTP
,
550 * gnutls_srtp_get_keys:
551 * @session: is a #gnutls_session_t structure.
552 * @key_material: Space to hold the generated key material
553 * @key_material_size: The maximum size of the key material
554 * @client_key: The master client write key, pointing inside the key material
555 * @server_key: The master server write key, pointing inside the key material
556 * @client_salt: The master client write salt, pointing inside the key material
557 * @server_salt: The master server write salt, pointing inside the key material
559 * This is a helper function to generate the keying material for SRTP.
560 * It requires the space of the key material to be pre-allocated (should be at least
561 * 2x the maximum key size and salt size). The @client_key, @client_salt, @server_key
562 * and @server_salt are convenience datums that point inside the key material. They may
565 * Returns: On success the size of the key material is returned,
566 * otherwise, %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
567 * sufficient, or a negative error code.
572 gnutls_srtp_get_keys (gnutls_session_t session
,
574 unsigned int key_material_size
,
575 gnutls_datum_t
*client_key
,
576 gnutls_datum_t
*client_salt
,
577 gnutls_datum_t
*server_key
,
578 gnutls_datum_t
*server_salt
)
581 const srtp_profile_st
*p
;
582 gnutls_srtp_profile_t profile
;
584 uint8_t *km
= key_material
;
586 ret
= gnutls_srtp_get_selected_profile (session
, &profile
);
588 return gnutls_assert_val(ret
);
590 p
= get_profile(profile
);
592 return gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM
);
594 msize
= 2*(p
->key_length
+p
->salt_length
);
595 if (msize
> key_material_size
)
596 return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER
);
599 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
601 ret
= gnutls_prf(session
, sizeof("EXTRACTOR-dtls_srtp")-1, "EXTRACTOR-dtls_srtp", 0, 0,
602 NULL
, msize
, key_material
);
604 return gnutls_assert_val(ret
);
608 client_key
->data
= km
;
609 client_key
->size
= p
->key_length
;
614 server_key
->data
= km
+ p
->key_length
;
615 server_key
->size
= p
->key_length
;
620 client_salt
->data
= km
+ 2*p
->key_length
;
621 client_salt
->size
= p
->salt_length
;
626 server_salt
->data
= km
+ 2*p
->key_length
+ p
->salt_length
;
627 server_salt
->size
= p
->salt_length
;
634 _gnutls_srtp_deinit_data (extension_priv_data_t priv
)
636 gnutls_free (priv
.ptr
);
640 _gnutls_srtp_pack (extension_priv_data_t epriv
, gnutls_buffer_st
* ps
)
642 srtp_ext_st
*priv
= epriv
.ptr
;
646 BUFFER_APPEND_NUM (ps
, priv
->profiles_size
);
647 for (i
= 0; i
< priv
->profiles_size
; i
++)
649 BUFFER_APPEND_NUM (ps
, priv
->profiles
[i
]);
652 BUFFER_APPEND_NUM (ps
, priv
->mki_received
);
653 if (priv
->mki_received
)
655 BUFFER_APPEND_NUM (ps
, priv
->selected_profile
);
656 BUFFER_APPEND_PFX4 (ps
, priv
->mki
, priv
->mki_size
);
662 _gnutls_srtp_unpack (gnutls_buffer_st
* ps
,
663 extension_priv_data_t
* _priv
)
668 extension_priv_data_t epriv
;
670 priv
= gnutls_calloc (1, sizeof (*priv
));
674 return GNUTLS_E_MEMORY_ERROR
;
677 BUFFER_POP_NUM (ps
, priv
->profiles_size
);
678 for (i
= 0; i
< priv
->profiles_size
; i
++)
680 BUFFER_POP_NUM (ps
, priv
->profiles
[i
]);
682 BUFFER_POP_NUM (ps
, priv
->selected_profile
);
684 BUFFER_POP_NUM (ps
, priv
->mki_received
);
685 if (priv
->mki_received
)
687 BUFFER_POP_NUM (ps
, priv
->mki_size
);
688 BUFFER_POP (ps
, priv
->mki
, priv
->mki_size
);