From cab9d895b208721da6c57cdc2ea91d896cd27ba8 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 3 Sep 2018 04:48:01 -0400 Subject: [PATCH] TT#42500 fix only one crypto suite being offered. We should offer all crypto suites that we support. If passing through SDES, we should amend the list of crypto suites with all additional ones that we support that weren't included in the received offer. closes #577 Change-Id: I9b6c16e8eadecf01cdbc8043bd8361e0f683e456 --- daemon/call.c | 197 +++++++++++++++++++++++++++++---------- daemon/call_interfaces.c | 3 +- daemon/crypto.c | 5 +- daemon/redis.c | 82 +++++++++++----- daemon/sdp.c | 72 ++++++++------ include/call.h | 10 +- include/crypto.h | 20 +++- tests/simulator-ng.pl | 22 +++-- 8 files changed, 287 insertions(+), 124 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index c842fea28..558b568a3 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -1014,9 +1014,13 @@ static int __init_stream(struct packet_stream *ps) { if (MEDIA_ISSET(media, SDES)) { for (GList *l = ps->sfds.head; l; l = l->next) { struct stream_fd *sfd = l->data; - crypto_init(&sfd->crypto, &media->sdes_in.params); + struct crypto_params_sdes *cps = media->sdes_in.head + ? media->sdes_in.head->data : NULL; + crypto_init(&sfd->crypto, cps ? &cps->params : NULL); } - crypto_init(&ps->crypto, &media->sdes_out.params); + struct crypto_params_sdes *cps = media->sdes_out.head + ? media->sdes_out.head->data : NULL; + crypto_init(&ps->crypto, cps ? &cps->params : NULL); } if (MEDIA_ISSET(media, DTLS) && !PS_ISSET(ps, FALLBACK_RTCP)) { @@ -1214,14 +1218,17 @@ static void __ice_offer(const struct sdp_ng_flags *flags, struct call_media *thi static void __generate_crypto(const struct sdp_ng_flags *flags, struct call_media *this, struct call_media *other) { - struct crypto_params *cp = &this->sdes_out.params, - *cp_in = &this->sdes_in.params; + //struct crypto_params *cp = &this->sdes_out.params, + //*cp_in = &this->sdes_in.params; + GQueue *cpq = &this->sdes_out; + GQueue *cpq_in = &this->sdes_in; + GQueue *offered_cpq = &other->sdes_in; if (!flags) return; if (!this->protocol || !this->protocol->srtp || MEDIA_ISSET(this, PASSTHRU)) { - cp->crypto_suite = NULL; + crypto_params_sdes_queue_clear(cpq); /* clear crypto for the this leg b/c we are in passthrough mode */ MEDIA_CLEAR(this, DTLS); MEDIA_CLEAR(this, SDES); @@ -1279,43 +1286,136 @@ 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 */ - 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) - goto apply_sdes_flags; - - cp->crypto_suite = cp_in->crypto_suite; - if (!cp->crypto_suite) - cp->crypto_suite = &crypto_suites[0]; - random_string((unsigned char *) cp->master_key, - cp->crypto_suite->master_key_len); - random_string((unsigned char *) cp->master_salt, - cp->crypto_suite->master_salt_len); - /* 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; + // XXX tests: + // generate all offers + // copy offered suites + // amend offered suites + // ignore suites not supported + // params copy on answer + + if (flags->opmode == OP_OFFER) { + if (!cpq->head) { + // generate a new set of params + // if we were offered some crypto suites, copy those first into our offer + unsigned int c_tag = 1; // tag for next crypto suite generated by us + unsigned long types_offered = 0; + + // make sure our bit field is large enough + assert(num_crypto_suites <= sizeof(types_offered) * 8); + + for (GList *l = offered_cpq->head; l; l = l->next) { + struct crypto_params_sdes *offered_cps = l->data; + + struct crypto_params_sdes *cps = g_slice_alloc0(sizeof(*cps)); + g_queue_push_tail(cpq, cps); + + cps->tag = offered_cps->tag; + // our own offered tags will be higher than the ones we received + if (cps->tag >= c_tag) + c_tag = cps->tag + 1; + crypto_params_copy(&cps->params, &offered_cps->params, 1); + + // we use a bit field to keep track of which types we've seen here + types_offered |= 1 << cps->params.crypto_suite->idx; + } + + // generate crypto suite offers for any types that we haven't seen above + for (unsigned int i = 0; i < num_crypto_suites; i++) { + if ((types_offered & (1 << i))) + continue; + + struct crypto_params_sdes *cps = g_slice_alloc0(sizeof(*cps)); + g_queue_push_tail(cpq, cps); + + cps->tag = c_tag++; + cps->params.crypto_suite = &crypto_suites[i]; + random_string((unsigned char *) cps->params.master_key, + cps->params.crypto_suite->master_key_len); + random_string((unsigned char *) cps->params.master_salt, + cps->params.crypto_suite->master_salt_len); + /* mki = mki_len = 0 */ +// XXX cps->params.session_params.unencrypted_srtp +// XXX = cp_in->session_params.unencrypted_srtp; +// XXX cps->params.session_params.unencrypted_srtcp +// XXX = cp_in->session_params.unencrypted_srtcp; +// XXX cps->params.session_params.unauthenticated_srtp +// XXX = cp_in->session_params.unauthenticated_srtp; + } + } + } + else { + // we pick the first supported crypto suite + struct crypto_params_sdes *cps = cpq->head ? cpq->head->data : NULL; + struct crypto_params_sdes *cps_in = cpq_in->head ? cpq_in->head->data : NULL; + struct crypto_params_sdes *offered_cps = offered_cpq->head ? offered_cpq->head->data : NULL; + if (offered_cps) { + // check if we can do SRTP<>SRTP passthrough. the crypto suite that was accepted + // must have been present in what was offered to us + for (GList *l = cpq_in->head; l; l = l->next) { + struct crypto_params_sdes *check_cps = l->data; + if (check_cps->params.crypto_suite == offered_cps->params.crypto_suite) { + cps_in = check_cps; + break; + } + } + } + if (cps_in && (!cps || cps->params.crypto_suite != cps_in->params.crypto_suite)) { + crypto_params_sdes_queue_clear(cpq); + cps = g_slice_alloc0(sizeof(*cps)); + g_queue_push_tail(cpq, cps); + + cps->tag = cps_in->tag; + cps->params.crypto_suite = cps_in->params.crypto_suite; + if (offered_cps && offered_cps->params.crypto_suite == cps->params.crypto_suite) { + // SRTP<>SRTP passthrough + cps->params.session_params = cps_in->params.session_params; // XXX verify + crypto_params_copy(&cps->params, &offered_cps->params, 1); + } + else { + random_string((unsigned char *) cps->params.master_key, + cps->params.crypto_suite->master_key_len); + random_string((unsigned char *) cps->params.master_salt, + cps->params.crypto_suite->master_salt_len); + /* mki = mki_len = 0 */ + cps->params.session_params = cps_in->params.session_params; +// XXX cps->params.session_params.unencrypted_srtp +// XXX = cp_in->session_params.unencrypted_srtp; +// XXX cps->params.session_params.unencrypted_srtcp +// XXX = cp_in->session_params.unencrypted_srtcp; +// XXX cps->params.session_params.unauthenticated_srtp +// XXX = cp_in->session_params.unauthenticated_srtp; + } + } + } + +// XXX if (cp->crypto_suite) +// XXX goto apply_sdes_flags; // XXX ? + +// cp->crypto_suite = cp_in->crypto_suite; +// if (!cp->crypto_suite) +// cp->crypto_suite = &crypto_suites[0]; +// random_string((unsigned char *) cp->master_key, +// cp->crypto_suite->master_key_len); +// random_string((unsigned char *) cp->master_salt, +// cp->crypto_suite->master_salt_len); +// /* 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; + +// XXXapply_sdes_flags: +// XXX if (flags->sdes_unencrypted_srtp && flags->opmode == OP_OFFER) +// XXX cp_in->session_params.unencrypted_srtp = cp->session_params.unencrypted_srtp = 1; +// XXX else if (flags->sdes_encrypted_srtp) +// XXX cp_in->session_params.unencrypted_srtp = cp->session_params.unencrypted_srtp = 0; +// XXX if (flags->sdes_unencrypted_srtcp && flags->opmode == OP_OFFER) +// XXX cp_in->session_params.unencrypted_srtcp = cp->session_params.unencrypted_srtcp = 1; +// XXX else if (flags->sdes_encrypted_srtcp) +// XXX cp_in->session_params.unencrypted_srtcp = cp->session_params.unencrypted_srtcp = 0; +// XXX if (flags->sdes_unauthenticated_srtp && flags->opmode == OP_OFFER) +// XXX cp_in->session_params.unauthenticated_srtp = cp->session_params.unauthenticated_srtp = 1; +// XXX else if (flags->sdes_authenticated_srtp) +// XXX cp_in->session_params.unauthenticated_srtp = cp->session_params.unauthenticated_srtp = 0; skip_sdes: ; @@ -1637,9 +1737,12 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams, SHARED_FLAG_RTCP_MUX | SHARED_FLAG_ASYMMETRIC | SHARED_FLAG_UNIDIRECTIONAL | SHARED_FLAG_ICE | SHARED_FLAG_TRICKLE_ICE | SHARED_FLAG_ICE_LITE); - 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) + // steal the entire queue of offered crypto params + crypto_params_sdes_queue_clear(&other_media->sdes_in); + other_media->sdes_in = sp->sdes_params; + g_queue_init(&sp->sdes_params); + + if (other_media->sdes_in.length) MEDIA_SET(other_media, SDES); } @@ -2053,8 +2156,8 @@ static void __call_free(void *p) { while (c->medias.head) { md = g_queue_pop_head(&c->medias); - crypto_params_cleanup(&md->sdes_in.params); - crypto_params_cleanup(&md->sdes_out.params); + crypto_params_sdes_queue_clear(&md->sdes_in); + crypto_params_sdes_queue_clear(&md->sdes_out); g_queue_clear(&md->streams); g_queue_clear(&md->endpoint_maps); g_hash_table_destroy(md->codecs_recv); diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index fd7ff4a62..4a65bfd34 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -288,10 +288,9 @@ static void rtp_pt_free(void *p) { static void sp_free(void *p) { struct stream_params *s = p; - if (s->crypto.mki) - free(s->crypto.mki); g_queue_clear_full(&s->rtp_payload_types, rtp_pt_free); ice_candidates_free(&s->ice_candidates); + crypto_params_sdes_queue_clear(&s->sdes_params); g_slice_free1(sizeof(*s), s); } static void streams_free(GQueue *q) { diff --git a/daemon/crypto.c b/daemon/crypto.c index 8dc4f31f3..c3bcb909d 100644 --- a/daemon/crypto.c +++ b/daemon/crypto.c @@ -277,7 +277,7 @@ struct crypto_suite __crypto_suites[] = { }; const struct crypto_suite *crypto_suites = __crypto_suites; -const int num_crypto_suites = G_N_ELEMENTS(__crypto_suites); +const unsigned int num_crypto_suites = G_N_ELEMENTS(__crypto_suites); @@ -726,8 +726,9 @@ void crypto_dump_keys(struct crypto_context *in, struct crypto_context *out) { void crypto_init_main() { struct crypto_suite *cs; - for (int i = 0; i < num_crypto_suites; i++) { + for (unsigned int i = 0; i < num_crypto_suites; i++) { cs = &__crypto_suites[i]; + cs->idx = i; switch(cs->master_key_len) { case 16: cs->lib_cipher_ptr = EVP_aes_128_ecb(); diff --git a/daemon/redis.c b/daemon/redis.c index a7fa9813e..902008f32 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -1037,7 +1037,7 @@ err1: } /* can return 1, 0 or -1 */ -static int redis_hash_get_crypto_params(struct crypto_params *out, const struct redis_hash *h, const char *k) { +static int redis_hash_get_sdes_params1(struct crypto_params *out, const struct redis_hash *h, const char *k) { str s; int i; const char *err; @@ -1078,6 +1078,31 @@ err: rlog(LOG_ERR, "Crypto params error: %s", err); return -1; } +static int redis_hash_get_sdes_params(GQueue *out, const struct redis_hash *h, const char *k) { + char key[32], tagkey[32]; + const char *kk = k; + unsigned int tag; + unsigned int iter = 0; + + while (1) { + snprintf(tagkey, sizeof(tagkey), "%s_tag", kk); + if (redis_hash_get_unsigned(&tag, h, tagkey)) + break; + struct crypto_params_sdes *cps = g_slice_alloc0(sizeof(cps)); + cps->tag = tag; + int ret = redis_hash_get_sdes_params1(&cps->params, h, kk); + if (ret) { + g_slice_free1(sizeof(*cps), cps); + if (ret == 1) + return 0; + return -1; + } + + snprintf(key, sizeof(key), "%s-%u", k, iter++); + kk = key; + } + return 0; +} static int redis_sfds(struct call *c, struct redis_list *sfds) { unsigned int i; @@ -1259,16 +1284,13 @@ static int json_medias(struct call *c, struct redis_list *medias, JsonReader *ro med->logical_intf = get_logical_interface(NULL, med->desired_family, 0); } - if (redis_hash_get_unsigned(&med->sdes_in.tag, rh, "sdes_in_tag")) - return -1; - if (redis_hash_get_unsigned(&med->sdes_out.tag, rh, "sdes_out_tag")) - return -1; if (redis_hash_get_unsigned((unsigned int *) &med->media_flags, rh, "media_flags")) return -1; - if (redis_hash_get_crypto_params(&med->sdes_in.params, rh, "sdes_in") < 0) + + if (redis_hash_get_sdes_params(&med->sdes_in, rh, "sdes_in") < 0) return -1; - if (redis_hash_get_crypto_params(&med->sdes_out.params, rh, "sdes_out") < 0) + if (redis_hash_get_sdes_params(&med->sdes_out, rh, "sdes_out") < 0) return -1; json_build_list_cb(NULL, c, "payload_types", i, NULL, rbl_cb_plts_r, med, root_reader); @@ -1750,25 +1772,37 @@ err: #define JSON_SET_SIMPLE_CSTR(a,d) JSON_SET_SIMPLE_LEN(a, strlen(d), d) #define JSON_SET_SIMPLE_STR(a,d) JSON_SET_SIMPLE_LEN(a, (d)->len, (d)->s) -static int json_update_crypto_params(JsonBuilder *builder, const char *pref, +static int json_update_sdes_params(JsonBuilder *builder, const char *pref, unsigned int unique_id, - const char *key, const struct crypto_params *p) + const char *k, GQueue *q) { char tmp[2048]; + unsigned int iter = 0; + char keybuf[32]; + const char *key = k; - if (!p->crypto_suite) - return -1; + for (GList *l = q->head; l; l = l->next) { + struct crypto_params_sdes *cps = l->data; + struct crypto_params *p = &cps->params; - JSON_SET_NSTRING_CSTR("%s-crypto_suite",key,p->crypto_suite->name); - JSON_SET_NSTRING_LEN("%s-master_key",key, sizeof(p->master_key), (char *) p->master_key); - JSON_SET_NSTRING_LEN("%s-master_salt",key, sizeof(p->master_salt), (char *) p->master_salt); + if (!p->crypto_suite) + return -1; + + JSON_SET_NSTRING("%s_tag", key, "%u", cps->tag); + JSON_SET_NSTRING_CSTR("%s-crypto_suite",key,p->crypto_suite->name); + JSON_SET_NSTRING_LEN("%s-master_key",key, sizeof(p->master_key), (char *) p->master_key); + JSON_SET_NSTRING_LEN("%s-master_salt",key, sizeof(p->master_salt), (char *) p->master_salt); - JSON_SET_NSTRING("%s-unenc-srtp",key,"%i",p->session_params.unencrypted_srtp); - JSON_SET_NSTRING("%s-unenc-srtcp",key,"%i",p->session_params.unencrypted_srtcp); - JSON_SET_NSTRING("%s-unauth-srtp",key,"%i",p->session_params.unauthenticated_srtp); + JSON_SET_NSTRING("%s-unenc-srtp",key,"%i",p->session_params.unencrypted_srtp); + JSON_SET_NSTRING("%s-unenc-srtcp",key,"%i",p->session_params.unencrypted_srtcp); + JSON_SET_NSTRING("%s-unauth-srtp",key,"%i",p->session_params.unauthenticated_srtp); + + if (p->mki) { + JSON_SET_NSTRING_LEN("%s-mki",key, p->mki_len, (char *) p->mki); + } - if (p->mki) { - JSON_SET_NSTRING_LEN("%s-mki",key, p->mki_len, (char *) p->mki); + snprintf(keybuf, sizeof(keybuf), "%s-%u", k, iter++); + key = keybuf; } return 0; @@ -1975,16 +2009,14 @@ char* redis_encode_json(struct call *c) { JSON_SET_SIMPLE_STR("type",&media->type); JSON_SET_SIMPLE_CSTR("protocol",media->protocol ? media->protocol->name : ""); JSON_SET_SIMPLE_CSTR("desired_family",media->desired_family ? media->desired_family->rfc_name : ""); - JSON_SET_SIMPLE("sdes_in_tag","%u",media->sdes_in.tag); - JSON_SET_SIMPLE("sdes_out_tag","%u",media->sdes_out.tag); JSON_SET_SIMPLE_STR("logical_intf",&media->logical_intf->name); JSON_SET_SIMPLE("ptime","%i",media->ptime); JSON_SET_SIMPLE("media_flags","%u",media->media_flags); - json_update_crypto_params(builder, "media", media->unique_id, "sdes_in", - &media->sdes_in.params); - json_update_crypto_params(builder, "media", media->unique_id, "sdes_out", - &media->sdes_out.params); + json_update_sdes_params(builder, "media", media->unique_id, "sdes_in", + &media->sdes_in); + json_update_sdes_params(builder, "media", media->unique_id, "sdes_out", + &media->sdes_out); json_update_dtls_fingerprint(builder, "media", media->unique_id, &media->fingerprint); } json_builder_end_object (builder); diff --git a/daemon/sdp.c b/daemon/sdp.c index 8b8572127..d06595cc2 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -1267,24 +1267,28 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl goto error; /* a=crypto */ - attr = attr_get_by_id(&media->attributes, ATTR_CRYPTO); - if (attr) { - sp->crypto.crypto_suite = attr->u.crypto.crypto_suite; - sp->crypto.mki_len = attr->u.crypto.mki_len; - if (sp->crypto.mki_len) { - sp->crypto.mki = malloc(sp->crypto.mki_len); - memcpy(sp->crypto.mki, attr->u.crypto.mki, sp->crypto.mki_len); + GQueue *attrs = attr_list_get_by_id(&media->attributes, ATTR_CRYPTO); + for (GList *ll = attrs ? attrs->head : NULL; ll; ll = ll->next) { + attr = ll->data; + struct crypto_params_sdes *cps = g_slice_alloc0(sizeof(*cps)); + g_queue_push_tail(&sp->sdes_params, cps); + + cps->params.crypto_suite = attr->u.crypto.crypto_suite; + cps->params.mki_len = attr->u.crypto.mki_len; + if (cps->params.mki_len) { + cps->params.mki = malloc(cps->params.mki_len); + memcpy(cps->params.mki, attr->u.crypto.mki, cps->params.mki_len); } - sp->sdes_tag = attr->u.crypto.tag; - assert(sizeof(sp->crypto.master_key) >= attr->u.crypto.master_key.len); - assert(sizeof(sp->crypto.master_salt) >= attr->u.crypto.salt.len); - memcpy(sp->crypto.master_key, attr->u.crypto.master_key.s, + cps->tag = attr->u.crypto.tag; + assert(sizeof(cps->params.master_key) >= attr->u.crypto.master_key.len); + assert(sizeof(cps->params.master_salt) >= attr->u.crypto.salt.len); + memcpy(cps->params.master_key, attr->u.crypto.master_key.s, attr->u.crypto.master_key.len); - memcpy(sp->crypto.master_salt, attr->u.crypto.salt.s, + memcpy(cps->params.master_salt, attr->u.crypto.salt.s, attr->u.crypto.salt.len); - 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; + cps->params.session_params.unencrypted_srtp = attr->u.crypto.unencrypted_srtp; + cps->params.session_params.unencrypted_srtcp = attr->u.crypto.unencrypted_srtcp; + cps->params.session_params.unauthenticated_srtp = attr->u.crypto.unauthenticated_srtp; } /* a=sendrecv/sendonly/recvonly/inactive */ @@ -1910,44 +1914,50 @@ static void insert_dtls(struct call_media *media, struct sdp_chopper *chop) { chopper_append_c(chop, "\r\n"); } -static void insert_crypto(struct call_media *media, struct sdp_chopper *chop) { +static void insert_crypto1(struct call_media *media, struct sdp_chopper *chop, struct crypto_params_sdes *cps) { char b64_buf[((SRTP_MAX_MASTER_KEY_LEN + SRTP_MAX_MASTER_SALT_LEN) / 3 + 1) * 4 + 4]; char *p; int state = 0, save = 0, i; - struct crypto_params *cp = &media->sdes_out.params; unsigned long long ull; - if (!cp->crypto_suite || !MEDIA_ISSET(media, SDES) || MEDIA_ISSET(media, PASSTHRU)) + if (!cps->params.crypto_suite || !MEDIA_ISSET(media, SDES) || MEDIA_ISSET(media, PASSTHRU)) return; p = b64_buf; - p += g_base64_encode_step((unsigned char *) cp->master_key, - cp->crypto_suite->master_key_len, 0, + p += g_base64_encode_step((unsigned char *) cps->params.master_key, + cps->params.crypto_suite->master_key_len, 0, p, &state, &save); - p += g_base64_encode_step((unsigned char *) cp->master_salt, - cp->crypto_suite->master_salt_len, 0, + p += g_base64_encode_step((unsigned char *) cps->params.master_salt, + cps->params.crypto_suite->master_salt_len, 0, p, &state, &save); p += g_base64_encode_close(0, p, &state, &save); + // truncate trailing == + while (p > b64_buf && p[-1] == '=') + p--; chopper_append_c(chop, "a=crypto:"); - chopper_append_printf(chop, "%u ", media->sdes_out.tag); - chopper_append_c(chop, cp->crypto_suite->name); + chopper_append_printf(chop, "%u ", cps->tag); + chopper_append_c(chop, cps->params.crypto_suite->name); chopper_append_c(chop, " inline:"); chopper_append(chop, b64_buf, p - b64_buf); - if (cp->mki_len) { + if (cps->params.mki_len) { ull = 0; - for (i = 0; i < cp->mki_len && i < sizeof(ull); i++) - ull |= (unsigned long long) cp->mki[cp->mki_len - i - 1] << (i * 8); - chopper_append_printf(chop, "|%llu:%u", ull, cp->mki_len); + for (i = 0; i < cps->params.mki_len && i < sizeof(ull); i++) + ull |= (unsigned long long) cps->params.mki[cps->params.mki_len - i - 1] << (i * 8); + chopper_append_printf(chop, "|%llu:%u", ull, cps->params.mki_len); } - if (cp->session_params.unencrypted_srtp) + if (cps->params.session_params.unencrypted_srtp) chopper_append_c(chop, " UNENCRYPTED_SRTP"); - if (cp->session_params.unencrypted_srtcp) + if (cps->params.session_params.unencrypted_srtcp) chopper_append_c(chop, " UNENCRYPTED_SRTCP"); - if (cp->session_params.unauthenticated_srtp) + if (cps->params.session_params.unauthenticated_srtp) chopper_append_c(chop, " UNAUTHENTICATED_SRTP"); chopper_append_c(chop, "\r\n"); } +static void insert_crypto(struct call_media *media, struct sdp_chopper *chop) { + for (GList *l = media->sdes_out.head; l; l = l->next) + insert_crypto1(media, chop, l->data); +} /* called with call->master_lock held in W */ diff --git a/include/call.h b/include/call.h index ad966d746..3a1aa3e88 100644 --- a/include/call.h +++ b/include/call.h @@ -232,8 +232,7 @@ struct stream_params { struct endpoint rtcp_endpoint; unsigned int consecutive_ports; const struct transport_protocol *protocol; - struct crypto_params crypto; - unsigned int sdes_tag; + GQueue sdes_params; // slice-alloc'd str direction[2]; sockfamily_t *desired_family; struct dtls_fingerprint fingerprint; @@ -321,12 +320,7 @@ struct call_media { struct ice_agent *ice_agent; - struct { - struct crypto_params params; - unsigned int tag; - } sdes_in, - sdes_out; - + GQueue sdes_in, sdes_out; struct dtls_fingerprint fingerprint; /* as received */ GQueue streams; /* normally RTP + RTCP */ diff --git a/include/crypto.h b/include/crypto.h index d0663fb83..9c0e0d939 100644 --- a/include/crypto.h +++ b/include/crypto.h @@ -55,8 +55,9 @@ struct crypto_suite { hash_func_rtcp hash_rtcp; session_key_init_func session_key_init; session_key_cleanup_func session_key_cleanup; - const char *dtls_profile_code; + //const char *dtls_profile_code; // unused const void *lib_cipher_ptr; + unsigned int idx; // filled in during crypto_init_main() }; struct crypto_session_params { @@ -75,6 +76,11 @@ struct crypto_params { struct crypto_session_params session_params; }; +struct crypto_params_sdes { + struct crypto_params params; + unsigned int tag; +}; + struct crypto_context { struct crypto_params params; @@ -92,7 +98,7 @@ struct crypto_context { extern const struct crypto_suite *crypto_suites; -extern const int num_crypto_suites; +extern const unsigned int num_crypto_suites; @@ -166,7 +172,8 @@ 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, 1); + if (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) @@ -185,6 +192,13 @@ INLINE int crypto_params_cmp(const struct crypto_params *a, const struct crypto_ return 1; return 0; } +INLINE void crypto_params_sdes_free(struct crypto_params_sdes *cps) { + crypto_params_cleanup(&cps->params); + g_slice_free1(sizeof(*cps), cps); +} +INLINE void crypto_params_sdes_queue_clear(GQueue *q) { + g_queue_clear_full(q, (GDestroyNotify) crypto_params_sdes_free); +} diff --git a/tests/simulator-ng.pl b/tests/simulator-ng.pl index 144328df7..2dd6d29b5 100755 --- a/tests/simulator-ng.pl +++ b/tests/simulator-ng.pl @@ -366,11 +366,19 @@ sub rtp_savp { sub savp_crypto { my ($sdp, $ctx, $ctx_o) = @_; - my @aa = $sdp =~ /[\r\n]a=crypto:(\d+) (\w+) inline:([\w\/+=]{40,})(?:\|(?:2\^(\d+)|(\d+)))?(?:\|(\d+):(\d+))?(?: (.*?))?[\r\n]/sig; + my @aa = $sdp =~ /[\r\n](?:a=crypto:(\d+) (\w+) inline:([\w\/+=]{40,})(?:\|(?:2\^(\d+)|(\d+)))?(?:\|(\d+):(\d+))?(?: (.*?))?|(m)=.*?)[\r\n]/sig; @aa or die; - my $i = 0; - while (@aa >= 8) { - $$ctx[$i]{in}{crypto_suite} = $NGCP::Rtpclient::SRTP::crypto_suites{$aa[1]} or die; + my $i = -1; + my @done; + while (@aa >= 9) { + if (defined($aa[8]) && $aa[8] eq 'm') { + $i++; + next; + } + $i >= 0 or die; + $done[$i] and next; + + $$ctx[$i]{in}{crypto_suite} = $NGCP::Rtpclient::SRTP::crypto_suites{$aa[1]} or next; $$ctx[$i]{in}{crypto_tag} = $aa[0]; ($$ctx[$i]{in}{rtp_master_key}, $$ctx[$i]{in}{rtp_master_salt}) = NGCP::Rtpclient::SRTP::decode_inline_base64($aa[2], $$ctx[$i]{in}{crypto_suite}); @@ -382,8 +390,10 @@ sub savp_crypto { ($aa[7] || '') =~ /UNENCRYPTED_SRTCP/ and $$ctx[$i]{in}{unenc_srtcp} = 1; ($aa[7] || '') =~ /UNAUTHENTICATED_SRTP/ and $$ctx[$i]{in}{unauth_srtp} = 1; - $i++; - @aa = @aa[8 .. $#aa]; + $done[$i] = 1; + } + continue { + @aa = @aa[9 .. $#aa]; } }