Beispiel #1
0
static pj_status_t start_srtp(transport_srtp *srtp)
{
    /* Make sure we have the SRTP policies */
    if (srtp_crypto_empty(&srtp->tx_policy_neg) ||
	srtp_crypto_empty(&srtp->rx_policy_neg))
    {
	srtp->bypass_srtp = PJ_TRUE;
	srtp->peer_use = PJMEDIA_SRTP_DISABLED;
	if (srtp->session_inited) {
	    pjmedia_transport_srtp_stop(&srtp->base);
	}

	return PJ_SUCCESS;
    }

    /* Reset probation counts */
    srtp->probation_cnt = PROBATION_CNT_INIT;

    /* Got policy_local & policy_remote, let's initalize the SRTP */

    /* Ticket #1075: media_start() is called whenever media description
     * gets updated, e.g: call hold, however we should restart SRTP only
     * when the SRTP policy settings are updated.
     */
    if (srtp_crypto_cmp(&srtp->tx_policy_neg, &srtp->tx_policy) ||
	srtp_crypto_cmp(&srtp->rx_policy_neg, &srtp->rx_policy))
    {
	pj_status_t status;
	status = pjmedia_transport_srtp_start(&srtp->base,
					      &srtp->tx_policy_neg,
					      &srtp->rx_policy_neg);
	if (status != PJ_SUCCESS)
	    return status;
    }

    srtp->bypass_srtp = PJ_FALSE;

    return PJ_SUCCESS;
}
static pj_status_t transport_media_start(pjmedia_transport *tp,
				         pj_pool_t *pool,
				         const pjmedia_sdp_session *sdp_local,
				         const pjmedia_sdp_session *sdp_remote,
				         unsigned media_index)
{
    struct transport_srtp *srtp = (struct transport_srtp*) tp;
    pjmedia_sdp_media *m_rem, *m_loc;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(tp && pool && sdp_local && sdp_remote, PJ_EINVAL);

    m_rem = sdp_remote->media[media_index];
    m_loc = sdp_local->media[media_index];

    if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP) == 0)
	srtp->peer_use = PJMEDIA_SRTP_MANDATORY;
    else
	srtp->peer_use = PJMEDIA_SRTP_OPTIONAL;

    /* For answerer side, this function will just have to start SRTP */

    /* Check remote media transport & set local media transport
     * based on SRTP usage option.
     */
    if (srtp->offerer_side) {
	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
	    if (pjmedia_sdp_media_find_attr(m_rem, &ID_CRYPTO, NULL)) {
		DEACTIVATE_MEDIA(pool, m_loc);
		return PJMEDIA_SRTP_ESDPINCRYPTO;
	    }
	    goto BYPASS_SRTP;
	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
	    // Regardless the answer's transport type (RTP/AVP or RTP/SAVP),
	    // the answer must be processed through in optional mode.
	    // Please note that at this point transport type is ensured to be
	    // RTP/AVP or RTP/SAVP, see transport_media_create()
	    //if (pj_stricmp(&m_rem->desc.transport, &m_loc->desc.transport)) {
		//DEACTIVATE_MEDIA(pool, m_loc);
		//return PJMEDIA_SDP_EINPROTO;
	    //}
	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
	    if (pj_stricmp(&m_rem->desc.transport, &ID_RTP_SAVP)) {
		DEACTIVATE_MEDIA(pool, m_loc);
		return PJMEDIA_SDP_EINPROTO;
	    }
	}
    }

    if (srtp->offerer_side) {
	/* find supported crypto-suite, get the tag, and assign policy_local */
	pjmedia_srtp_crypto tmp_tx_crypto;
	pj_bool_t has_crypto_attr = PJ_FALSE;
	int rem_tag;

	for (i=0; i<m_rem->attr_count; ++i) {
	    if (pj_stricmp(&m_rem->attr[i]->name, &ID_CRYPTO) != 0)
		continue;

	    /* more than one crypto attribute in media answer */
	    if (has_crypto_attr) {
		DEACTIVATE_MEDIA(pool, m_loc);
		return PJMEDIA_SRTP_ESDPAMBIGUEANS;
	    }

	    has_crypto_attr = PJ_TRUE;

	    status = parse_attr_crypto(srtp->pool, m_rem->attr[i],
				       &tmp_tx_crypto, &rem_tag);
	    if (status != PJ_SUCCESS)
		return status;


	    /* our offer tag is always ordered by setting */
	    if (rem_tag < 1 || rem_tag > (int)srtp->setting.crypto_count) {
		DEACTIVATE_MEDIA(pool, m_loc);
		return PJMEDIA_SRTP_ESDPINCRYPTOTAG;
	    }

	    /* match the crypto name */
	    if (pj_stricmp(&tmp_tx_crypto.name,
		&srtp->setting.crypto[rem_tag-1].name) != 0)
	    {
		DEACTIVATE_MEDIA(pool, m_loc);
		return PJMEDIA_SRTP_ECRYPTONOTMATCH;
	    }

	    srtp->tx_policy_neg = srtp->setting.crypto[rem_tag-1];
	    srtp->rx_policy_neg = tmp_tx_crypto;
	}

	if (srtp->setting.use == PJMEDIA_SRTP_DISABLED) {
	    /* should never reach here */
	    goto BYPASS_SRTP;
	} else if (srtp->setting.use == PJMEDIA_SRTP_OPTIONAL) {
	    if (!has_crypto_attr)
		goto BYPASS_SRTP;
	} else if (srtp->setting.use == PJMEDIA_SRTP_MANDATORY) {
	    if (!has_crypto_attr) {
		DEACTIVATE_MEDIA(pool, m_loc);
		return PJMEDIA_SRTP_ESDPREQCRYPTO;
	    }
	}

	/* At this point, we get valid rx_policy_neg & tx_policy_neg. */
    }

    /* Make sure we have the SRTP policies */
    if (srtp_crypto_empty(&srtp->tx_policy_neg) ||
	srtp_crypto_empty(&srtp->rx_policy_neg))
    {
	goto BYPASS_SRTP;
    }

    /* Reset probation counts */
    srtp->probation_cnt = PROBATION_CNT_INIT;

    /* Got policy_local & policy_remote, let's initalize the SRTP */

    /* Ticket #1075: media_start() is called whenever media description
     * gets updated, e.g: call hold, however we should restart SRTP only
     * when the SRTP policy settings are updated.
     */
    if (srtp_crypto_cmp(&srtp->tx_policy_neg, &srtp->tx_policy) ||
	srtp_crypto_cmp(&srtp->rx_policy_neg, &srtp->rx_policy))
    {
	status = pjmedia_transport_srtp_start(tp,
					      &srtp->tx_policy_neg,
					      &srtp->rx_policy_neg);
	if (status != PJ_SUCCESS)
	    return status;
    }

    srtp->bypass_srtp = PJ_FALSE;

    goto PROPAGATE_MEDIA_START;

