Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RFC5764 - SRTP key generation during DTLS handshake #361

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/mbedtls/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,17 @@
*/
#define MBEDTLS_SSL_DTLS_HELLO_VERIFY

/**
* \def MBEDTLS_SSL_DTLS_SRTP
*
* Enable support for DTLS-SRTP, RFC5764
*
* Requires: MBEDTLS_SSL_PROTO_DTLS
*
* Comment this to disable support for DTLS-SRTP.
*/
#define MBEDTLS_SSL_DTLS_SRTP

/**
* \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE
*
Expand Down
81 changes: 81 additions & 0 deletions include/mbedtls/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,8 @@

#define MBEDTLS_TLS_EXT_SIG_ALG 13

#define MBEDTLS_TLS_EXT_USE_SRTP 14

#define MBEDTLS_TLS_EXT_ALPN 16

#define MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC 22 /* 0x16 */
Expand All @@ -339,6 +341,14 @@

#define MBEDTLS_TLS_EXT_RENEGOTIATION_INFO 0xFF01

/*
* use_srtp extension protection profiles values as defined in http://www.iana.org/assignments/srtp-protection/srtp-protection.xhtml
*/
#define MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80_IANA_VALUE 0x0001
#define MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32_IANA_VALUE 0x0002
#define MBEDTLS_SRTP_NULL_HMAC_SHA1_80_IANA_VALUE 0x0005
#define MBEDTLS_SRTP_NULL_HMAC_SHA1_32_IANA_VALUE 0x0006

/*
* Size defines
*/
Expand Down Expand Up @@ -538,6 +548,21 @@ typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert;
typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item;
#endif

#if defined(MBEDTLS_SSL_DTLS_SRTP)
/*
* List of SRTP profiles for DTLS-SRTP
*/
typedef enum
{
MBEDTLS_SRTP_UNSET_PROFILE,
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80,
MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32,
MBEDTLS_SRTP_NULL_HMAC_SHA1_80,
MBEDTLS_SRTP_NULL_HMAC_SHA1_32,
}
mbedtls_dtls_srtp_protection_profiles;
#endif /* MBEDTLS_SSL_DTLS_SRTP */

/*
* This structure is used for storing current session data.
*/
Expand Down Expand Up @@ -678,6 +703,14 @@ struct mbedtls_ssl_config
const char **alpn_list; /*!< ordered list of protocols */
#endif

#if defined(MBEDTLS_SSL_DTLS_SRTP)
/*
* use_srtp extension
*/
mbedtls_dtls_srtp_protection_profiles *dtls_srtp_profiles_list; /*!< ordered list of supported srtp profile */
size_t dtls_srtp_profiles_list_len; /*!< number of supported profiles */
#endif /* MBEDTLS_SSL_DTLS_SRTP */

/*
* Numerical settings (int then char)
*/
Expand Down Expand Up @@ -877,6 +910,15 @@ struct mbedtls_ssl_context
const char *alpn_chosen; /*!< negotiated protocol */
#endif

#if defined(MBEDTLS_SSL_DTLS_SRTP)
/*
* use_srtp extension
*/
mbedtls_dtls_srtp_protection_profiles chosen_dtls_srtp_profile; /*!< negotiated SRTP profile */
unsigned char *dtls_srtp_keys; /*!< master keys and master salt for SRTP generated during handshake */
size_t dtls_srtp_keys_len; /*!< length in bytes of master keys and master salt for SRTP generated during handshake */
#endif /* MBEDTLS_SSL_DTLS_SRTP */

/*
* Information for DTLS hello verify
*/
Expand Down Expand Up @@ -1921,6 +1963,45 @@ int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **prot
const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl );
#endif /* MBEDTLS_SSL_ALPN */

#if defined(MBEDTLS_SSL_DTLS_SRTP)
/**
* \brief Set the supported DTLS-SRTP protection profiles.
*
* \param conf SSL configuration
* \param profiles List of supported protection profiles,
* in decreasing preference order.
* \param profiles_number Number of supported profiles.
*
* \return 0 on success, or MBEDTLS_ERR_SSL_BAD_INPUT_DATA.
*/
int mbedtls_ssl_conf_dtls_srtp_protection_profiles( mbedtls_ssl_config *conf, const mbedtls_dtls_srtp_protection_profiles *profiles, size_t profiles_number);

/**
* \brief Get the negotiated DTLS-SRTP Protection Profile.
* This function should be called after the handshake is
* completed.
*
* \param ssl SSL context
*
* \return Protection Profile enum member, MBEDTLS_SRTP_UNSET_PROFILE if no protocol was negotiated.
*/
mbedtls_dtls_srtp_protection_profiles mbedtls_ssl_get_dtls_srtp_protection_profile( const mbedtls_ssl_context *ssl);

