support selective SDES session parameters

pull/110/head
Richard Fuchs 10 years ago
parent d4222375bf
commit 144a451526

@ -345,7 +345,7 @@ The options are described in more detail below.
* --dtls-passive
Enabled the `DTLS=passive` flag for all calls unconditionally.
Enables the `DTLS=passive` flag for all calls unconditionally.
* -d, --delete-delay
@ -776,11 +776,44 @@ Optionally included keys are:
* `DTLS`
Contains a string and influences the behaviour of DTLS-SRTP. Currently the only recognized option
is `passive`, which instructs *rtpengine* to prefer the passive (i.e. server) role for the DTLS
handshake. The default is to take the active (client) role if possible. This is useful in cases where
the SRTP endpoint isn't able to receive or process the DTLS handshake packets, for example when it's
behind NAT or needs to finish ICE processing first.
Contains a string and influences the behaviour of DTLS-SRTP. Possible values are:
- `off` or `no` or `disable`
Prevents *rtpengine* from offering or acceping DTLS-SRTP when otherwise it would. The default
is to offer DTLS-SRTP when encryption is desired and to favour it over SDES when accepting
an offer.
- `passive`
Instructs *rtpengine* to prefer the passive (i.e. server) role for the DTLS
handshake. The default is to take the active (client) role if possible. This is useful in cases
where the SRTP endpoint isn't able to receive or process the DTLS handshake packets, for example
when it's behind NAT or needs to finish ICE processing first.
* `SDES`
A list of strings controlling the behaviour regarding SDES. The default is to offer SDES without any
session parameters when encryption is desired, and to accept it when DTLS-SRTP is unavailable. If two
SDES endpoints are connected to each other, then the default is to offer SDES with the same options
as were received from the other endpoint.
These options can also be put into the `flags` list using a prefix of `SDES-`. All options controlling
SDES session parameters can be used either in all lower case or in all upper case.
- `off` or `no` or `disable`
Prevents *rtpengine* from offering SDES, leaving DTLS-SRTP as the other option.
- `unencrypted_srtp`, `unencrypted_srtcp` and `unauthenticated_srtp`
Enables the respective SDES session parameter (see section 6.3 or RFC 4568). The default is to
copy these options from the offering client, or not to have them enabled if SDES wasn't offered.
- `encrypted_srtp`, `encrypted_srtcp` and `authenticated_srtp`
Negates the respective option. This is useful if one of the session parameters was offered by
an SDES endpoint, but it should not be offered on the far side if this endpoint also speaks SDES.
An example of a complete `offer` request dictionary could be (SDP body abbreviated):

