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]; } }