BYPASS_SRTP:
    srtp->bypass_srtp = PJ_TRUE;
    srtp->peer_use = PJMEDIA_SRTP_DISABLED;
    if (srtp->session_inited) {
	pjmedia_transport_srtp_stop(tp);
    }

PROPAGATE_MEDIA_START:
    return pjmedia_transport_media_start(srtp->member_tp, pool,
					 sdp_local, sdp_remote,
				         media_index);
}
Beispiel #3
0
static pj_status_t transport_media_start(pjmedia_transport *tp,
				         pj_pool_t *pool,
				         const pjmedia_sdp_session *sdp_local,
				         const pjmedia_sdp_session *sdp_remote,
				         unsigned media_index)
{
    struct transport_srtp *srtp = (struct transport_srtp*) tp;
    pj_status_t last_err_st = PJ_EBUG;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(tp && pool && sdp_local && sdp_remote, PJ_EINVAL);

    status = pjmedia_transport_media_start(srtp->member_tp, pool,
					   sdp_local, sdp_remote,
				           media_index);
    if (status != PJ_SUCCESS || srtp->bypass_srtp)
	return status;

    /* Invoke media_start() of all keying methods */
    for (i=0; i < srtp->keying_cnt; ) {
	status = pjmedia_transport_media_start(srtp->keying[i], pool,
					       sdp_local, sdp_remote,
					       media_index);
	if (status != PJ_SUCCESS) {
	    /* This keying method returns error, remove it */
	    pj_array_erase(srtp->keying, sizeof(srtp->keying[0]),
			   srtp->keying_cnt, i);
	    srtp->keying_cnt--;
	    last_err_st = status;
	    continue;
	}

	if (!srtp_crypto_empty(&srtp->tx_policy_neg) &&
	    !srtp_crypto_empty(&srtp->rx_policy_neg))
	{
	    /* SRTP nego is done, let's destroy any other keying. */
	    unsigned j;
	    for (j = 0; j < srtp->keying_cnt; ++j) {
		if (j != i)
		    pjmedia_transport_close(srtp->keying[j]);
	    }
	    srtp->keying_cnt = 1;
	    srtp->keying[0] = srtp->keying[i];
	    srtp->keying_pending_cnt = 0;
	    break;
	}

	i++;
    }

    /* All keying method failed to process remote SDP? */
    if (srtp->keying_cnt == 0)
	return last_err_st;

    /* If SRTP key is being negotiated, just return now.
     * The keying method should start the SRTP once keying nego is done.
     */
    if (srtp->keying_pending_cnt)
	return PJ_SUCCESS;

    /* Start SRTP */
    status = start_srtp(srtp);

    return status;
}
Beispiel #4
0
static pj_status_t transport_encode_sdp(pjmedia_transport *tp,
					pj_pool_t *sdp_pool,
					pjmedia_sdp_session *sdp_local,
					const pjmedia_sdp_session *sdp_remote,
					unsigned media_index)
{
    struct transport_srtp *srtp = (struct transport_srtp*) tp;
    pj_status_t last_err_st = PJ_EBUG;
    pj_status_t status;
    unsigned i;

    PJ_ASSERT_RETURN(tp && sdp_pool && sdp_local, PJ_EINVAL);

    pj_bzero(&srtp->rx_policy_neg, sizeof(srtp->rx_policy_neg));
    pj_bzero(&srtp->tx_policy_neg, sizeof(srtp->tx_policy_neg));

    srtp->offerer_side = (sdp_remote == NULL);

    status = pjmedia_transport_encode_sdp(srtp->member_tp, sdp_pool,
					  sdp_local, sdp_remote, media_index);
    if (status != PJ_SUCCESS || srtp->bypass_srtp)
	return status;

    /* Invoke encode_sdp() of all keying methods */
    for (i=0; i < srtp->keying_cnt; ) {
	pj_status_t st;
	st = pjmedia_transport_encode_sdp(srtp->keying[i], sdp_pool,
					  sdp_local, sdp_remote,
					  media_index);
	if (st != PJ_SUCCESS) {
	    /* This keying method returns error, remove it */
	    pj_array_erase(srtp->keying, sizeof(srtp->keying[0]),
			   srtp->keying_cnt, i);
	    srtp->keying_cnt--;
	    last_err_st = st;
	    continue;
	}

	if (!srtp_crypto_empty(&srtp->tx_policy_neg) &&
	    !srtp_crypto_empty(&srtp->rx_policy_neg))
	{
	    /* SRTP nego is done, let's destroy any other keying. */
	    unsigned j;
	    for (j = 0; j < srtp->keying_cnt; ++j) {
		if (j != i)
		    pjmedia_transport_close(srtp->keying[j]);
	    }
	    srtp->keying_cnt = 1;
	    srtp->keying[0] = srtp->keying[i];
	    srtp->keying_pending_cnt = 0;
	    break;
	}

	i++;
    }

    /* All keying method failed to process remote SDP? */
    if (srtp->keying_cnt == 0)
	return last_err_st;

    return PJ_SUCCESS;
}