@ -539,9 +539,9 @@ static int __k_srtp_crypt(struct rtpengine_srtp *s, struct crypto_context *c) {
memcpy(s->master_key, c->params.master_key, c->params.crypto_suite->master_key_len);
memcpy(s->master_salt, c->params.master_salt, c->params.crypto_suite->master_salt_len);
if (c->params.unencrypted_srtp)
if (c->params.session_params.unencrypted_srtp)
s->cipher = REC_NULL;
if (c->params.unauthenticated_srtp)
if (c->params.session_params.unauthenticated_srtp)
s->auth_tag_len = 0;
return 0;
@ -2158,10 +2158,21 @@ static void __generate_crypto(const struct sdp_ng_flags *flags, struct call_medi
if (!MEDIA_ISSET(this, INITIALIZED)) {
/* we offer both DTLS and SDES by default */
MEDIA_SET(this, DTLS);
MEDIA_SET(this, SDES);
/* unless this is overridden by flags */
if (!flags->dtls_off)
MEDIA_SET(this, DTLS);
if (!flags->sdes_off)
MEDIA_SET(this, SDES);
else
goto skip_sdes;
}
else {
/* if both SDES and DTLS are supported, we may use the flags to select one
* over the other */
if (MEDIA_ARESET2(this, DTLS, SDES) && flags->dtls_off)
MEDIA_CLEAR(this, DTLS);
/* flags->sdes_off is ignored as we prefer DTLS by default */
/* if we're talking to someone understanding DTLS, then skip the SDES stuff */
if (MEDIA_ISSET(this, DTLS)) {
MEDIA_CLEAR(this, SDES);
@ -2169,17 +2180,19 @@ static void __generate_crypto(const struct sdp_ng_flags *flags, struct call_medi
}
}
/* SDES parameters below */
/* for answer case, otherwise we default to one */
this->sdes_out.tag = cp_in->crypto_suite ? this->sdes_in.tag : 1;
if (other->sdes_in.params.crypto_suite) {
/* SRTP <> SRTP case, copy from other stream */
crypto_params_copy(cp, &other->sdes_in.params);
return;
cp->session_params = cp_in->session_params;
crypto_params_copy(cp, &other->sdes_in.params, (flags->opmode == OP_OFFER) ? 1 : 0);
}
if (cp->crypto_suite)
return;
goto apply_sdes_flags;
cp->crypto_suite = cp_in->crypto_suite;
if (!cp->crypto_suite)
@ -2188,10 +2201,24 @@ static void __generate_crypto(const struct sdp_ng_flags *flags, struct call_medi
cp->crypto_suite->master_key_len);
random_string((unsigned char *) cp->master_salt,
cp->crypto_suite->master_salt_len);
cp->unencrypted_srtp = cp_in->unencrypted_srtp;
cp->unencrypted_srtcp = cp_in->unencrypted_srtcp;
cp->unauthenticated_srtp = cp_in->unauthenticated_srtp;
/* mki = mki_len = 0 */
cp->session_params.unencrypted_srtp = cp_in->session_params.unencrypted_srtp;
cp->session_params.unencrypted_srtcp = cp_in->session_params.unencrypted_srtcp;
cp->session_params.unauthenticated_srtp = cp_in->session_params.unauthenticated_srtp;
apply_sdes_flags:
if (flags->sdes_unencrypted_srtp && flags->opmode == OP_OFFER)
cp_in->session_params.unencrypted_srtp = cp->session_params.unencrypted_srtp = 1;
else if (flags->sdes_encrypted_srtp)
cp_in->session_params.unencrypted_srtp = cp->session_params.unencrypted_srtp = 0;
if (flags->sdes_unencrypted_srtcp && flags->opmode == OP_OFFER)
cp_in->session_params.unencrypted_srtcp = cp->session_params.unencrypted_srtcp = 1;
else if (flags->sdes_encrypted_srtcp)
cp_in->session_params.unencrypted_srtcp = cp->session_params.unencrypted_srtcp = 0;
if (flags->sdes_unauthenticated_srtp && flags->opmode == OP_OFFER)
cp_in->session_params.unauthenticated_srtp = cp->session_params.unauthenticated_srtp = 1;
else if (flags->sdes_authenticated_srtp)
cp_in->session_params.unauthenticated_srtp = cp->session_params.unauthenticated_srtp = 0;
skip_sdes:
;
@ -2478,7 +2505,7 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
SHARED_FLAG_RTCP_MUX | SHARED_FLAG_ASYMMETRIC | SHARED_FLAG_ICE
| SHARED_FLAG_TRICKLE_ICE | SHARED_FLAG_ICE_LITE);
crypto_params_copy(&other_media->sdes_in.params, &sp->crypto);
crypto_params_copy(&other_media->sdes_in.params, &sp->crypto, 1);
other_media->sdes_in.tag = sp->sdes_tag;
if (other_media->sdes_in.params.crypto_suite)
MEDIA_SET(other_media, SDES);

@ -496,6 +496,33 @@ INLINE char *bencode_get_alt(bencode_item_t *i, const char *one, const char *two
return bencode_dictionary_get_str(i, two, out);
}
INLINE void ng_sdes_option(struct sdp_ng_flags *out, bencode_item_t *it, unsigned int strip) {
str s;
if (!bencode_get_str(it, &s))
return;
str_shift(&s, strip);
if (!str_cmp(&s, "no") || !str_cmp(&s, "off") || !str_cmp(&s, "disabled")
|| !str_cmp(&s, "disable"))
out->sdes_off = 1;
else if (!str_cmp(&s, "unencrypted_srtp") || !str_cmp(&s, "UNENCRYPTED_SRTP"))
out->sdes_unencrypted_srtp = 1;
else if (!str_cmp(&s, "unencrypted_srtcp") || !str_cmp(&s, "UNENCRYPTED_SRTCP"))
out->sdes_unencrypted_srtcp = 1;
else if (!str_cmp(&s, "unauthenticated_srtp") || !str_cmp(&s, "UNAUTHENTICATED_SRTP"))
out->sdes_unauthenticated_srtp = 1;
else if (!str_cmp(&s, "encrypted_srtp") || !str_cmp(&s, "ENCRYPTED_SRTP"))
out->sdes_encrypted_srtp = 1;
else if (!str_cmp(&s, "encrypted_srtcp") || !str_cmp(&s, "ENCRYPTED_SRTCP"))
out->sdes_encrypted_srtcp = 1;
else if (!str_cmp(&s, "authenticated_srtp") || !str_cmp(&s, "AUTHENTICATED_SRTP"))
out->sdes_authenticated_srtp = 1;
else
ilog(LOG_WARN, "Unknown 'SDES' flag encountered: '"STR_FORMAT"'",
STR_FMT(&s));
}
static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *input) {
bencode_item_t *list, *it;
int diridx;
@ -508,7 +535,11 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
if ((list = bencode_dictionary_get_expect(input, "flags", BENCODE_LIST))) {
for (it = list->child; it; it = it->sibling) {
if (it->type != BENCODE_STRING)
continue;
str_hyphenate(it);
if (!bencode_strcmp(it, "trust-address"))
out->trust_address = 1;
else if (!bencode_strcmp(it, "SIP-source-address"))
@ -519,6 +550,8 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
out->strict_source = 1;
else if (!bencode_strcmp(it, "media-handover"))
out->media_handover = 1;
else if (it->iov[1].iov_len >= 5 && !memcmp(it->iov[1].iov_base, "SDES-", 5))
ng_sdes_option(out, it, 5);
else
ilog(LOG_WARN, "Unknown flag encountered: '"BENCODE_FORMAT"'",
BENCODE_FMT(it));
@ -568,6 +601,9 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
if (bencode_dictionary_get_str(input, "DTLS", &s)) {
if (!str_cmp(&s, "passive"))
out->dtls_passive = 1;
else if (!str_cmp(&s, "no") || !str_cmp(&s, "off") || !str_cmp(&s, "disabled")
|| !str_cmp(&s, "disable"))
out->dtls_off = 1;
else
ilog(LOG_WARN, "Unknown 'DTLS' flag encountered: '"STR_FORMAT"'",
STR_FMT(&s));
@ -589,6 +625,13 @@ static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *inpu
}
}
/* XXX abstractize the other list walking functions using callbacks */
/* XXX module still needs to support this list */
if ((list = bencode_dictionary_get_expect(input, "SDES", BENCODE_LIST))) {
for (it = list->child; it; it = it->sibling)
ng_sdes_option(out, it, 0);
}
bencode_get_alt(input, "transport-protocol", "transport protocol", &out->transport_protocol_str);
out->transport_protocol = transport_protocol(&out->transport_protocol_str);
bencode_get_alt(input, "media-address", "media address", &out->media_address);

@ -29,7 +29,8 @@ static void pretty_print(bencode_item_t *el, GString *s) {
break;
case BENCODE_LIST:
sep = "[ ";
g_string_append(s, "[ ");
sep = "";
for (chld = el->child; chld; chld = chld->sibling) {
g_string_append(s, sep);
pretty_print(chld, s);
@ -39,7 +40,8 @@ static void pretty_print(bencode_item_t *el, GString *s) {
break;
case BENCODE_DICTIONARY:
sep = "{ ";
g_string_append(s, "{ ");
sep = "";
for (chld = el->child; chld; chld = chld->sibling) {
g_string_append(s, sep);
pretty_print(chld, s);

@ -57,6 +57,12 @@ struct crypto_suite {
const char *dtls_profile_code;
};
struct crypto_session_params {
int unencrypted_srtcp:1,
unencrypted_srtp:1,
unauthenticated_srtp:1;
};
struct crypto_params {
const struct crypto_suite *crypto_suite;
/* we only support one master key for now */
@ -64,9 +70,7 @@ struct crypto_params {
unsigned char master_salt[SRTP_MAX_MASTER_SALT_LEN];
unsigned char *mki;
unsigned int mki_len;
int unencrypted_srtcp:1,
unencrypted_srtp:1,
unauthenticated_srtp:1;
struct crypto_session_params session_params;
};
struct crypto_context {
@ -144,9 +148,17 @@ INLINE void crypto_reset(struct crypto_context *c) {
c->last_index = 0;
c->ssrc = 0;
}
INLINE void crypto_params_copy(struct crypto_params *o, const struct crypto_params *i) {
INLINE void crypto_params_copy(struct crypto_params *o, const struct crypto_params *i, int copy_sp) {
struct crypto_session_params sp;
crypto_params_cleanup(o);
if (!copy_sp)
sp = o->session_params;
*o = *i;
if (!copy_sp)
o->session_params = sp;
if (o->mki_len > 255)
o->mki_len = 0;
if (o->mki_len) {
@ -156,7 +168,7 @@ INLINE void crypto_params_copy(struct crypto_params *o, const struct crypto_para
}
INLINE void crypto_init(struct crypto_context *c, const struct crypto_params *p) {
crypto_cleanup(c);
crypto_params_copy(&c->params, p);
crypto_params_copy(&c->params, p, 1);
}
INLINE int crypto_params_cmp(const struct crypto_params *a, const struct crypto_params *b) {
if (a->crypto_suite != b->crypto_suite)

@ -401,11 +401,11 @@ int rtcp_avp2savp(str *s, struct crypto_context *c) {
if (check_session_keys(c))
return -1;
if (!c->params.unencrypted_srtcp && crypto_encrypt_rtcp(c, rtcp, &payload, c->last_index))
if (!c->params.session_params.unencrypted_srtcp && crypto_encrypt_rtcp(c, rtcp, &payload, c->last_index))
return -1;
idx = (void *) s->s + s->len;
*idx = htonl((c->params.unencrypted_srtcp ? 0ULL : 0x80000000ULL) | c->last_index++);
*idx = htonl((c->params.session_params.unencrypted_srtcp ? 0ULL : 0x80000000ULL) | c->last_index++);
s->len += sizeof(*idx);
to_auth = *s;

@ -201,14 +201,14 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
/* rfc 3711 section 3.1 */
if (!c->params.unencrypted_srtp && crypto_encrypt_rtp(c, rtp, &payload, index))
if (!c->params.session_params.unencrypted_srtp && crypto_encrypt_rtp(c, rtp, &payload, index))
return -1;
to_auth = *s;
rtp_append_mki(s, c);
if (!c->params.unauthenticated_srtp && c->params.crypto_suite->srtp_auth_tag) {
if (!c->params.session_params.unauthenticated_srtp && c->params.crypto_suite->srtp_auth_tag) {
c->params.crypto_suite->hash_rtp(c, s->s + s->len, &to_auth, index);
s->len += c->params.crypto_suite->srtp_auth_tag;
}
@ -230,7 +230,7 @@ int rtp_savp2avp(str *s, struct crypto_context *c) {
index = packet_index(c, rtp);
if (srtp_payloads(&to_auth, &to_decrypt, &auth_tag, NULL,
c->params.unauthenticated_srtp ? 0 : c->params.crypto_suite->srtp_auth_tag,
c->params.session_params.unauthenticated_srtp ? 0 : c->params.crypto_suite->srtp_auth_tag,
c->params.mki_len,
s, &payload))
return -1;
@ -266,7 +266,7 @@ int rtp_savp2avp(str *s, struct crypto_context *c) {
decrypt_idx:
c->last_index = index;
decrypt:
if (!c->params.unencrypted_srtp && crypto_decrypt_rtp(c, rtp, &to_decrypt, index))
if (!c->params.session_params.unencrypted_srtp && crypto_decrypt_rtp(c, rtp, &to_decrypt, index))
return -1;
*s = to_auth;

@ -1245,9 +1245,9 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl
attr->u.crypto.master_key.len);
memcpy(sp->crypto.master_salt, attr->u.crypto.salt.s,
attr->u.crypto.salt.len);
sp->crypto.unencrypted_srtp = attr->u.crypto.unencrypted_srtp;
sp->crypto.unencrypted_srtcp = attr->u.crypto.unencrypted_srtcp;
sp->crypto.unauthenticated_srtp = attr->u.crypto.unauthenticated_srtp;
sp->crypto.session_params.unencrypted_srtp = attr->u.crypto.unencrypted_srtp;
sp->crypto.session_params.unencrypted_srtcp = attr->u.crypto.unencrypted_srtcp;
sp->crypto.session_params.unauthenticated_srtp = attr->u.crypto.unauthenticated_srtp;
}
/* a=sendrecv/sendonly/recvonly/inactive */
@ -1878,11 +1878,11 @@ static void insert_crypto(struct call_media *media, struct sdp_chopper *chop) {
ull |= cp->mki[cp->mki_len - i - 1] << (i * 8);
chopper_append_printf(chop, "|%llu:%u", ull, cp->mki_len);
}
if (cp->unencrypted_srtp)
if (cp->session_params.unencrypted_srtp)
chopper_append_c(chop, " UNENCRYPTED_SRTP");
if (cp->unencrypted_srtcp)
if (cp->session_params.unencrypted_srtcp)
chopper_append_c(chop, " UNENCRYPTED_SRTCP");
if (cp->unauthenticated_srtp)
if (cp->session_params.unauthenticated_srtp)
chopper_append_c(chop, " UNAUTHENTICATED_SRTP");
chopper_append_c(chop, "\r\n");
}

@ -32,7 +32,15 @@ struct sdp_ng_flags {
rtcp_mux_reject:1,
strict_source:1,
media_handover:1,
dtls_passive:1;
dtls_passive:1,
dtls_off:1,
sdes_off:1,
sdes_unencrypted_srtp:1,
sdes_unencrypted_srtcp:1,
sdes_unauthenticated_srtp:1,
sdes_encrypted_srtp:1,
sdes_encrypted_srtcp:1,
sdes_authenticated_srtp:1;
};
struct sdp_chopper {

@ -626,6 +626,25 @@ a=rtpmap:111 opus/48000/2
{
$$dict{'address family'} = $$pr_o{family_str};
$$dict{'transport protocol'} = $$tr_o{name};
if ($$tr_o{name} =~ /SAVP/ && $op eq 'offer') {
my (@opts, @opt);
rand() < .2 and @opt = ('unencrypted_srtp');
rand() < .2 and @opt = ('encrypted_srtp');
rand() < .5 and @opt = ();
push(@opts, @opt);
@opt = ();
rand() < .2 and @opt = ('unencrypted_srtcp');
rand() < .2 and @opt = ('encrypted_srtcp');
rand() < .5 and @opt = ();
push(@opts, @opt);
@opt = ();
rand() < .2 and @opt = ('unauthenticated_srtp');
rand() < .2 and @opt = ('authenticated_srtp');
rand() < .5 and @opt = ();
push(@opts, @opt);
$$dict{SDES} = \@opts;
}
}
#print(Dumper($dict) . "\n\n");

@ -31,10 +31,8 @@ GetOptions(
'sdp-file=s' => \$options{'sdp-file'},
'ICE=s' => \$options{'ICE'},
'DTLS=s' => \$options{'DTLS'},
'rtcp-mux-offer' => \$options{'rtcp-mux-offer'},
'rtcp-mux-demux' => \$options{'rtcp-mux-demux'},
'rtcp-mux-accept' => \$options{'rtcp-mux-accept'},
'rtcp-mux-reject' => \$options{'rtcp-mux-reject'},
'SDES=s@' => \$options{'SDES'},
'rtcp-mux=s@' => \$options{'rtcp-mux'},
'address-family=s' => \$options{'address family'},
'direction=s' => \$options{'direction'},
'force' => \$options{'force'},
@ -57,8 +55,9 @@ for my $x (split(',', 'trust address,symmetric,asymmetric,force,strict source,me
for my $x (split(',', 'origin,session connection')) {
defined($options{'replace-' . $x}) and push(@{$packet{replace}}, $x);
}
for my $x (split(',', 'offer,demux,accept,reject')) {
defined($options{'rtcp-mux-' . $x}) and push(@{$packet{'rtcp-mux'}}, $x);
for my $x (split(',', 'rtcp-mux,SDES')) {
defined($options{$x}) && ref($options{$x}) eq 'ARRAY'
and $packet{$x} = $options{$x};
}
if (defined($options{direction})) {
$options{direction} =~ /(.*),(.*)/ or die;

Loading…
Cancel
Save