static int setup_dtls_srtp(struct ast_sip_session *session, struct ast_sip_session_media *session_media) { struct ast_rtp_engine_dtls *dtls; if (!session->endpoint->media.rtp.dtls_cfg.enabled || !session_media->rtp) { return -1; } dtls = ast_rtp_instance_get_dtls(session_media->rtp); if (!dtls) { return -1; } session->endpoint->media.rtp.dtls_cfg.suite = ((session->endpoint->media.rtp.srtp_tag_32) ? AST_AES_CM_128_HMAC_SHA1_32 : AST_AES_CM_128_HMAC_SHA1_80); if (dtls->set_configuration(session_media->rtp, &session->endpoint->media.rtp.dtls_cfg)) { ast_log(LOG_ERROR, "Attempted to set an invalid DTLS-SRTP configuration on RTP instance '%p'\n", session_media->rtp); return -1; } if (setup_srtp(session_media)) { return -1; } return 0; }
static int parse_dtls_attrib(struct ast_sip_session_media *session_media, const struct pjmedia_sdp_media *stream) { int i; struct ast_rtp_engine_dtls *dtls = ast_rtp_instance_get_dtls(session_media->rtp); for (i = 0; i < stream->attr_count; i++) { pjmedia_sdp_attr *attr = stream->attr[i]; pj_str_t *value; if (!attr->value.ptr) { continue; } value = pj_strtrim(&attr->value); if (!pj_strcmp2(&attr->name, "setup")) { if (!pj_stricmp2(value, "active")) { dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTIVE); } else if (!pj_stricmp2(value, "passive")) { dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_PASSIVE); } else if (!pj_stricmp2(value, "actpass")) { dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_ACTPASS); } else if (!pj_stricmp2(value, "holdconn")) { dtls->set_setup(session_media->rtp, AST_RTP_DTLS_SETUP_HOLDCONN); } else { ast_log(LOG_WARNING, "Unsupported setup attribute value '%*s'\n", (int)value->slen, value->ptr); } } else if (!pj_strcmp2(&attr->name, "connection")) { if (!pj_stricmp2(value, "new")) { dtls->reset(session_media->rtp); } else if (!pj_stricmp2(value, "existing")) { /* Do nothing */ } else { ast_log(LOG_WARNING, "Unsupported connection attribute value '%*s'\n", (int)value->slen, value->ptr); } } else if (!pj_strcmp2(&attr->name, "fingerprint")) { char hash_value[256], hash[32]; char fingerprint_text[value->slen + 1]; ast_copy_pj_str(fingerprint_text, value, sizeof(fingerprint_text)); if (sscanf(fingerprint_text, "%31s %255s", hash, hash_value) == 2) { if (!strcasecmp(hash, "sha-1")) { dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1, hash_value); } else if (!strcasecmp(hash, "sha-256")) { dtls->set_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA256, hash_value); } else { ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s'\n", hash); } } } } ast_set_flag(session_media->srtp, AST_SRTP_CRYPTO_OFFER_OK); return 0; }
char *ast_sdp_get_rtp_profile(unsigned int sdes_active, struct ast_rtp_instance *instance, unsigned int using_avpf, unsigned int force_avp) { struct ast_rtp_engine_dtls *dtls; if ((dtls = ast_rtp_instance_get_dtls(instance)) && dtls->active(instance)) { if (force_avp) { return using_avpf ? "RTP/SAVPF" : "RTP/SAVP"; } else { return using_avpf ? "UDP/TLS/RTP/SAVPF" : "UDP/TLS/RTP/SAVP"; } } else { if (using_avpf) { return sdes_active ? "RTP/SAVPF" : "RTP/AVPF"; } else { return sdes_active ? "RTP/SAVP" : "RTP/AVP"; } } }
static int add_crypto_to_stream(struct ast_sip_session *session, struct ast_sip_session_media *session_media, pj_pool_t *pool, pjmedia_sdp_media *media) { pj_str_t stmp; pjmedia_sdp_attr *attr; enum ast_rtp_dtls_hash hash; const char *crypto_attribute; struct ast_rtp_engine_dtls *dtls; static const pj_str_t STR_NEW = { "new", 3 }; static const pj_str_t STR_EXISTING = { "existing", 8 }; static const pj_str_t STR_ACTIVE = { "active", 6 }; static const pj_str_t STR_PASSIVE = { "passive", 7 }; static const pj_str_t STR_ACTPASS = { "actpass", 7 }; static const pj_str_t STR_HOLDCONN = { "holdconn", 8 }; switch (session_media->encryption) { case AST_SIP_MEDIA_ENCRYPT_NONE: case AST_SIP_MEDIA_TRANSPORT_INVALID: break; case AST_SIP_MEDIA_ENCRYPT_SDES: if (!session_media->srtp) { session_media->srtp = ast_sdp_srtp_alloc(); if (!session_media->srtp) { return -1; } } crypto_attribute = ast_sdp_srtp_get_attrib(session_media->srtp, 0 /* DTLS running? No */, session->endpoint->media.rtp.srtp_tag_32 /* 32 byte tag length? */); if (!crypto_attribute) { /* No crypto attribute to add, bad news */ return -1; } attr = pjmedia_sdp_attr_create(pool, "crypto", pj_cstr(&stmp, crypto_attribute)); media->attr[media->attr_count++] = attr; break; case AST_SIP_MEDIA_ENCRYPT_DTLS: if (setup_dtls_srtp(session, session_media)) { return -1; } dtls = ast_rtp_instance_get_dtls(session_media->rtp); if (!dtls) { return -1; } switch (dtls->get_connection(session_media->rtp)) { case AST_RTP_DTLS_CONNECTION_NEW: attr = pjmedia_sdp_attr_create(pool, "connection", &STR_NEW); media->attr[media->attr_count++] = attr; break; case AST_RTP_DTLS_CONNECTION_EXISTING: attr = pjmedia_sdp_attr_create(pool, "connection", &STR_EXISTING); media->attr[media->attr_count++] = attr; break; default: break; } switch (dtls->get_setup(session_media->rtp)) { case AST_RTP_DTLS_SETUP_ACTIVE: attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTIVE); media->attr[media->attr_count++] = attr; break; case AST_RTP_DTLS_SETUP_PASSIVE: attr = pjmedia_sdp_attr_create(pool, "setup", &STR_PASSIVE); media->attr[media->attr_count++] = attr; break; case AST_RTP_DTLS_SETUP_ACTPASS: attr = pjmedia_sdp_attr_create(pool, "setup", &STR_ACTPASS); media->attr[media->attr_count++] = attr; break; case AST_RTP_DTLS_SETUP_HOLDCONN: attr = pjmedia_sdp_attr_create(pool, "setup", &STR_HOLDCONN); media->attr[media->attr_count++] = attr; break; default: break; } hash = dtls->get_fingerprint_hash(session_media->rtp); crypto_attribute = dtls->get_fingerprint(session_media->rtp); if (crypto_attribute && (hash == AST_RTP_DTLS_HASH_SHA1 || hash == AST_RTP_DTLS_HASH_SHA256)) { RAII_VAR(struct ast_str *, fingerprint, ast_str_create(64), ast_free); if (!fingerprint) { return -1; } if (hash == AST_RTP_DTLS_HASH_SHA1) { ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute); } else { ast_str_set(&fingerprint, 0, "SHA-256 %s", crypto_attribute); } attr = pjmedia_sdp_attr_create(pool, "fingerprint", pj_cstr(&stmp, ast_str_buffer(fingerprint))); media->attr[media->attr_count++] = attr; } break; }