/**
* \brief Get the generated DTLS-SRTP key material.
* This function should be called after the handshake is
* completed. It shall returns 80 bytes of key material generated according to RFC5764
*
* \param ssl SSL context
* \param key Buffer to hold the generated key material
* \param key_buffer_len Length in bytes of the key buffer
* \param key_len Actual length of data written in the key buffer
*
* \return 0 on succes, MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if the key buffer is too small to hold the generated key
*/
int mbedtls_ssl_get_dtls_srtp_key_material( const mbedtls_ssl_context *ssl, unsigned char *key, const size_t key_buffer_len, size_t *key_len );
#endif /* MBEDTLS_SSL_DTLS_SRTP */

/**
* \brief Set the maximum supported version sent from the client side
* and/or accepted at the server side
Expand Down
163 changes: 163 additions & 0 deletions library/ssl_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,79 @@ static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl,
}
#endif /* MBEDTLS_SSL_ALPN */

#if defined (MBEDTLS_SSL_DTLS_SRTP)
static void ssl_write_use_srtp_ext( mbedtls_ssl_context *ssl,
unsigned char *buf, size_t *olen )
{
unsigned char *p = buf;
size_t protection_profiles_index = 0;

*olen = 0;

if( (ssl->conf->dtls_srtp_profiles_list == NULL) || (ssl->conf->dtls_srtp_profiles_list_len == 0) )
{
return;
}

MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding use_srtp extension" ) );

*p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_USE_SRTP >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_USE_SRTP ) & 0xFF );

/* RFC5764 section 4.1.1
* uint8 SRTPProtectionProfile[2];
*
* struct {
* SRTPProtectionProfiles SRTPProtectionProfiles;
* opaque srtp_mki<0..255>;
* } UseSRTPData;

* SRTPProtectionProfile SRTPProtectionProfiles<2..2^16-1>;
*
* Note: srtp_mki is not supported
*/

/* Extension length = 2bytes for profiles lenght, ssl->conf->dtls_srtp_profiles_list_len*2 (each profile is 2 bytes length ) + 1 byte for the non implemented srtp_mki vector length (always 0) */
*p++ = (unsigned char)( ( ( 2 + 2*(ssl->conf->dtls_srtp_profiles_list_len) + 1 ) >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( ( 2 + 2*(ssl->conf->dtls_srtp_profiles_list_len) + 1 ) ) & 0xFF );


/* protection profile length: 2*(ssl->conf->dtls_srtp_profiles_list_len) */
*p++ = (unsigned char)( ( ( 2*(ssl->conf->dtls_srtp_profiles_list_len) ) >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( 2*(ssl->conf->dtls_srtp_profiles_list_len) ) & 0xFF );

for( protection_profiles_index=0; protection_profiles_index < ssl->conf->dtls_srtp_profiles_list_len; protection_profiles_index++ )
{
switch (ssl->conf->dtls_srtp_profiles_list[protection_profiles_index]) {
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80:
*p++ = ( ( ( MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80_IANA_VALUE ) >> 8 ) & 0xFF);
*p++ = ( ( MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80_IANA_VALUE ) & 0xFF);
break;
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32:
*p++ = ( ( ( MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32_IANA_VALUE ) >> 8 ) & 0xFF);
*p++ = ( ( MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32_IANA_VALUE ) & 0xFF);
break;
case MBEDTLS_SRTP_NULL_HMAC_SHA1_80:
*p++ = ( ( ( MBEDTLS_SRTP_NULL_HMAC_SHA1_80_IANA_VALUE ) >> 8 ) & 0xFF);
*p++ = ( ( MBEDTLS_SRTP_NULL_HMAC_SHA1_80_IANA_VALUE ) & 0xFF);
break;
case MBEDTLS_SRTP_NULL_HMAC_SHA1_32:
*p++ = ( ( ( MBEDTLS_SRTP_NULL_HMAC_SHA1_32_IANA_VALUE ) >> 8 ) & 0xFF);
*p++ = ( ( MBEDTLS_SRTP_NULL_HMAC_SHA1_32_IANA_VALUE ) & 0xFF);
break;
default:
/* Note: we shall never arrive here as protection profiles is checked by ssl_set_dtls_srtp_protection_profiles function */
MBEDTLS_SSL_DEBUG_MSG( 1, ( "client hello, ignore illegal DTLS-SRTP protection profile %d", ssl->conf->dtls_srtp_profiles_list[protection_profiles_index]) );
break;
}
}

*p++ = 0x00; /* non implemented srtp_mki vector length is always 0 */
/* total extension length: extension type (2 bytes) + extension length (2 bytes) + protection profile length (2 bytes) + 2*nb protection profiles + srtp_mki vector length(1 byte)*/
*olen = 2 + 2 + 2 + 2*(ssl->conf->dtls_srtp_profiles_list_len) + 1;
}
#endif /* MBEDTLS_SSL_DTLS_SRTP */

/*
* Generate random bytes for ClientHello
*/
Expand Down Expand Up @@ -1011,6 +1084,11 @@ static int ssl_write_client_hello( mbedtls_ssl_context *ssl )
ext_len += olen;
#endif

#if defined(MBEDTLS_SSL_DTLS_SRTP)
ssl_write_use_srtp_ext( ssl, p + 2 + ext_len, &olen );
ext_len += olen;
#endif

#if defined(MBEDTLS_SSL_SESSION_TICKETS)
ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen );
ext_len += olen;
Expand Down Expand Up @@ -1313,6 +1391,81 @@ static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl,
}
#endif /* MBEDTLS_SSL_ALPN */

