mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
RTC: refine srtp layer
This commit is contained in:
parent
81d2e10f65
commit
b6ecb0a18f
4 changed files with 181 additions and 165 deletions
|
@ -71,9 +71,6 @@ string gen_random_str(int len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
const int SRTP_MASTER_KEY_KEY_LEN = 16;
|
||||
const int SRTP_MASTER_KEY_SALT_LEN = 14;
|
||||
|
||||
uint64_t SrsNtp::kMagicNtpFractionalUnit = 1ULL << 32;
|
||||
|
||||
SrsNtp::SrsNtp()
|
||||
|
@ -114,13 +111,9 @@ SrsSecurityTransport::SrsSecurityTransport(SrsRtcSession* s)
|
|||
{
|
||||
session_ = s;
|
||||
|
||||
client_key = "";
|
||||
server_key = "";
|
||||
|
||||
srtp_send = NULL;
|
||||
srtp_recv = NULL;
|
||||
|
||||
dtls_ = new SrsDtls((ISrsDtlsCallback*)this);
|
||||
srtp_send = new SrsSRTP();
|
||||
srtp_recv = new SrsSRTP();
|
||||
|
||||
handshake_done = false;
|
||||
}
|
||||
|
@ -133,11 +126,11 @@ SrsSecurityTransport::~SrsSecurityTransport()
|
|||
}
|
||||
|
||||
if (srtp_send) {
|
||||
srtp_dealloc(srtp_send);
|
||||
srs_freep(srtp_send);
|
||||
}
|
||||
|
||||
if (srtp_recv) {
|
||||
srtp_dealloc(srtp_recv);
|
||||
srs_freep(srtp_recv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,189 +193,68 @@ srs_error_t SrsSecurityTransport::srtp_initialize()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server
|
||||
static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp";
|
||||
std::string send_key;
|
||||
std::string recv_key;
|
||||
|
||||
if ((err = dtls_->export_keying_material(material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) != srs_success) {
|
||||
if ((err = dtls_->get_srtp_key(recv_key, send_key)) != srs_success) {
|
||||
return err;
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
std::string client_master_key(reinterpret_cast<char*>(material), SRTP_MASTER_KEY_KEY_LEN);
|
||||
offset += SRTP_MASTER_KEY_KEY_LEN;
|
||||
std::string server_master_key(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_KEY_LEN);
|
||||
offset += SRTP_MASTER_KEY_KEY_LEN;
|
||||
std::string client_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
||||
offset += SRTP_MASTER_KEY_SALT_LEN;
|
||||
std::string server_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
||||
|
||||
client_key = client_master_key + client_master_salt;
|
||||
server_key = server_master_key + server_master_salt;
|
||||
|
||||
if ((err = srtp_send_init()) != srs_success) {
|
||||
if ((err = srtp_send->initialize(send_key, true)) != srs_success) {
|
||||
return srs_error_wrap(err, "srtp send init failed");
|
||||
}
|
||||
|
||||
if ((err = srtp_recv_init()) != srs_success) {
|
||||
if ((err = srtp_recv->initialize(recv_key, false)) != srs_success) {
|
||||
return srs_error_wrap(err, "srtp recv init failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::srtp_send_init()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srtp_policy_t policy;
|
||||
bzero(&policy, sizeof(policy));
|
||||
|
||||
// TODO: Maybe we can use SRTP-GCM in future.
|
||||
// @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701
|
||||
// @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
|
||||
|
||||
policy.ssrc.type = ssrc_any_outbound;
|
||||
|
||||
policy.ssrc.value = 0;
|
||||
// TODO: adjust window_size
|
||||
policy.window_size = 8192;
|
||||
policy.allow_repeat_tx = 1;
|
||||
policy.next = NULL;
|
||||
|
||||
uint8_t *key = new uint8_t[server_key.size()];
|
||||
memcpy(key, server_key.data(), server_key.size());
|
||||
policy.key = key;
|
||||
|
||||
if (srtp_create(&srtp_send, &policy) != srtp_err_status_ok) {
|
||||
srs_freepa(key);
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed");
|
||||
}
|
||||
|
||||
srs_freepa(key);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::srtp_recv_init()
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srtp_policy_t policy;
|
||||
bzero(&policy, sizeof(policy));
|
||||
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
|
||||
|
||||
policy.ssrc.type = ssrc_any_inbound;
|
||||
|
||||
policy.ssrc.value = 0;
|
||||
// TODO: adjust window_size
|
||||
policy.window_size = 8192;
|
||||
policy.allow_repeat_tx = 1;
|
||||
policy.next = NULL;
|
||||
|
||||
uint8_t *key = new uint8_t[client_key.size()];
|
||||
memcpy(key, client_key.data(), client_key.size());
|
||||
policy.key = key;
|
||||
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_create(&srtp_recv, &policy) != srtp_err_status_ok) {
|
||||
srs_freepa(key);
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed");
|
||||
}
|
||||
|
||||
srs_freepa(key);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (srtp_send) {
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect(srtp_send, out_buf, &nb_out_buf) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
if (!srtp_send) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed");
|
||||
}
|
||||
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed");
|
||||
return srtp_send->protect_rtp(out_buf, in_buf, nb_out_buf);
|
||||
}
|
||||
|
||||
// TODO: FIXME: Merge with protect_rtp.
|
||||
srs_error_t SrsSecurityTransport::protect_rtp2(void* rtp_hdr, int* len_ptr)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!srtp_send) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect");
|
||||
}
|
||||
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect(srtp_send, rtp_hdr, len_ptr) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect");
|
||||
}
|
||||
|
||||
return err;
|
||||
return srtp_send->protect_rtp2(rtp_hdr, len_ptr);
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (srtp_recv) {
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
|
||||
srtp_err_status_t r0 = srtp_unprotect(srtp_recv, out_buf, &nb_out_buf);
|
||||
if (r0 != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "unprotect r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
if (!srtp_recv) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed");
|
||||
}
|
||||
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtp unprotect failed");
|
||||
|
||||
return srtp_recv->unprotect_rtp(out_buf, in_buf, nb_out_buf);
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (srtp_send) {
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect_rtcp(srtp_send, out_buf, &nb_out_buf) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
if (!srtp_send) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed");
|
||||
}
|
||||
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed");
|
||||
return srtp_send->protect_rtcp(out_buf, in_buf, nb_out_buf);
|
||||
}
|
||||
|
||||
srs_error_t SrsSecurityTransport::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (srtp_recv) {
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_unprotect_rtcp(srtp_recv, out_buf, &nb_out_buf) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
if (!srtp_recv) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed");
|
||||
}
|
||||
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed");
|
||||
return srtp_recv->unprotect_rtcp(out_buf, in_buf, nb_out_buf);
|
||||
}
|
||||
|
||||
SrsRtcOutgoingInfo::SrsRtcOutgoingInfo()
|
||||
|
|
|
@ -44,9 +44,6 @@
|
|||
#include <vector>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <srtp2/srtp.h>
|
||||
|
||||
class SrsUdpMuxSocket;
|
||||
class SrsConsumer;
|
||||
class SrsStunPacket;
|
||||
|
@ -114,12 +111,8 @@ class SrsSecurityTransport : public ISrsDtlsCallback
|
|||
private:
|
||||
SrsRtcSession* session_;
|
||||
SrsDtls* dtls_;
|
||||
|
||||
std::string client_key;
|
||||
std::string server_key;
|
||||
|
||||
srtp_t srtp_send;
|
||||
srtp_t srtp_recv;
|
||||
SrsSRTP* srtp_send;
|
||||
SrsSRTP* srtp_recv;
|
||||
|
||||
bool handshake_done;
|
||||
public:
|
||||
|
@ -143,8 +136,6 @@ public:
|
|||
virtual srs_error_t write_dtls_data(void* data, int size);
|
||||
private:
|
||||
srs_error_t srtp_initialize();
|
||||
srs_error_t srtp_send_init();
|
||||
srs_error_t srtp_recv_init();
|
||||
};
|
||||
|
||||
// A group of RTP packets for outgoing(send to players).
|
||||
|
|
|
@ -427,13 +427,148 @@ srs_error_t SrsDtls::do_handshake()
|
|||
return handshake();
|
||||
}
|
||||
|
||||
srs_error_t SrsDtls::export_keying_material(unsigned char *out, size_t olen, const char *label, size_t llen, const unsigned char *p, size_t plen, int use_context)
|
||||
const int SRTP_MASTER_KEY_KEY_LEN = 16;
|
||||
const int SRTP_MASTER_KEY_SALT_LEN = 14;
|
||||
srs_error_t SrsDtls::get_srtp_key(std::string& client_key, std::string& server_key)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!SSL_export_keying_material(dtls, out, olen, label, llen, p, plen, use_context)) {
|
||||
unsigned char material[SRTP_MASTER_KEY_LEN * 2] = {0}; // client(SRTP_MASTER_KEY_KEY_LEN + SRTP_MASTER_KEY_SALT_LEN) + server
|
||||
static const string dtls_srtp_lable = "EXTRACTOR-dtls_srtp";
|
||||
if (!SSL_export_keying_material(dtls, material, sizeof(material), dtls_srtp_lable.c_str(), dtls_srtp_lable.size(), NULL, 0, 0)) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "SSL_export_keying_material failed");
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
|
||||
std::string client_master_key(reinterpret_cast<char*>(material), SRTP_MASTER_KEY_KEY_LEN);
|
||||
offset += SRTP_MASTER_KEY_KEY_LEN;
|
||||
std::string server_master_key(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_KEY_LEN);
|
||||
offset += SRTP_MASTER_KEY_KEY_LEN;
|
||||
std::string client_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
||||
offset += SRTP_MASTER_KEY_SALT_LEN;
|
||||
std::string server_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
|
||||
|
||||
client_key = client_master_key + client_master_salt;
|
||||
server_key = server_master_key + server_master_salt;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
SrsSRTP::SrsSRTP()
|
||||
{
|
||||
srtp_ctx = NULL;
|
||||
}
|
||||
|
||||
SrsSRTP::~SrsSRTP()
|
||||
{
|
||||
if (srtp_ctx) {
|
||||
srtp_dealloc(srtp_ctx);
|
||||
}
|
||||
}
|
||||
|
||||
srs_error_t SrsSRTP::initialize(string srtp_key, bool send)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
srtp_policy_t policy;
|
||||
bzero(&policy, sizeof(policy));
|
||||
|
||||
// TODO: Maybe we can use SRTP-GCM in future.
|
||||
// @see https://bugs.chromium.org/p/chromium/issues/detail?id=713701
|
||||
// @see https://groups.google.com/forum/#!topic/discuss-webrtc/PvCbWSetVAQ
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
|
||||
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
|
||||
|
||||
if (send) {
|
||||
policy.ssrc.type = ssrc_any_outbound;
|
||||
} else {
|
||||
policy.ssrc.type = ssrc_any_inbound;
|
||||
}
|
||||
|
||||
|
||||
policy.ssrc.value = 0;
|
||||
// TODO: adjust window_size
|
||||
policy.window_size = 8192;
|
||||
policy.allow_repeat_tx = 1;
|
||||
policy.next = NULL;
|
||||
|
||||
//uint8_t *key = new uint8_t[server_key.size()];
|
||||
//memcpy(key, server_key.data(), server_key.size());
|
||||
uint8_t *key = new uint8_t[srtp_key.size()];
|
||||
memcpy(key, srtp_key.data(), srtp_key.size());
|
||||
policy.key = key;
|
||||
|
||||
if (srtp_create(&srtp_ctx, &policy) != srtp_err_status_ok) {
|
||||
srs_freepa(key);
|
||||
return srs_error_new(ERROR_RTC_SRTP_INIT, "srtp_create failed");
|
||||
}
|
||||
|
||||
srs_freepa(key);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSRTP::protect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect(srtp_ctx, out_buf, &nb_out_buf) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSRTP::protect_rtp2(void* rtp_hdr, int* len_ptr)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect(srtp_ctx, rtp_hdr, len_ptr) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtp protect");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSRTP::unprotect_rtp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
srtp_err_status_t r0 = srtp_unprotect(srtp_ctx, out_buf, &nb_out_buf);
|
||||
if (r0 != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "unprotect r0=%u", r0);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSRTP::protect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_protect_rtcp(srtp_ctx, out_buf, &nb_out_buf) != 0) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_PROTECT, "rtcp protect failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsSRTP::unprotect_rtcp(char* out_buf, const char* in_buf, int& nb_out_buf)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
memcpy(out_buf, in_buf, nb_out_buf);
|
||||
// TODO: FIXME: Wrap error code.
|
||||
if (srtp_unprotect_rtcp(srtp_ctx, out_buf, &nb_out_buf) != srtp_err_status_ok) {
|
||||
return srs_error_new(ERROR_RTC_SRTP_UNPROTECT, "rtcp unprotect failed");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
|
@ -31,6 +31,7 @@
|
|||
class SrsRequest;
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <srtp2/srtp.h>
|
||||
|
||||
class SrsDtlsCertificate
|
||||
{
|
||||
|
@ -93,10 +94,27 @@ public:
|
|||
srs_error_t initialize(SrsRequest* r);
|
||||
srs_error_t do_handshake();
|
||||
srs_error_t on_dtls(char* data, int nb_data);
|
||||
srs_error_t export_keying_material(unsigned char *out, size_t olen, const char *label, size_t llen, const unsigned char *p, size_t plen, int use_context);
|
||||
srs_error_t get_srtp_key(std::string& send_key, std::string& recv_key);
|
||||
private:
|
||||
SSL_CTX* build_dtls_ctx();
|
||||
srs_error_t handshake();
|
||||
};
|
||||
|
||||
class SrsSRTP
|
||||
{
|
||||
private:
|
||||
srtp_t srtp_ctx;
|
||||
public:
|
||||
SrsSRTP();
|
||||
virtual ~SrsSRTP();
|
||||
public:
|
||||
srs_error_t initialize(std::string srtp_key, bool send);
|
||||
public:
|
||||
srs_error_t protect_rtp(char* protected_buf, const char* ori_buf, int& nb_protected_buf);
|
||||
srs_error_t protect_rtp2(void* rtp_hdr, int* len_ptr);
|
||||
srs_error_t unprotect_rtp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf);
|
||||
srs_error_t protect_rtcp(char* protected_buf, const char* ori_buf, int& nb_protected_buf);
|
||||
srs_error_t unprotect_rtcp(char* unprotected_buf, const char* ori_buf, int& nb_unprotected_buf);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue