I am trying to build an SRTP
to RTP
stream converter and I am having issues getting the Master Key
from the WebRTC peerconnection
I am creating.
From what I understand, with a DES exchange, the key is exchange via the SDP
exchange and is shown in the a=crypto
field. So, this situation seems pretty straight forward(please correct me if I am wrong), but ultimately useless as WebRTC
standardization is now demanding that DES should not be used(only Chrome
supports it now and it may be removed in the future).
For DTLS there is the fingerprint field in the SDP
, is that a hash of the certificate desired to be utilized in the future exchange?[EDIT: After doing some reading, I am thinking that that is not the case] I would think with knowledge of the fingerprint along side the ability to parse through the DTLS packets in the exchange I should be able to grab the Master Key
to decode the SRTP stream, but I am hitting a wall as I do not know where to look or even 100% sure if it is possible.
So, in short, is it even feasible(without getting into the lower C++ API and creating my own implementation of WebRTC
) to decode the SRTP
feed that is created with a WebRTC PeerConnection
in Chrome
and FireFox
(possibly through packet sniffing with the information gleaned from the SDP
exchange)?[EDIT: depressingly, it seems that access to the private part of the key(aka, the master key) is not possible...please correct if I am wrong]
tHere is some code using openssl and libsrtp native api
#define SRTP_MASTER_KEY_KEY_LEN 16
#define SRTP_MASTER_KEY_SALT_LEN 14
static void dtls_srtp_init( struct transport_dtls *dtls )
{
/*
When SRTP mode is in effect, different keys are used for ordinary
DTLS record protection and SRTP packet protection. These keys are
generated using a TLS exporter [RFC5705] to generate
2 * (SRTPSecurityParams.master_key_len +
SRTPSecurityParams.master_salt_len) bytes of data
which are assigned as shown below. The per-association context value
is empty.
client_write_SRTP_master_key[SRTPSecurityParams.master_key_len];
server_write_SRTP_master_key[SRTPSecurityParams.master_key_len];
client_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len];
server_write_SRTP_master_salt[SRTPSecurityParams.master_salt_len];
*/
int code;
err_status_t err;
srtp_policy_t policy;
char dtls_buffer[SRTP_MASTER_KEY_KEY_LEN * 2 + SRTP_MASTER_KEY_SALT_LEN * 2];
char client_write_key[SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN];
char server_write_key[SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN];
size_t offset = 0;
/*
The exporter label for this usage is "EXTRACTOR-dtls_srtp". (The
"EXTRACTOR" prefix is for historical compatibility.)
RFC 5764 4.2. Key Derivation
*/
const char * label = "EXTRACTOR-dtls_srtp";
SRTP_PROTECTION_PROFILE * srtp_profile= SSL_get_selected_srtp_profile( dtls->ssl );
/* SSL_export_keying_material exports a value derived from the master secret,
* as specified in RFC 5705. It writes |olen| bytes to |out| given a label and
* optional context. (Since a zero length context is allowed, the |use_context|
* flag controls whether a context is included.)
*
* It returns 1 on success and zero otherwise.
*/
code = SSL_export_keying_material(dtls->ssl,
dtls_buffer,
sizeof(dtls_buffer),
label,
strlen( label),
NULL,
0,
PJ_FALSE);
memcpy(&client_write_key[0], &dtls_buffer[offset], SRTP_MASTER_KEY_KEY_LEN);
offset += SRTP_MASTER_KEY_KEY_LEN;
memcpy(&server_write_key[0], &dtls_buffer[offset], SRTP_MASTER_KEY_KEY_LEN);
offset += SRTP_MASTER_KEY_KEY_LEN;
memcpy(&client_write_key[SRTP_MASTER_KEY_KEY_LEN], &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN);
offset += SRTP_MASTER_KEY_SALT_LEN;
memcpy(&server_write_key[SRTP_MASTER_KEY_KEY_LEN], &dtls_buffer[offset], SRTP_MASTER_KEY_SALT_LEN);
switch( srtp_profile->id )
{
case SRTP_AES128_CM_SHA1_80:
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
break;
case SRTP_AES128_CM_SHA1_32:
crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp); // rtp is 32,
crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp); // rtcp still 80
break;
default:
assert(0);
}
policy.ssrc.value = 0;
policy.next = NULL;
/* Init transmit direction */
policy.ssrc.type = ssrc_any_outbound;
policy.key = client_write_key;
err = srtp_create(&dtls->srtp_ctx_rx, &policy);
if (err != err_status_ok) {
printf("not working\n");
}
/* Init receive direction */
policy.ssrc.type = ssrc_any_inbound;
policy.key = server_write_key;
err = srtp_create(&dtls->srtp_ctx_tx, &policy);
if (err != err_status_ok) {
printf("not working\n");
}
}