Skip to content

Commit 02cbae1

Browse files
authored
Add SRTP for remote publishers (#3449)
1 parent 39f726f commit 02cbae1

File tree

1 file changed

+182
-12
lines changed

1 file changed

+182
-12
lines changed

src/plugins/janus_videoroom.c

+182-12
Original file line numberDiff line numberDiff line change
@@ -1608,6 +1608,8 @@ room-<unique room ID>: {
16081608
"mcast" : "<multicast group port for receiving RTP packets, if any>",
16091609
"iface" : "<network interface or IP address to bind to, if any (binds to all otherwise)>",
16101610
"port" : <local port for receiving all RTP packets; 0 will bind to a random one (default)>,
1611+
"srtp_suite" : <length of authentication tag (32 or 80); optional>,
1612+
"srtp_crypto" : "<key to use as crypto (base64 encoded key as in SDES); optional>",
16111613
"streams" : [
16121614
{
16131615
"type" : "<type of published stream #1 (audio|video|data)">,
@@ -1657,6 +1659,8 @@ room-<unique room ID>: {
16571659
"secret" : "<password required to edit the room, mandatory if configured in the room>",
16581660
"display" : "<new display name for the remote publisher; optional>",
16591661
"metadata" : <new valid json object of metadata; optional>,
1662+
"srtp_suite" : <length of authentication tag (32 or 80); optional>,
1663+
"srtp_crypto" : "<key to use as crypto (base64 encoded key as in SDES); optional>",
16601664
"streams" : [
16611665
{
16621666
// Same syntax as add_remote_publisher: only needs to
@@ -1713,7 +1717,9 @@ room-<unique room ID>: {
17131717
"host" : "<host address to forward the RTP and data packets to>",
17141718
"host_family" : "<ipv4|ipv6, if we need to resolve the host address to an IP; by default, whatever we get>",
17151719
"port" : <port to forward the packets to>,
1716-
"rtcp_port" : <port to contact to receive RTCP feedback from the recipient; optional, and only for RTP streams, not data>
1720+
"rtcp_port" : <port to contact to receive RTCP feedback from the recipient; optional, and only for RTP streams, not data>,
1721+
"srtp_suite" : <length of authentication tag (32 or 80); optional>,
1722+
"srtp_crypto" : "<key to use as crypto (base64 encoded key as in SDES); optional>"
17171723
}
17181724
\endverbatim
17191725
*
@@ -2194,7 +2200,9 @@ static struct janus_json_parameter publish_remotely_parameters[] = {
21942200
{"host", JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
21952201
{"host_family", JSON_STRING, 0},
21962202
{"port", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE | JANUS_JSON_PARAM_REQUIRED},
2197-
{"rtcp_port", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}
2203+
{"rtcp_port", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
2204+
{"srtp_suite", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
2205+
{"srtp_crypto", JSON_STRING, 0}
21982206
};
21992207
static struct janus_json_parameter unpublish_remotely_parameters[] = {
22002208
{"secret", JSON_STRING, 0},
@@ -2207,13 +2215,17 @@ static struct janus_json_parameter remote_publisher_parameters[] = {
22072215
{"iface", JANUS_JSON_STRING, 0},
22082216
{"port", JANUS_JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
22092217
{"streams", JANUS_JSON_ARRAY, JANUS_JSON_PARAM_REQUIRED},
2210-
{"metadata", JSON_OBJECT, 0}
2218+
{"metadata", JSON_OBJECT, 0},
2219+
{"srtp_suite", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
2220+
{"srtp_crypto", JSON_STRING, 0}
22112221
};
22122222
static struct janus_json_parameter remote_publisher_update_parameters[] = {
22132223
{"secret", JSON_STRING, 0},
22142224
{"display", JANUS_JSON_STRING, 0},
22152225
{"metadata", JSON_OBJECT, 0},
2216-
{"streams", JANUS_JSON_ARRAY, JANUS_JSON_PARAM_REQUIRED}
2226+
{"streams", JANUS_JSON_ARRAY, JANUS_JSON_PARAM_REQUIRED},
2227+
{"srtp_suite", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE},
2228+
{"srtp_crypto", JSON_STRING, 0}
22172229
};
22182230
static struct janus_json_parameter remote_publisher_stream_parameters[] = {
22192231
{"mid", JANUS_JSON_STRING, JANUS_JSON_PARAM_REQUIRED},
@@ -2498,6 +2510,12 @@ typedef struct janus_videoroom_publisher_stream {
24982510
volatile gint need_pli; /* Whether we need to send a PLI later */
24992511
volatile gint sending_pli; /* Whether we're currently sending a PLI */
25002512
gint64 pli_latest; /* Time of latest sent PLI (to avoid flooding) */
2513+
/* Only needed for SRTP support for remote publisher */
2514+
gboolean is_srtp;
2515+
int srtp_suite;
2516+
char *srtp_crypto;
2517+
srtp_t srtp_ctx;
2518+
srtp_policy_t srtp_policy;
25012519
/* Subscriptions to this publisher stream (who's receiving it) */
25022520
GSList *subscribers;
25032521
janus_mutex subscribers_mutex;
@@ -2622,11 +2640,15 @@ typedef struct janus_videoroom_remote_recipient {
26222640
uint16_t port; /* Port this publisher is being relayed to */
26232641
uint16_t rtcp_port; /* RTCP port this publisher is going to latch to */
26242642
gboolean rtcp_added; /* Whether we created an RTCP socket for this remotization */
2643+
/* Only needed for SRTP support for remote publisher */
2644+
int srtp_suite;
2645+
char *srtp_crypto;
26252646
} janus_videoroom_remote_recipient;
26262647
static void janus_videoroom_remote_recipient_free(janus_videoroom_remote_recipient *r) {
26272648
if(r) {
26282649
g_free(r->remote_id);
26292650
g_free(r->host);
2651+
g_free(r->srtp_crypto);
26302652
g_free(r);
26312653
}
26322654
}
@@ -2710,6 +2732,11 @@ static void janus_videoroom_publisher_stream_free(const janus_refcount *ps_ref)
27102732
janus_mutex_destroy(&ps->subscribers_mutex);
27112733
janus_mutex_destroy(&ps->rid_mutex);
27122734
janus_rtp_simulcasting_cleanup(NULL, NULL, ps->rid, NULL);
2735+
if(ps->is_srtp) {
2736+
g_free(ps->srtp_crypto);
2737+
srtp_dealloc(ps->srtp_ctx);
2738+
g_free(ps->srtp_policy.key);
2739+
}
27132740
g_free(ps);
27142741
}
27152742

@@ -7120,6 +7147,22 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
71207147
if(error_code != 0)
71217148
goto prepare_response;
71227149
}
7150+
/* We may need to SRTP-encrypt this stream */
7151+
int srtp_suite = 0;
7152+
const char *srtp_crypto = NULL;
7153+
json_t *s_suite = json_object_get(root, "srtp_suite");
7154+
json_t *s_crypto = json_object_get(root, "srtp_crypto");
7155+
if(s_suite && s_crypto) {
7156+
srtp_suite = json_integer_value(s_suite);
7157+
if(srtp_suite != 32 && srtp_suite != 80) {
7158+
JANUS_LOG(LOG_ERR, "Invalid SRTP suite (%d)\n", srtp_suite);
7159+
error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT;
7160+
g_snprintf(error_cause, 512, "Invalid SRTP suite (%d)", srtp_suite);
7161+
goto prepare_response;
7162+
}
7163+
srtp_crypto = json_string_value(s_crypto);
7164+
JANUS_LOG(LOG_VERB, "SRTP setting s_suite (%d) and s_crypto (%s) on publish_remotely\n", srtp_suite, srtp_crypto);
7165+
}
71237166
const char *remote_id = json_string_value(json_object_get(root, "remote_id"));
71247167
json_t *pub_id = json_object_get(root, "publisher_id");
71257168
json_t *json_host = json_object_get(root, "host");
@@ -7267,7 +7310,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
72677310
f = janus_videoroom_rtp_forwarder_add_helper(publisher, ps,
72687311
host, port, -1, 0,
72697312
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP),
7270-
FALSE, 0, NULL, 0, FALSE, FALSE);
7313+
FALSE, srtp_suite, srtp_crypto, 0, FALSE, FALSE);
72717314
if(f != NULL)
72727315
f->metadata = g_strdup(remote_id);
72737316
} else if(ps->type == JANUS_VIDEOROOM_MEDIA_VIDEO) {
@@ -7276,7 +7319,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
72767319
f = janus_videoroom_rtp_forwarder_add_helper(publisher, ps,
72777320
host, port, add_rtcp ? rtcp_port : -1, 0,
72787321
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP),
7279-
FALSE, 0, NULL, 0, TRUE, FALSE);
7322+
FALSE, srtp_suite, srtp_crypto, 0, TRUE, FALSE);
72807323
if(f != NULL)
72817324
f->metadata = g_strdup(remote_id);
72827325
if(add_rtcp)
@@ -7286,15 +7329,15 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
72867329
f = janus_videoroom_rtp_forwarder_add_helper(publisher, ps,
72877330
host, port, -1, 0,
72887331
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP + 1),
7289-
FALSE, 0, NULL, 1, TRUE, FALSE);
7332+
FALSE, srtp_suite, srtp_crypto, 1, TRUE, FALSE);
72907333
if(f != NULL)
72917334
f->metadata = g_strdup(remote_id);
72927335
}
72937336
if(ps->vssrc[2] || ps->rid[2]) {
72947337
f = janus_videoroom_rtp_forwarder_add_helper(publisher, ps,
72957338
host, port, -1, 0,
72967339
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP + 2),
7297-
FALSE, 0, NULL, 2, TRUE, FALSE);
7340+
FALSE, srtp_suite, srtp_crypto, 2, TRUE, FALSE);
72987341
if(f != NULL)
72997342
f->metadata = g_strdup(remote_id);
73007343
}
@@ -7316,6 +7359,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
73167359
recipient->port = port;
73177360
recipient->rtcp_port = rtcp_port;
73187361
recipient->rtcp_added = rtcp_added;
7362+
recipient->srtp_suite = srtp_suite;
7363+
recipient->srtp_crypto = srtp_crypto ? g_strdup(srtp_crypto) : NULL;
73197364
g_hash_table_insert(publisher->remote_recipients, g_strdup(remote_id), recipient);
73207365
/* Done */
73217366
janus_mutex_unlock(&publisher->rtp_forwarders_mutex);
@@ -7592,6 +7637,22 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
75927637
}
75937638
}
75947639
}
7640+
/* We may need to SRTP-decrypt this stream */
7641+
int srtp_suite = 0;
7642+
const char *srtp_crypto = NULL;
7643+
json_t *s_suite = json_object_get(root, "srtp_suite");
7644+
json_t *s_crypto = json_object_get(root, "srtp_crypto");
7645+
if(s_suite && s_crypto) {
7646+
srtp_suite = json_integer_value(s_suite);
7647+
if(srtp_suite != 32 && srtp_suite != 80) {
7648+
JANUS_LOG(LOG_ERR, "Invalid SRTP suite (%d)\n", srtp_suite);
7649+
error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT;
7650+
g_snprintf(error_cause, 512, "Invalid SRTP suite (%d)", srtp_suite);
7651+
goto prepare_response;
7652+
}
7653+
srtp_crypto = json_string_value(s_crypto);
7654+
JANUS_LOG(LOG_VERB, "SRTP setting s_suite (%d) and s_crypto (%s) on add_remote_publisher\n", srtp_suite, srtp_crypto);
7655+
}
75957656
if(error_code != 0)
75967657
goto prepare_response;
75977658
/* Now access the room */
@@ -7772,6 +7833,45 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
77727833
gboolean disabled = json_is_true(json_object_get(s, "disabled"));
77737834
/* Create a publisher stream */
77747835
ps = g_malloc0(sizeof(janus_videoroom_publisher_stream));
7836+
if(mtype == JANUS_VIDEOROOM_MEDIA_AUDIO || mtype == JANUS_VIDEOROOM_MEDIA_VIDEO) {
7837+
/* First of all, let's check if we need to setup an SRTP for remote publisher */
7838+
if(srtp_suite > 0 && srtp_crypto != NULL) {
7839+
JANUS_LOG(LOG_VERB, "enabling SRTP crypto (%s) for stream.\n", srtp_crypto);
7840+
gsize len = 0;
7841+
guchar *srtp_crypto_decoded = g_base64_decode(srtp_crypto, &len);
7842+
if(len < SRTP_MASTER_LENGTH) {
7843+
/* Something went wrong */
7844+
g_free(srtp_crypto_decoded);
7845+
JANUS_LOG(LOG_ERR, "Invalid SRTP crypto (%s), disabling stream\n", srtp_crypto);
7846+
ps->is_srtp = FALSE;
7847+
disabled = TRUE;
7848+
} else {
7849+
/* Set SRTP policy */
7850+
srtp_policy_t *policy = &ps->srtp_policy;
7851+
srtp_crypto_policy_set_rtp_default(&policy->rtp);
7852+
if(srtp_suite == 32) {
7853+
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy->rtp);
7854+
} else if(srtp_suite == 80) {
7855+
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy->rtp);
7856+
}
7857+
policy->ssrc.type = ssrc_any_inbound;
7858+
policy->key = srtp_crypto_decoded;
7859+
policy->next = NULL;
7860+
/* Create SRTP context */
7861+
srtp_err_status_t res = srtp_create(&ps->srtp_ctx, policy);
7862+
if(res == srtp_err_status_ok) {
7863+
ps->is_srtp = TRUE;
7864+
ps->srtp_suite = srtp_suite;
7865+
ps->srtp_crypto = g_strdup(srtp_crypto);
7866+
} else {
7867+
/* Something went wrong... */
7868+
JANUS_LOG(LOG_ERR, "Error creating SRTP context: %d (%s), disabling stream\n", res, janus_srtp_error_str(res));
7869+
ps->is_srtp = FALSE;
7870+
disabled = TRUE;
7871+
}
7872+
}
7873+
}
7874+
}
77757875
ps->type = mtype;
77767876
ps->mindex = mindex;
77777877
char mid[5];
@@ -7974,6 +8074,22 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
79748074
}
79758075
}
79768076
}
8077+
/* We may need to SRTP-decrypt this stream */
8078+
int srtp_suite = 0;
8079+
const char *srtp_crypto = NULL;
8080+
json_t *s_suite = json_object_get(root, "srtp_suite");
8081+
json_t *s_crypto = json_object_get(root, "srtp_crypto");
8082+
if(s_suite && s_crypto) {
8083+
srtp_suite = json_integer_value(s_suite);
8084+
if(srtp_suite != 32 && srtp_suite != 80) {
8085+
JANUS_LOG(LOG_ERR, "Invalid SRTP suite (%d)\n", srtp_suite);
8086+
error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT;
8087+
g_snprintf(error_cause, 512, "Invalid SRTP suite (%d)", srtp_suite);
8088+
goto prepare_response;
8089+
}
8090+
srtp_crypto = json_string_value(s_crypto);
8091+
JANUS_LOG(LOG_VERB, "SRTP setting s_suite (%d) and s_crypto (%s) on add_remote_publisher\n", srtp_suite, srtp_crypto);
8092+
}
79778093
if(error_code != 0)
79788094
goto prepare_response;
79798095
/* Now access the room */
@@ -8061,6 +8177,46 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi
80618177
gboolean disabled = json_is_true(json_object_get(s, "disabled"));
80628178
/* Create a publisher stream */
80638179
ps = g_malloc0(sizeof(janus_videoroom_publisher_stream));
8180+
if(mtype == JANUS_VIDEOROOM_MEDIA_AUDIO || mtype == JANUS_VIDEOROOM_MEDIA_VIDEO) {
8181+
/* First of all, let's check if we need to setup an SRTP for remote publisher */
8182+
if(srtp_suite > 0 && srtp_crypto != NULL) {
8183+
JANUS_LOG(LOG_VERB, "Enabling SRTP crypto (%s) for stream\n", srtp_crypto);
8184+
gsize len = 0;
8185+
guchar *srtp_crypto_decoded = g_base64_decode(srtp_crypto, &len);
8186+
if(len < SRTP_MASTER_LENGTH) {
8187+
/* Something went wrong */
8188+
g_free(srtp_crypto_decoded);
8189+
JANUS_LOG(LOG_ERR, "Invalid SRTP crypto (%s), disabling stream\n", srtp_crypto);
8190+
disabled = TRUE;
8191+
} else {
8192+
/* Set SRTP policy */
8193+
srtp_policy_t *policy = &ps->srtp_policy;
8194+
srtp_crypto_policy_set_rtp_default(&policy->rtp);
8195+
if(srtp_suite == 32) {
8196+
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy->rtp);
8197+
} else if(srtp_suite == 80) {
8198+
srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy->rtp);
8199+
}
8200+
policy->ssrc.type = ssrc_any_inbound;
8201+
policy->key = srtp_crypto_decoded;
8202+
policy->next = NULL;
8203+
/* Create SRTP context */
8204+
srtp_err_status_t res = srtp_create(&ps->srtp_ctx, policy);
8205+
if(res == srtp_err_status_ok) {
8206+
ps->is_srtp = TRUE;
8207+
ps->srtp_suite = srtp_suite;
8208+
ps->srtp_crypto = g_strdup(srtp_crypto);
8209+
} else {
8210+
/* Something went wrong... */
8211+
JANUS_LOG(LOG_ERR, "Error creating SRTP context: %d (%s), disabling stream\n", res, janus_srtp_error_str(res));
8212+
ps->is_srtp = FALSE;
8213+
disabled = TRUE;
8214+
}
8215+
}
8216+
} else {
8217+
JANUS_LOG(LOG_ERR, "SRTP crypto (%d) (%s) not enabled for stream\n", srtp_suite, srtp_crypto);
8218+
}
8219+
}
80648220
ps->type = mtype;
80658221
ps->mindex = mindex;
80668222
char pmid[5];
@@ -12918,7 +13074,7 @@ static void *janus_videoroom_handler(void *data) {
1291813074
f = janus_videoroom_rtp_forwarder_add_helper(participant, ps,
1291913075
r->host, r->port, -1, 0,
1292013076
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP),
12921-
FALSE, 0, NULL, 0, FALSE, FALSE);
13077+
FALSE, r->srtp_suite, r->srtp_crypto, 0, FALSE, FALSE);
1292213078
if(f != NULL)
1292313079
f->metadata = g_strdup(r->remote_id);
1292413080
} else if(ps->type == JANUS_VIDEOROOM_MEDIA_VIDEO) {
@@ -12927,7 +13083,7 @@ static void *janus_videoroom_handler(void *data) {
1292713083
f = janus_videoroom_rtp_forwarder_add_helper(participant, ps,
1292813084
r->host, r->port, add_rtcp ? r->rtcp_port : -1, 0,
1292913085
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP),
12930-
FALSE, 0, NULL, 0, TRUE, FALSE);
13086+
FALSE, r->srtp_suite, r->srtp_crypto, 0, TRUE, FALSE);
1293113087
if(f != NULL)
1293213088
f->metadata = g_strdup(r->remote_id);
1293313089
if(add_rtcp)
@@ -12937,15 +13093,15 @@ static void *janus_videoroom_handler(void *data) {
1293713093
f = janus_videoroom_rtp_forwarder_add_helper(participant, ps,
1293813094
r->host, r->port, -1, 0,
1293913095
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP + 1),
12940-
FALSE, 0, NULL, 1, TRUE, FALSE);
13096+
FALSE, r->srtp_suite, r->srtp_crypto, 1, TRUE, FALSE);
1294113097
if(f != NULL)
1294213098
f->metadata = g_strdup(r->remote_id);
1294313099
}
1294413100
if(ps->vssrc[2] || ps->rid[2]) {
1294513101
f = janus_videoroom_rtp_forwarder_add_helper(participant, ps,
1294613102
r->host, r->port, -1, 0,
1294713103
(REMOTE_PUBLISHER_BASE_SSRC + ps->mindex*REMOTE_PUBLISHER_SSRC_STEP + 2),
12948-
FALSE, 0, NULL, 2, TRUE, FALSE);
13104+
FALSE, r->srtp_suite, r->srtp_crypto, 2, TRUE, FALSE);
1294913105
if(f != NULL)
1295013106
f->metadata = g_strdup(r->remote_id);
1295113107
}
@@ -13745,6 +13901,20 @@ static void *janus_videoroom_remote_publisher_thread(void *user_data) {
1374513901
janus_videoroom_incoming_data_internal(publisher->session, publisher, &data);
1374613902
continue;
1374713903
}
13904+
/* Is this SRTP? */
13905+
if(ps->is_srtp) {
13906+
int buflen = bytes;
13907+
srtp_err_status_t res = srtp_unprotect(ps->srtp_ctx, buffer, &buflen);
13908+
if(res != srtp_err_status_ok) {
13909+
janus_mutex_unlock(&publisher->streams_mutex);
13910+
guint32 timestamp = ntohl(rtp->timestamp);
13911+
guint16 seq = ntohs(rtp->seq_number);
13912+
JANUS_LOG(LOG_ERR, "[%s] Publisher stream (#%d) SRTP unprotect error: %s (len=%d-->%d, ts=%"SCNu32", seq=%"SCNu16")\n",
13913+
publisher->user_id_str, ps->mindex, janus_srtp_error_str(res), bytes, buflen, timestamp, seq);
13914+
continue;
13915+
}
13916+
bytes = buflen;
13917+
}
1374813918
/* Prepare the RTP packet */
1374913919
pkt.mindex = mindex;
1375013920
pkt.video = (ps->type == JANUS_VIDEOROOM_MEDIA_VIDEO);

0 commit comments

Comments
 (0)