diff options
author | Joshua Colp <jcolp@digium.com> | 2014-06-30 19:51:28 +0000 |
---|---|---|
committer | Joshua Colp <jcolp@digium.com> | 2014-06-30 19:51:28 +0000 |
commit | 6e60f5d317d2bccaa556c98fbcc01d2db5796c1e (patch) | |
tree | 9d2e1bd2d26e584aa31e3b6b019ffe145784a2b2 /res | |
parent | 688bb204dc872aaec9f2b829fe85039c08091b55 (diff) |
Recorded merge of revisions 417677 from http://svn.asterisk.org/svn/asterisk/branches/11
........
res_rtp_asterisk: Add SHA-256 support for DTLS and perform DTLS negotiation on RTCP.
This change fixes up DTLS support in res_rtp_asterisk so it can accept and provide
a SHA-256 fingerprint, so it occurs on RTCP, and so it occurs after ICE negotiation
completes. Configuration options to chan_sip and chan_pjsip have also been added to
allow behavior to be tweaked (such as forcing the AVP type media transports in SDP).
ASTERISK-22961 #close
Reported by: Jay Jideliov
Review: https://reviewboard.asterisk.org/r/3679/
Review: https://reviewboard.asterisk.org/r/3686/
........
Merged revisions 417678 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@417679 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res')
-rw-r--r-- | res/res_pjsip.c | 22 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 2 | ||||
-rw-r--r-- | res/res_pjsip_sdp_rtp.c | 60 | ||||
-rw-r--r-- | res/res_rtp_asterisk.c | 498 |
4 files changed, 407 insertions, 175 deletions
diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 45b8e7e02..b123a3706 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -390,6 +390,28 @@ media offers. </para></description> </configOption> + <configOption name="force_avp" default="no"> + <synopsis>Determines whether res_pjsip will use and enforce usage of AVP, + regardless of the RTP profile in use for this endpoint.</synopsis> + <description><para> + If set to <literal>yes</literal>, res_pjsip will use the AVP, AVPF, SAVP, or + SAVPF RTP profile for all media offers on outbound calls and media updates including + those for DTLS-SRTP streams. + </para><para> + If set to <literal>no</literal>, res_pjsip will use the respective RTP profile + depending on configuration. + </para></description> + </configOption> + <configOption name="media_use_received_transport" default="no"> + <synopsis>Determines whether res_pjsip will use the media transport received in the + offer SDP in the corresponding answer SDP.</synopsis> + <description><para> + If set to <literal>yes</literal>, res_pjsip will use the received media transport. + </para><para> + If set to <literal>no</literal>, res_pjsip will use the respective RTP profile + depending on configuration. + </para></description> + </configOption> <configOption name="media_encryption" default="no"> <synopsis>Determines whether res_pjsip will use and enforce usage of media encryption for this endpoint.</synopsis> diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index b2ce4fe7e..ccd494932 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -1686,6 +1686,8 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_use_received_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_received_transport)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress)); ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 59fa647d9..b7e1eef3d 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -390,14 +390,26 @@ static void process_ice_attributes(struct ast_sip_session *session, struct ast_s return; } - if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL))) { + attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-ufrag", NULL); + if (!attr) { + attr = pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-ufrag", NULL); + } + if (attr) { ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value)); ice->set_authentication(session_media->rtp, attr_value, NULL); + } else { + return; } - if ((attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL))) { + attr = pjmedia_sdp_media_find_attr2(remote_stream, "ice-pwd", NULL); + if (!attr) { + pjmedia_sdp_attr_find2(remote->attr_count, remote->attr, "ice-pwd", NULL); + } + if (attr) { ast_copy_pj_str(attr_value, (pj_str_t*)&attr->value, sizeof(attr_value)); ice->set_authentication(session_media->rtp, NULL, attr_value); + } else { + return; } if (pjmedia_sdp_media_find_attr2(remote_stream, "ice-lite", NULL)) { @@ -452,6 +464,8 @@ static void process_ice_attributes(struct ast_sip_session *session, struct ast_s ice->add_remote_candidate(session_media->rtp, &candidate); } + ice->set_role(session_media->rtp, pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_TRUE ? + AST_RTP_ICE_ROLE_CONTROLLING : AST_RTP_ICE_ROLE_CONTROLLED); ice->start(session_media->rtp); } @@ -529,6 +543,10 @@ static enum ast_sip_session_media_encryption check_endpoint_media_transport( return incoming_encryption; } + if (endpoint->media.rtp.force_avp) { + return incoming_encryption; + } + return AST_SIP_MEDIA_TRANSPORT_INVALID; } @@ -615,13 +633,15 @@ static int parse_dtls_attrib(struct ast_sip_session_media *session_media, 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[6]; + 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, "%5s %255s", hash, hash_value) == 2) { + 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); @@ -710,7 +730,8 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct } /* Ensure incoming transport is compatible with the endpoint's configuration */ - if (check_endpoint_media_transport(session->endpoint, stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) { + if (!session->endpoint->media.rtp.use_received_transport && + check_endpoint_media_transport(session->endpoint, stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) { return -1; } @@ -727,6 +748,10 @@ static int negotiate_incoming_sdp_stream(struct ast_sip_session *session, struct return -1; } + if (session->endpoint->media.rtp.use_received_transport) { + pj_strdup(session->inv_session->pool, &session_media->transport, &stream->desc.transport); + } + if (setup_media_encryption(session, session_media, stream)) { return -1; } @@ -748,6 +773,7 @@ static int add_crypto_to_stream(struct ast_sip_session *session, { 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 }; @@ -824,13 +850,19 @@ static int add_crypto_to_stream(struct ast_sip_session *session, break; } - if ((crypto_attribute = dtls->get_fingerprint(session_media->rtp, AST_RTP_DTLS_HASH_SHA1))) { + 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; } - ast_str_set(&fingerprint, 0, "SHA-1 %s", crypto_attribute); + 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; @@ -889,9 +921,14 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as } media->desc.media = pj_str(session_media->stream_type); - media->desc.transport = pj_str(ast_sdp_get_rtp_profile( - session->endpoint->media.rtp.encryption == AST_SIP_MEDIA_ENCRYPT_SDES, - session_media->rtp, session->endpoint->media.rtp.use_avpf)); + if (session->endpoint->media.rtp.use_received_transport && pj_strlen(&session_media->transport)) { + media->desc.transport = session_media->transport; + } else { + media->desc.transport = pj_str(ast_sdp_get_rtp_profile( + session->endpoint->media.rtp.encryption == AST_SIP_MEDIA_ENCRYPT_SDES, + session_media->rtp, session->endpoint->media.rtp.use_avpf, + session->endpoint->media.rtp.force_avp)); + } /* Add connection level details */ if (direct_media_enabled) { @@ -1033,7 +1070,8 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, struct a } /* Ensure incoming transport is compatible with the endpoint's configuration */ - if (check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) { + if (!session->endpoint->media.rtp.use_received_transport && + check_endpoint_media_transport(session->endpoint, remote_stream) == AST_SIP_MEDIA_TRANSPORT_INVALID) { return -1; } diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c index 97c09a3a9..a50a80887 100644 --- a/res/res_rtp_asterisk.c +++ b/res/res_rtp_asterisk.c @@ -181,6 +181,16 @@ struct rtp_learning_info { int packets; /*!< The number of remaining packets before the source is accepted */ }; +#ifdef HAVE_OPENSSL_SRTP +struct dtls_details { + SSL *ssl; /*!< SSL session */ + BIO *read_bio; /*!< Memory buffer for reading */ + BIO *write_bio; /*!< Memory buffer for writing */ + enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */ + enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */ +}; +#endif + /*! \brief RTP session description */ struct ast_rtp { int s; @@ -280,19 +290,17 @@ struct ast_rtp { #ifdef HAVE_OPENSSL_SRTP SSL_CTX *ssl_ctx; /*!< SSL context */ - SSL *ssl; /*!< SSL session */ - BIO *read_bio; /*!< Memory buffer for reading */ - BIO *write_bio; /*!< Memory buffer for writing */ ast_mutex_t dtls_timer_lock; /*!< Lock for synchronization purposes */ - enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */ + enum ast_rtp_dtls_verify dtls_verify; /*!< What to verify */ enum ast_srtp_suite suite; /*!< SRTP crypto suite */ + enum ast_rtp_dtls_hash local_hash; /*!< Local hash used for the fingerprint */ char local_fingerprint[160]; /*!< Fingerprint of our certificate */ + enum ast_rtp_dtls_hash remote_hash; /*!< Remote hash used for the fingerprint */ unsigned char remote_fingerprint[EVP_MAX_MD_SIZE]; /*!< Fingerprint of the peer certificate */ - enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */ - unsigned int dtls_failure:1; /*!< Failure occurred during DTLS negotiation */ unsigned int rekey; /*!< Interval at which to renegotiate and rekey */ int rekeyid; /*!< Scheduled item id for rekeying */ int dtlstimerid; /*!< Scheduled item id for DTLS retransmission for RTP */ + struct dtls_details dtls; /*!< DTLS state information */ #endif }; @@ -358,6 +366,10 @@ struct ast_rtcp { /* VP8: sequence number for the RTCP FIR FCI */ int firseq; + +#ifdef HAVE_OPENSSL_SRTP + struct dtls_details dtls; /*!< DTLS state information */ +#endif }; struct rtp_red { @@ -404,7 +416,7 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level); #ifdef HAVE_OPENSSL_SRTP static int ast_rtp_activate(struct ast_rtp_instance *instance); -static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp); +static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp); #endif static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp); @@ -542,9 +554,18 @@ static void ast_rtp_ice_stop(struct ast_rtp_instance *instance) static int ice_reset_session(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + pj_ice_sess_role role = rtp->ice->role; + int res; ast_rtp_ice_stop(instance); - return ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1); + + res = ice_create(instance, &rtp->ice_original_rtp_addr, rtp->ice_port, 1); + if (!res) { + /* Preserve the role that the old ICE session used */ + pj_ice_sess_change_role(rtp->ice, role); + } + + return res; } static int ice_candidates_compare(struct ao2_container *left, struct ao2_container *right) @@ -701,6 +722,20 @@ static void ast_rtp_ice_lite(struct ast_rtp_instance *instance) pj_ice_sess_change_role(rtp->ice, PJ_ICE_SESS_ROLE_CONTROLLING); } +static void ast_rtp_ice_set_role(struct ast_rtp_instance *instance, enum ast_rtp_ice_role role) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + if (!rtp->ice) { + return; + } + + pj_thread_register_check(); + + pj_ice_sess_change_role(rtp->ice, role == AST_RTP_ICE_ROLE_CONTROLLED ? + PJ_ICE_SESS_ROLE_CONTROLLED : PJ_ICE_SESS_ROLE_CONTROLLING); +} + static void ast_rtp_ice_add_cand(struct ast_rtp *rtp, unsigned comp_id, unsigned transport_id, pj_ice_cand_type type, pj_uint16_t local_pref, const pj_sockaddr_t *addr, const pj_sockaddr_t *base_addr, const pj_sockaddr_t *rel_addr, int addr_len) { @@ -781,25 +816,83 @@ static struct ast_rtp_engine_ice ast_rtp_ice = { .get_password = ast_rtp_ice_get_password, .get_local_candidates = ast_rtp_ice_get_local_candidates, .ice_lite = ast_rtp_ice_lite, + .set_role = ast_rtp_ice_set_role, }; #endif #ifdef HAVE_OPENSSL_SRTP -static void dtls_info_callback(const SSL *ssl, int where, int ret) +static int dtls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) +{ + /* We don't want to actually verify the certificate so just accept what they have provided */ + return 1; +} + +static int dtls_details_initialize(struct dtls_details *dtls, SSL_CTX *ssl_ctx, + enum ast_rtp_dtls_setup setup) { - struct ast_rtp *rtp = SSL_get_ex_data(ssl, 0); + dtls->dtls_setup = setup; - /* We only care about alerts */ - if (!(where & SSL_CB_ALERT)) { - return; + if (!(dtls->ssl = SSL_new(ssl_ctx))) { + ast_log(LOG_ERROR, "Failed to allocate memory for SSL\n"); + goto error; + } + + if (!(dtls->read_bio = BIO_new(BIO_s_mem()))) { + ast_log(LOG_ERROR, "Failed to allocate memory for inbound SSL traffic\n"); + goto error; + } + BIO_set_mem_eof_return(dtls->read_bio, -1); + + if (!(dtls->write_bio = BIO_new(BIO_s_mem()))) { + ast_log(LOG_ERROR, "Failed to allocate memory for outbound SSL traffic\n"); + goto error; } + BIO_set_mem_eof_return(dtls->write_bio, -1); + + SSL_set_bio(dtls->ssl, dtls->read_bio, dtls->write_bio); + + if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + SSL_set_accept_state(dtls->ssl); + } else { + SSL_set_connect_state(dtls->ssl); + } + dtls->connection = AST_RTP_DTLS_CONNECTION_NEW; + + return 0; - rtp->dtls_failure = 1; +error: + if (dtls->read_bio) { + BIO_free(dtls->read_bio); + dtls->read_bio = NULL; + } + + if (dtls->write_bio) { + BIO_free(dtls->write_bio); + dtls->write_bio = NULL; + } + + if (dtls->ssl) { + SSL_free(dtls->ssl); + dtls->ssl = NULL; + } + return -1; +} + +static int dtls_setup_rtcp(struct ast_rtp_instance *instance) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + if (!rtp->ssl_ctx || !rtp->rtcp) { + return 0; + } + + return dtls_details_initialize(&rtp->rtcp->dtls, rtp->ssl_ctx, rtp->dtls.dtls_setup); } static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + int res; if (!dtls_cfg->enabled) { return 0; @@ -813,7 +906,11 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con return -1; } - SSL_CTX_set_verify(rtp->ssl_ctx, dtls_cfg->verify ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, NULL); + rtp->dtls_verify = dtls_cfg->verify; + + SSL_CTX_set_verify(rtp->ssl_ctx, (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) || (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_CERTIFICATE) ? + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, !(rtp->dtls_verify & AST_RTP_DTLS_VERIFY_CERTIFICATE) ? + dtls_verify_callback : NULL); if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_80) { SSL_CTX_set_tlsext_use_srtp(rtp->ssl_ctx, "SRTP_AES128_CM_SHA1_80"); @@ -821,13 +918,16 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con SSL_CTX_set_tlsext_use_srtp(rtp->ssl_ctx, "SRTP_AES128_CM_SHA1_32"); } else { ast_log(LOG_ERROR, "Unsupported suite specified for DTLS-SRTP on RTP instance '%p'\n", instance); - goto error; + return -1; } + rtp->local_hash = dtls_cfg->hash; + if (!ast_strlen_zero(dtls_cfg->certfile)) { char *private = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile; BIO *certbio; X509 *cert; + const EVP_MD *type; unsigned int size, i; unsigned char fingerprint[EVP_MAX_MD_SIZE]; char *local_fingerprint = rtp->local_fingerprint; @@ -835,30 +935,40 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con if (!SSL_CTX_use_certificate_file(rtp->ssl_ctx, dtls_cfg->certfile, SSL_FILETYPE_PEM)) { ast_log(LOG_ERROR, "Specified certificate file '%s' for RTP instance '%p' could not be used\n", dtls_cfg->certfile, instance); - goto error; + return -1; } if (!SSL_CTX_use_PrivateKey_file(rtp->ssl_ctx, private, SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(rtp->ssl_ctx)) { ast_log(LOG_ERROR, "Specified private key file '%s' for RTP instance '%p' could not be used\n", private, instance); - goto error; + return -1; } if (!(certbio = BIO_new(BIO_s_file()))) { ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n", instance); - goto error; + return -1; + } + + if (rtp->local_hash == AST_RTP_DTLS_HASH_SHA1) { + type = EVP_sha1(); + } else if (rtp->local_hash == AST_RTP_DTLS_HASH_SHA256) { + type = EVP_sha256(); + } else { + ast_log(LOG_ERROR, "Unsupported fingerprint hash type on RTP instance '%p'\n", + instance); + return -1; } if (!BIO_read_filename(certbio, dtls_cfg->certfile) || !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) || - !X509_digest(cert, EVP_sha1(), fingerprint, &size) || + !X509_digest(cert, type, fingerprint, &size) || !size) { ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n", dtls_cfg->certfile, instance); BIO_free_all(certbio); - goto error; + return -1; } for (i = 0; i < size; i++) { @@ -875,7 +985,7 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con if (!SSL_CTX_set_cipher_list(rtp->ssl_ctx, dtls_cfg->cipher)) { ast_log(LOG_ERROR, "Invalid cipher specified in cipher list '%s' for RTP instance '%p'\n", dtls_cfg->cipher, instance); - goto error; + return -1; } } @@ -883,69 +993,19 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con if (!SSL_CTX_load_verify_locations(rtp->ssl_ctx, S_OR(dtls_cfg->cafile, NULL), S_OR(dtls_cfg->capath, NULL))) { ast_log(LOG_ERROR, "Invalid certificate authority file '%s' or path '%s' specified for RTP instance '%p'\n", S_OR(dtls_cfg->cafile, ""), S_OR(dtls_cfg->capath, ""), instance); - goto error; + return -1; } } rtp->rekey = dtls_cfg->rekey; - rtp->dtls_setup = dtls_cfg->default_setup; rtp->suite = dtls_cfg->suite; - if (!(rtp->ssl = SSL_new(rtp->ssl_ctx))) { - ast_log(LOG_ERROR, "Failed to allocate memory for SSL context on RTP instance '%p'\n", - instance); - goto error; - } - - SSL_set_ex_data(rtp->ssl, 0, rtp); - SSL_set_info_callback(rtp->ssl, dtls_info_callback); - - if (!(rtp->read_bio = BIO_new(BIO_s_mem()))) { - ast_log(LOG_ERROR, "Failed to allocate memory for inbound SSL traffic on RTP instance '%p'\n", - instance); - goto error; - } - BIO_set_mem_eof_return(rtp->read_bio, -1); - - if (!(rtp->write_bio = BIO_new(BIO_s_mem()))) { - ast_log(LOG_ERROR, "Failed to allocate memory for outbound SSL traffic on RTP instance '%p'\n", - instance); - goto error; - } - BIO_set_mem_eof_return(rtp->write_bio, -1); - - SSL_set_bio(rtp->ssl, rtp->read_bio, rtp->write_bio); - - if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { - SSL_set_accept_state(rtp->ssl); - } else { - SSL_set_connect_state(rtp->ssl); - } - - rtp->connection = AST_RTP_DTLS_CONNECTION_NEW; - - return 0; - -error: - if (rtp->read_bio) { - BIO_free(rtp->read_bio); - rtp->read_bio = NULL; - } - - if (rtp->write_bio) { - BIO_free(rtp->write_bio); - rtp->write_bio = NULL; - } - - if (rtp->ssl) { - SSL_free(rtp->ssl); - rtp->ssl = NULL; + res = dtls_details_initialize(&rtp->dtls, rtp->ssl_ctx, dtls_cfg->default_setup); + if (!res) { + dtls_setup_rtcp(instance); } - SSL_CTX_free(rtp->ssl_ctx); - rtp->ssl_ctx = NULL; - - return -1; + return res; } static int ast_rtp_dtls_active(struct ast_rtp_instance *instance) @@ -964,9 +1024,14 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance) rtp->ssl_ctx = NULL; } - if (rtp->ssl) { - SSL_free(rtp->ssl); - rtp->ssl = NULL; + if (rtp->dtls.ssl) { + SSL_free(rtp->dtls.ssl); + rtp->dtls.ssl = NULL; + } + + if (rtp->rtcp && rtp->rtcp->dtls.ssl) { + SSL_free(rtp->rtcp->dtls.ssl); + rtp->rtcp->dtls.ssl = NULL; } } @@ -974,49 +1039,50 @@ static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - /* If the SSL session is not yet finalized don't bother resetting */ - if (!SSL_is_init_finished(rtp->ssl)) { - return; + if (SSL_is_init_finished(rtp->dtls.ssl)) { + SSL_shutdown(rtp->dtls.ssl); + rtp->dtls.connection = AST_RTP_DTLS_CONNECTION_NEW; } - SSL_shutdown(rtp->ssl); - rtp->connection = AST_RTP_DTLS_CONNECTION_NEW; + if (rtp->rtcp && SSL_is_init_finished(rtp->rtcp->dtls.ssl)) { + SSL_shutdown(rtp->rtcp->dtls.ssl); + rtp->rtcp->dtls.connection = AST_RTP_DTLS_CONNECTION_NEW; + } } static enum ast_rtp_dtls_connection ast_rtp_dtls_get_connection(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - return rtp->connection; + return rtp->dtls.connection; } static enum ast_rtp_dtls_setup ast_rtp_dtls_get_setup(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - return rtp->dtls_setup; + return rtp->dtls.dtls_setup; } -static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup) +static void dtls_set_setup(enum ast_rtp_dtls_setup *dtls_setup, enum ast_rtp_dtls_setup setup, SSL *ssl) { - struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - enum ast_rtp_dtls_setup old = rtp->dtls_setup; + enum ast_rtp_dtls_setup old = *dtls_setup; switch (setup) { case AST_RTP_DTLS_SETUP_ACTIVE: - rtp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE; + *dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE; break; case AST_RTP_DTLS_SETUP_PASSIVE: - rtp->dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE; + *dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE; break; case AST_RTP_DTLS_SETUP_ACTPASS: /* We can't respond to an actpass setup with actpass ourselves... so respond with active, as we can initiate connections */ - if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) { - rtp->dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE; + if (*dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) { + *dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE; } break; case AST_RTP_DTLS_SETUP_HOLDCONN: - rtp->dtls_setup = AST_RTP_DTLS_SETUP_HOLDCONN; + *dtls_setup = AST_RTP_DTLS_SETUP_HOLDCONN; break; default: /* This should never occur... if it does exit early as we don't know what state things are in */ @@ -1024,46 +1090,64 @@ static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_r } /* If the setup state did not change we go on as if nothing happened */ - if (old == rtp->dtls_setup) { + if (old == *dtls_setup) { return; } /* If they don't want us to establish a connection wait until later */ - if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_HOLDCONN) { + if (*dtls_setup == AST_RTP_DTLS_SETUP_HOLDCONN) { return; } - if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) { - SSL_set_connect_state(rtp->ssl); - } else if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { - SSL_set_accept_state(rtp->ssl); + if (*dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) { + SSL_set_connect_state(ssl); + } else if (*dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + SSL_set_accept_state(ssl); } else { return; } } +static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + if (rtp->dtls.ssl) { + dtls_set_setup(&rtp->dtls.dtls_setup, setup, rtp->dtls.ssl); + } + + if (rtp->rtcp && rtp->rtcp->dtls.ssl) { + dtls_set_setup(&rtp->rtcp->dtls.dtls_setup, setup, rtp->rtcp->dtls.ssl); + } +} + static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint) { char *tmp = ast_strdupa(fingerprint), *value; int pos = 0; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - if (hash != AST_RTP_DTLS_HASH_SHA1) { + if (hash != AST_RTP_DTLS_HASH_SHA1 && hash != AST_RTP_DTLS_HASH_SHA256) { return; } + rtp->remote_hash = hash; + while ((value = strsep(&tmp, ":")) && (pos != (EVP_MAX_MD_SIZE - 1))) { sscanf(value, "%02x", (unsigned int*)&rtp->remote_fingerprint[pos++]); } } -static const char *ast_rtp_dtls_get_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash) +static enum ast_rtp_dtls_hash ast_rtp_dtls_get_fingerprint_hash(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - if (hash != AST_RTP_DTLS_HASH_SHA1) { - return NULL; - } + return rtp->local_hash; +} + +static const char *ast_rtp_dtls_get_fingerprint(struct ast_rtp_instance *instance) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); return rtp->local_fingerprint; } @@ -1078,6 +1162,7 @@ static struct ast_rtp_engine_dtls ast_rtp_dtls = { .get_setup = ast_rtp_dtls_get_setup, .set_setup = ast_rtp_dtls_set_setup, .set_fingerprint = ast_rtp_dtls_set_fingerprint, + .get_fingerprint_hash = ast_rtp_dtls_get_fingerprint_hash, .get_fingerprint = ast_rtp_dtls_get_fingerprint, }; @@ -1121,9 +1206,41 @@ static struct ast_rtp_engine asterisk_rtp_engine = { #ifdef HAVE_PJPROJECT static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq); +#ifdef HAVE_OPENSSL_SRTP +static void dtls_perform_handshake(struct ast_rtp_instance *instance, struct dtls_details *dtls, int rtcp) +{ + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + + if (!dtls->ssl) { + return; + } + + if (SSL_is_init_finished(dtls->ssl)) { + SSL_clear(dtls->ssl); + if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) { + SSL_set_accept_state(dtls->ssl); + } else { + SSL_set_connect_state(dtls->ssl); + } + dtls->connection = AST_RTP_DTLS_CONNECTION_NEW; + } + SSL_do_handshake(dtls->ssl); + dtls_srtp_check_pending(instance, rtp, rtcp); +} +#endif + static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) { - struct ast_rtp *rtp = ice->user_data; + struct ast_rtp_instance *instance = ice->user_data; + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); + +#ifdef HAVE_OPENSSL_SRTP + dtls_perform_handshake(instance, &rtp->dtls, 0); + + if (rtp->rtcp) { + dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); + } +#endif if (!strictrtp) { return; @@ -1135,7 +1252,8 @@ static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) static void ast_rtp_on_ice_rx_data(pj_ice_sess *ice, unsigned comp_id, unsigned transport_id, void *pkt, pj_size_t size, const pj_sockaddr_t *src_addr, unsigned src_addr_len) { - struct ast_rtp *rtp = ice->user_data; + struct ast_rtp_instance *instance = ice->user_data; + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); /* Instead of handling the packet here (which really doesn't work with our architecture) we set a bit to indicate that it should be handled after pj_ice_sess_on_rx_pkt * returns */ @@ -1144,7 +1262,8 @@ static void ast_rtp_on_ice_rx_data(pj_ice_sess *ice, unsigned comp_id, unsigned static pj_status_t ast_rtp_on_ice_tx_pkt(pj_ice_sess *ice, unsigned comp_id, unsigned transport_id, const void *pkt, pj_size_t size, const pj_sockaddr_t *dst_addr, unsigned dst_addr_len) { - struct ast_rtp *rtp = ice->user_data; + struct ast_rtp_instance *instance = ice->user_data; + struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); pj_status_t status = PJ_EINVALIDOP; pj_ssize_t _size = (pj_ssize_t)size; @@ -1345,36 +1464,51 @@ static int dtls_srtp_handle_timeout(const void *data) rtp->dtlstimerid = -1; ast_mutex_unlock(&rtp->dtls_timer_lock); - if (rtp->ssl) { - DTLSv1_handle_timeout(rtp->ssl); + if (rtp->dtls.ssl && !SSL_is_init_finished(rtp->dtls.ssl)) { + DTLSv1_handle_timeout(rtp->dtls.ssl); } + dtls_srtp_check_pending(instance, rtp, 0); - dtls_srtp_check_pending(instance, rtp); + if (rtp->rtcp && rtp->rtcp->dtls.ssl && !SSL_is_init_finished(rtp->rtcp->dtls.ssl)) { + DTLSv1_handle_timeout(rtp->rtcp->dtls.ssl); + } + dtls_srtp_check_pending(instance, rtp, 1); ao2_ref(instance, -1); return 0; } -static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp) +static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp) { - size_t pending = BIO_ctrl_pending(rtp->write_bio); + struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; + size_t pending; struct timeval dtls_timeout; /* timeout on DTLS */ + if (!dtls->ssl || !dtls->write_bio) { + return; + } + + pending = BIO_ctrl_pending(dtls->write_bio); + if (pending > 0) { char outgoing[pending]; size_t out; struct ast_sockaddr remote_address = { {0, } }; int ice; - ast_rtp_instance_get_remote_address(instance, &remote_address); + if (!rtcp) { + ast_rtp_instance_get_remote_address(instance, &remote_address); + } else { + ast_sockaddr_copy(&remote_address, &rtp->rtcp->them); + } /* If we do not yet know an address to send this to defer it until we do */ if (ast_sockaddr_isnull(&remote_address)) { return; } - out = BIO_read(rtp->write_bio, outgoing, sizeof(outgoing)); + out = BIO_read(dtls->write_bio, outgoing, sizeof(outgoing)); /* Stop existing DTLS timer if running */ ast_mutex_lock(&rtp->dtls_timer_lock); @@ -1383,7 +1517,7 @@ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct as rtp->dtlstimerid = -1; } - if (DTLSv1_get_timeout(rtp->ssl, &dtls_timeout)) { + if (DTLSv1_get_timeout(dtls->ssl, &dtls_timeout)) { int timeout = dtls_timeout.tv_sec * 1000 + dtls_timeout.tv_usec / 1000; ao2_ref(instance, +1); if ((rtp->dtlstimerid = ast_sched_add(rtp->sched, timeout, dtls_srtp_handle_timeout, instance)) < 0) { @@ -1393,7 +1527,7 @@ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct as } ast_mutex_unlock(&rtp->dtls_timer_lock); - __rtp_sendto(instance, outgoing, out, 0, &remote_address, 0, &ice, 0); + __rtp_sendto(instance, outgoing, out, 0, &remote_address, rtcp, &ice, 0); } } @@ -1402,9 +1536,15 @@ static int dtls_srtp_renegotiate(const void *data) struct ast_rtp_instance *instance = (struct ast_rtp_instance *)data; struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - SSL_renegotiate(rtp->ssl); - SSL_do_handshake(rtp->ssl); - dtls_srtp_check_pending(instance, rtp); + SSL_renegotiate(rtp->dtls.ssl); + SSL_do_handshake(rtp->dtls.ssl); + dtls_srtp_check_pending(instance, rtp, 0); + + if (rtp->rtcp && rtp->rtcp->dtls.ssl) { + SSL_renegotiate(rtp->rtcp->dtls.ssl); + SSL_do_handshake(rtp->rtcp->dtls.ssl); + dtls_srtp_check_pending(instance, rtp, 1); + } rtp->rekeyid = -1; ao2_ref(instance, -1); @@ -1420,20 +1560,30 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as struct ast_rtp_instance_stats stats = { 0, }; /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */ - if (SSL_CTX_get_verify_mode(rtp->ssl_ctx) != SSL_VERIFY_NONE) { + if (rtp->dtls_verify & AST_RTP_DTLS_VERIFY_FINGERPRINT) { X509 *certificate; - if (!(certificate = SSL_get_peer_certificate(rtp->ssl))) { + if (!(certificate = SSL_get_peer_certificate(rtp->dtls.ssl))) { ast_log(LOG_WARNING, "No certificate was provided by the peer on RTP instance '%p'\n", instance); return -1; } /* If a fingerprint is present in the SDP make sure that the peer certificate matches it */ if (rtp->remote_fingerprint[0]) { + const EVP_MD *type; unsigned char fingerprint[EVP_MAX_MD_SIZE]; unsigned int size; - if (!X509_digest(certificate, EVP_sha1(), fingerprint, &size) || + if (rtp->remote_hash == AST_RTP_DTLS_HASH_SHA1) { + type = EVP_sha1(); + } else if (rtp->remote_hash == AST_RTP_DTLS_HASH_SHA256) { + type = EVP_sha256(); + } else { + ast_log(LOG_WARNING, "Unsupported fingerprint hash type on RTP instance '%p'\n", instance); + return -1; + } + + if (!X509_digest(certificate, type, fingerprint, &size) || !size || memcmp(fingerprint, rtp->remote_fingerprint, size)) { X509_free(certificate); @@ -1447,21 +1597,21 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as } /* Ensure that certificate verification was successful */ - if (SSL_get_verify_result(rtp->ssl) != X509_V_OK) { + if ((rtp->dtls_verify & AST_RTP_DTLS_VERIFY_CERTIFICATE) && SSL_get_verify_result(rtp->dtls.ssl) != X509_V_OK) { ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n", instance); return -1; } /* Produce key information and set up SRTP */ - if (!SSL_export_keying_material(rtp->ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { + if (!SSL_export_keying_material(rtp->dtls.ssl, material, SRTP_MASTER_LEN * 2, "EXTRACTOR-dtls_srtp", 19, NULL, 0, 0)) { ast_log(LOG_WARNING, "Unable to extract SRTP keying material from DTLS-SRTP negotiation on RTP instance '%p'\n", instance); return -1; } /* Whether we are acting as a server or client determines where the keys/salts are */ - if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) { + if (rtp->dtls.dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) { local_key = material; remote_key = local_key + SRTP_MASTER_KEY_LEN; local_salt = remote_key + SRTP_MASTER_KEY_LEN; @@ -1547,50 +1697,51 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s } #ifdef HAVE_OPENSSL_SRTP - if (!rtcp) { - dtls_srtp_check_pending(instance, rtp); - - /* If this is an SSL packet pass it to OpenSSL for processing */ - if ((*in >= 20) && (*in <= 64)) { - int res = 0; + dtls_srtp_check_pending(instance, rtp, rtcp); - /* If no SSL session actually exists terminate things */ - if (!rtp->ssl) { - ast_log(LOG_ERROR, "Received SSL traffic on RTP instance '%p' without an SSL session\n", - instance); - return -1; - } + /* If this is an SSL packet pass it to OpenSSL for processing */ + if ((*in >= 20) && (*in <= 64)) { + struct dtls_details *dtls = !rtcp ? &rtp->dtls : &rtp->rtcp->dtls; + int res = 0; - /* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */ - if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) { - rtp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE; - SSL_set_accept_state(rtp->ssl); - } + /* If no SSL session actually exists terminate things */ + if (!dtls->ssl) { + ast_log(LOG_ERROR, "Received SSL traffic on RTP instance '%p' without an SSL session\n", + instance); + return -1; + } - dtls_srtp_check_pending(instance, rtp); + /* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */ + if (dtls->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) { + dtls->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE; + SSL_set_accept_state(dtls->ssl); + } - BIO_write(rtp->read_bio, buf, len); + dtls_srtp_check_pending(instance, rtp, rtcp); - len = SSL_read(rtp->ssl, buf, len); + BIO_write(dtls->read_bio, buf, len); - dtls_srtp_check_pending(instance, rtp); + len = SSL_read(dtls->ssl, buf, len); - if (rtp->dtls_failure) { - ast_log(LOG_ERROR, "DTLS failure occurred on RTP instance '%p', terminating\n", - instance); - return -1; - } + if ((len < 0) && (SSL_get_error(dtls->ssl, len) == SSL_ERROR_SSL)) { + unsigned long error = ERR_get_error(); + ast_log(LOG_ERROR, "DTLS failure occurred on RTP instance '%p' due to reason '%s', terminating\n", + instance, ERR_reason_error_string(error)); + return -1; + } - if (SSL_is_init_finished(rtp->ssl)) { - /* Any further connections will be existing since this is now established */ - rtp->connection = AST_RTP_DTLS_CONNECTION_EXISTING; + dtls_srtp_check_pending(instance, rtp, rtcp); + if (SSL_is_init_finished(dtls->ssl)) { + /* Any further connections will be existing since this is now established */ + dtls->connection = AST_RTP_DTLS_CONNECTION_EXISTING; + if (!rtcp) { /* Use the keying material to set up key/salt information */ res = dtls_srtp_setup(rtp, srtp, instance); } - - return res; } + + return res; } #endif @@ -1919,7 +2070,7 @@ static int ice_create(struct ast_rtp_instance *instance, struct ast_sockaddr *ad if (pj_ice_sess_create(&stun_config, NULL, PJ_ICE_SESS_ROLE_UNKNOWN, 2, &ast_rtp_ice_sess_cb, &ufrag, &passwd, NULL, &rtp->ice) == PJ_SUCCESS) { /* Make this available for the callbacks */ - rtp->ice->user_data = rtp; + rtp->ice->user_data = instance; /* Add all of the available candidates to the ICE session */ rtp_add_candidates_to_ice(instance, rtp, addr, port, AST_RTP_ICE_COMPONENT_RTP, @@ -2054,6 +2205,11 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) * RTP instance while it's active. */ close(rtp->rtcp->s); +#ifdef HAVE_OPENSSL_SRTP + if (rtp->rtcp->dtls.ssl) { + SSL_free(rtp->rtcp->dtls.ssl); + } +#endif ast_free(rtp->rtcp); } @@ -2100,8 +2256,8 @@ static int ast_rtp_destroy(struct ast_rtp_instance *instance) } /* Destroy the SSL session if present */ - if (rtp->ssl) { - SSL_free(rtp->ssl); + if (rtp->dtls.ssl) { + SSL_free(rtp->dtls.ssl); } #endif @@ -4166,6 +4322,10 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro } #endif +#ifdef HAVE_OPENSSL_SRTP + dtls_setup_rtcp(instance); +#endif + return; } else { if (rtp->rtcp) { @@ -4181,6 +4341,11 @@ static void ast_rtp_prop_set(struct ast_rtp_instance *instance, enum ast_rtp_pro rtp->rtcp->schedid = -1; } close(rtp->rtcp->s); +#ifdef HAVE_OPENSSL_SRTP + if (rtp->rtcp->dtls.ssl) { + SSL_free(rtp->rtcp->dtls.ssl); + } +#endif ast_free(rtp->rtcp); rtp->rtcp = NULL; } @@ -4464,13 +4629,18 @@ static int ast_rtp_activate(struct ast_rtp_instance *instance) { struct ast_rtp *rtp = ast_rtp_instance_get_data(instance); - if (!rtp->ssl) { + /* If ICE negotiation is enabled the DTLS Handshake will be performed upon completion of it */ +#ifdef USE_PJPROJECT + if (rtp->ice) { return 0; } +#endif - SSL_do_handshake(rtp->ssl); + dtls_perform_handshake(instance, &rtp->dtls, 0); - dtls_srtp_check_pending(instance, rtp); + if (rtp->rtcp) { + dtls_perform_handshake(instance, &rtp->rtcp->dtls, 1); + } return 0; } |