#if defined(MBEDTLS_SSL_DTLS_SRTP)
static int ssl_parse_use_srtp_ext( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
mbedtls_dtls_srtp_protection_profiles server_protection = MBEDTLS_SRTP_UNSET_PROFILE;
size_t i;
uint16_t server_protection_profile_value = 0;

/* If use_srtp is not configured, just ignore the extension */
if( ( ssl->conf->dtls_srtp_profiles_list == NULL ) || ( ssl->conf->dtls_srtp_profiles_list_len == 0 ) )
return( 0 );

/* RFC5764 section 4.1.1
* uint8 SRTPProtectionProfile[2];
*
* struct {
* SRTPProtectionProfiles SRTPProtectionProfiles;
* opaque srtp_mki<0..255>;
* } UseSRTPData;

* SRTPProtectionProfile SRTPProtectionProfiles<2..2^16-1>;
*
* Note: srtp_mki is not supported
*/

/* Length is 5 : one protection profile(2 bytes) + length(2 bytes) and potential srtp_mki which won't be parsed */
if( len < 5 )
return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );

/*
* get the server protection profile
*/
if (((uint16_t)(buf[0]<<8 | buf[1])) != 0x0002) { /* protection profile length must be 0x0002 as we must have only one protection profile in server Hello */
return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
} else {
server_protection_profile_value = buf[2]<<8 | buf[3];
}

/*
* Check we have the server profile in our list
*/
for( i=0; i < ssl->conf->dtls_srtp_profiles_list_len; i++)
{
switch ( server_protection_profile_value ) {
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80_IANA_VALUE:
server_protection = MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_80;
break;
case MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32_IANA_VALUE:
server_protection = MBEDTLS_SRTP_AES128_CM_HMAC_SHA1_32;
break;
case MBEDTLS_SRTP_NULL_HMAC_SHA1_80_IANA_VALUE:
server_protection = MBEDTLS_SRTP_NULL_HMAC_SHA1_80;
break;
case MBEDTLS_SRTP_NULL_HMAC_SHA1_32_IANA_VALUE:
server_protection = MBEDTLS_SRTP_NULL_HMAC_SHA1_32;
break;
default:
server_protection = MBEDTLS_SRTP_UNSET_PROFILE;
break;
}

if (server_protection == ssl->conf->dtls_srtp_profiles_list[i]) {
ssl->chosen_dtls_srtp_profile = ssl->conf->dtls_srtp_profiles_list[i];
return 0;
}
}

/* If we get there, no match was found : server problem, it shall never answer with incompatible profile */
ssl->chosen_dtls_srtp_profile = MBEDTLS_SRTP_UNSET_PROFILE;
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
}
#endif /* MBEDTLS_SSL_DTLS_SRTP */

/*
* Parse HelloVerifyRequest. Only called after verifying the HS type.
*/
Expand Down Expand Up @@ -1800,6 +1953,16 @@ static int ssl_parse_server_hello( mbedtls_ssl_context *ssl )
break;
#endif /* MBEDTLS_SSL_ALPN */

#if defined(MBEDTLS_SSL_DTLS_SRTP)
case MBEDTLS_TLS_EXT_USE_SRTP:
MBEDTLS_SSL_DEBUG_MSG( 3, ( "found use_srtp extension" ) );

if( ( ret = ssl_parse_use_srtp_ext( ssl, ext + 4, ext_size ) ) != 0 )
return( ret );

break;
#endif /* MBEDTLS_SSL_DTLS_SRTP */

default:
MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)",
ext_id ) );
Expand Down
Loading