[Pkg-voip-commits] [asterisk] 01/02: Add DTLS SRTP patch from issue 22961

Daniel Pocock pocock at moszumanska.debian.org
Fri Jan 24 15:14:53 UTC 2014


This is an automated email from the git hooks/post-receive script.

pocock pushed a commit to branch dtls-srtp-patch
in repository asterisk.

commit 0af9be2fbc077f24b3115f60d5fee0783498a293
Author: Daniel Pocock <daniel at pocock.com.au>
Date:   Fri Jan 24 14:13:51 2014 +0100

    Add DTLS SRTP patch from issue 22961
---
 debian/patches/dtls_srtp_patch | 1213 ++++++++++++++++++++++++++++++++++++++++
 debian/patches/series          |    3 +
 2 files changed, 1216 insertions(+)

diff --git a/debian/patches/dtls_srtp_patch b/debian/patches/dtls_srtp_patch
new file mode 100644
index 0000000..7c60e20
--- /dev/null
+++ b/debian/patches/dtls_srtp_patch
@@ -0,0 +1,1213 @@
+diff --git a/channels/chan_sip.c b/channels/chan_sip.c
+index 4fc2322..99126b7 100644
+--- a/channels/chan_sip.c
++++ b/channels/chan_sip.c
+@@ -1401,7 +1401,7 @@ static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_
+ static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newtextrtp, char *red_fmtp, int *red_num_gen, int *red_data_pt, int *last_rtpmap_codec);
+ static int process_sdp_a_image(const char *a, struct sip_pvt *p);
+ static void add_ice_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
+-static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf);
++static void add_dtls_to_sdp(struct ast_rtp_instance *instance, const struct sip_pvt *dialog, struct ast_str **a_buf);
+ static void start_ice(struct ast_rtp_instance *instance);
+ static void add_codec_to_sdp(const struct sip_pvt *p, struct ast_format *codec,
+ 			     struct ast_str **m_buf, struct ast_str **a_buf,
+@@ -5889,10 +5889,6 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
+ 		ice->stop(dialog->rtp);
+ 	}
+ 
+-	if (dialog_initialize_dtls_srtp(dialog, dialog->rtp, &dialog->srtp)) {
+-		return -1;
+-	}
+-
+ 	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT_ALWAYS) ||
+ 			(ast_test_flag(&dialog->flags[1], SIP_PAGE2_VIDEOSUPPORT) && (ast_format_cap_has_type(dialog->caps, AST_FORMAT_TYPE_VIDEO)))) {
+ 		if (!(dialog->vrtp = ast_rtp_instance_new(dialog->engine, sched, &bindaddr_tmp, NULL))) {
+@@ -5903,16 +5899,17 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
+ 			ice->stop(dialog->vrtp);
+ 		}
+ 
+-		if (dialog_initialize_dtls_srtp(dialog, dialog->vrtp, &dialog->vsrtp)) {
+-			return -1;
+-		}
+-
+ 		ast_rtp_instance_set_timeout(dialog->vrtp, dialog->rtptimeout);
+ 		ast_rtp_instance_set_hold_timeout(dialog->vrtp, dialog->rtpholdtimeout);
+ 		ast_rtp_instance_set_keepalive(dialog->vrtp, dialog->rtpkeepalive);
+ 
+ 		ast_rtp_instance_set_prop(dialog->vrtp, AST_RTP_PROPERTY_RTCP, 1);
+ 		ast_rtp_instance_set_qos(dialog->vrtp, global_tos_video, global_cos_video, "SIP VIDEO");
++		
++		/*SRTP_DTLS */
++		if (dialog_initialize_dtls_srtp(dialog, dialog->vrtp, &dialog->vsrtp)) {
++			return -1;
++		}
+ 	}
+ 
+ 	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_TEXTSUPPORT)) {
+@@ -5924,14 +5921,15 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
+ 			ice->stop(dialog->trtp);
+ 		}
+ 
+-		if (dialog_initialize_dtls_srtp(dialog, dialog->trtp, &dialog->tsrtp)) {
+-			return -1;
+-		}
+-
+ 		/* Do not timeout text as its not constant*/
+ 		ast_rtp_instance_set_keepalive(dialog->trtp, dialog->rtpkeepalive);
+ 
+ 		ast_rtp_instance_set_prop(dialog->trtp, AST_RTP_PROPERTY_RTCP, 1);
++		
++		/*SRTP_DTLS */
++		if (dialog_initialize_dtls_srtp(dialog, dialog->vrtp, &dialog->vsrtp)) {
++			return -1;
++		}
+ 	}
+ 
+ 	ast_rtp_instance_set_timeout(dialog->rtp, dialog->rtptimeout);
+@@ -5941,6 +5939,11 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog)
+ 	ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_RTCP, 1);
+ 	ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF, ast_test_flag(&dialog->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833);
+ 	ast_rtp_instance_set_prop(dialog->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
++ 
++	/*SRTP_DTLS */
++	if (dialog_initialize_dtls_srtp(dialog, dialog->rtp, &dialog->srtp)) {
++		return -1;
++	}
+ 
+ 	ast_rtp_instance_set_qos(dialog->rtp, global_tos_audio, global_cos_audio, "SIP RTP");
+ 
+@@ -9942,6 +9945,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
+ 	/* SRTP */
+ 	int secure_audio = FALSE;
+ 	int secure_video = FALSE;
++/** SRTP_DTLS **/
++	int processed_dtls = FALSE;
++	/** SRTP_DTLS **/
+ 
+ 	/* Others */
+ 	int sendonly = -1;
+@@ -10034,12 +10040,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
+ 			}
+ 
+ 			if (process_sdp_a_dtls(value, p, p->rtp)) {
++				processed_dtls = TRUE;
+ 				processed = TRUE;
+ 			}
+ 			if (process_sdp_a_dtls(value, p, p->vrtp)) {
++				processed_dtls = TRUE;
+ 				processed = TRUE;
+ 			}
+ 			if (process_sdp_a_dtls(value, p, p->trtp)) {
++				processed_dtls = TRUE;
+ 				processed = TRUE;
+ 			}
+ 
+@@ -10132,7 +10141,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
+ 					}
+ 				} else if (!strcmp(protocol, "UDP/TLS/RTP/SAVP") || !strcmp(protocol, "UDP/TLS/RTP/SAVPF")) {
+ 					secure_audio = 1;
+-
+ 					if (p->srtp) {
+ 						ast_set_flag(p->srtp, SRTP_CRYPTO_OFFER_OK);
+ 					}
+@@ -10435,6 +10443,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
+ 						processed = TRUE;
+ 					} else if (process_sdp_a_dtls(value, p, p->rtp)) {
+ 						processed = TRUE;
++						processed_dtls = TRUE;
+ 					} else if (process_sdp_a_sendonly(value, &sendonly)) {
+ 						processed = TRUE;
+ 					} else if (!processed_crypto && process_crypto(p, p->rtp, &p->srtp, value)) {
+@@ -10450,6 +10459,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
+ 						processed = TRUE;
+ 					} else if (process_sdp_a_dtls(value, p, p->vrtp)) {
+ 						processed = TRUE;
++						processed_dtls = TRUE;
+ 					} else if (!processed_crypto && process_crypto(p, p->vrtp, &p->vsrtp, value)) {
+ 						processed_crypto = TRUE;
+ 						processed = TRUE;
+@@ -10483,10 +10493,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
+ 		}
+ 
+ 		/* Ensure crypto lines are provided where necessary */
+-		if (audio && secure_audio && !processed_crypto) {
++			ast_log(LOG_WARNING, "Processed DTLS [%s] \n", processed_dtls?"TRUE":"FALSE");
++			if (audio && secure_audio && !(processed_crypto || processed_dtls)) {
+ 			ast_log(LOG_WARNING, "Rejecting secure audio stream without encryption details: %s\n", m);
+ 			return -1;
+-		} else if (video && secure_video && !processed_crypto) {
++			} else if (video && secure_video && !(processed_crypto || processed_dtls)) {
+ 			ast_log(LOG_WARNING, "Rejecting secure video stream without encryption details: %s\n", m);
+ 			return -1;
+ 		}
+@@ -10993,6 +11004,7 @@ static int process_sdp_a_dtls(const char *a, struct sip_pvt *p, struct ast_rtp_i
+ {
+ 	struct ast_rtp_engine_dtls *dtls;
+ 	int found = FALSE;
++	int found_setup = FALSE;
+ 	char value[256], hash[6];
+ 
+ 	if (!instance || !p->dtls_cfg.enabled || !(dtls = ast_rtp_instance_get_dtls(instance))) {
+@@ -11001,7 +11013,7 @@ static int process_sdp_a_dtls(const char *a, struct sip_pvt *p, struct ast_rtp_i
+ 
+ 	if (sscanf(a, "setup: %255s", value) == 1) {
+ 		found = TRUE;
+-
++		found_setup = TRUE;
+ 		if (!strcasecmp(value, "active")) {
+ 			dtls->set_setup(instance, AST_RTP_DTLS_SETUP_ACTIVE);
+ 		} else if (!strcasecmp(value, "passive")) {
+@@ -11025,17 +11037,24 @@ static int process_sdp_a_dtls(const char *a, struct sip_pvt *p, struct ast_rtp_i
+ 			ast_log(LOG_WARNING, "Unsupported connection attribute value '%s' received on dialog '%s'\n",
+ 				value, p->callid);
+ 		}
+-	} else if (sscanf(a, "fingerprint: %5s %255s", hash, value) == 2) {
++	} else if (sscanf(a, "fingerprint: %s %255s", hash, value) == 2) {
+ 		found = TRUE;
+ 
+ 		if (!strcasecmp(hash, "sha-1")) {
+ 			dtls->set_fingerprint(instance, AST_RTP_DTLS_HASH_SHA1, value);
++			} else if (!strcasecmp(hash, "sha-256"))
++			{
++			dtls->set_fingerprint(instance, AST_RTP_DTLS_HASH_SHA256, value);
+ 		} else {
+ 			ast_log(LOG_WARNING, "Unsupported fingerprint hash type '%s' received on dialog '%s'\n",
+ 				hash, p->callid);
+ 		}
+ 	}
+-
++	if (found && !found_setup)
++	{
++		/* No setup line provided by WebRTC peer */
++		dtls->set_setup(instance, AST_RTP_DTLS_SETUP_PASSIVE);
++	}
+ 	return found;
+ }
+ 
+@@ -12653,11 +12672,14 @@ static void start_ice(struct ast_rtp_instance *instance)
+ }
+ 
+ /*! \brief Add DTLS attributes to SDP */
+-static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **a_buf)
++static void add_dtls_to_sdp(struct ast_rtp_instance *instance, const struct sip_pvt *dialog, struct ast_str **a_buf)
+ {
+ 	struct ast_rtp_engine_dtls *dtls;
+ 	const char *fingerprint;
++	/*SRTP_DTLS */
++	dtls = ast_rtp_instance_get_dtls(instance);
+ 
++	/*SRTP_DTLS */
+ 	if (!instance || !(dtls = ast_rtp_instance_get_dtls(instance)) || !dtls->active(instance)) {
+ 		return;
+ 	}
+@@ -12690,7 +12712,11 @@ static void add_dtls_to_sdp(struct ast_rtp_instance *instance, struct ast_str **
+ 		break;
+ 	}
+ 
+-	if ((fingerprint = dtls->get_fingerprint(instance, AST_RTP_DTLS_HASH_SHA1))) {
++	if ((fingerprint = dtls->get_fingerprint(instance, &dialog->dtls_cfg, AST_RTP_DTLS_HASH_SHA256))) {
++			ast_str_append(a_buf, 0, "a=fingerprint:SHA-256 %s\r\n", fingerprint);
++	}
++	else if ((fingerprint = dtls->get_fingerprint(instance, &dialog->dtls_cfg, AST_RTP_DTLS_HASH_SHA1)))
++	{
+ 		ast_str_append(a_buf, 0, "a=fingerprint:SHA-1 %s\r\n", fingerprint);
+ 	}
+ }
+@@ -12999,7 +13025,9 @@ static char *get_sdp_rtp_profile(const struct sip_pvt *p, unsigned int secure, s
+ 	struct ast_rtp_engine_dtls *dtls;
+ 
+ 	if ((dtls = ast_rtp_instance_get_dtls(instance)) && dtls->active(instance)) {
+-		return ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF) ? "UDP/TLS/RTP/SAVPF" : "UDP/TLS/RTP/SAVP";
++				/*SRTP_DTLS */
++		return ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF) ? "RTP/SAVPF" : "RTP/SAVP";
++		/*SRTP_DTLS */
+ 	} else {
+ 		if (ast_test_flag(&p->flags[2], SIP_PAGE3_USE_AVPF)) {
+ 			return secure ? "RTP/SAVPF" : "RTP/AVPF";
+@@ -13183,7 +13211,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
+ 					add_ice_to_sdp(p->vrtp, &a_video);
+ 				}
+ 
+-				add_dtls_to_sdp(p->vrtp, &a_video);
++				add_dtls_to_sdp(p->vrtp, p, &a_video);
+ 			}
+ 		}
+ 
+@@ -13204,7 +13232,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
+ 					add_ice_to_sdp(p->trtp, &a_text);
+ 				}
+ 
+-				add_dtls_to_sdp(p->trtp, &a_text);
++				add_dtls_to_sdp(p->trtp, p, &a_text);
+ 			}
+ 		}
+ 
+@@ -13306,7 +13334,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
+ 				add_ice_to_sdp(p->rtp, &a_audio);
+ 			}
+ 
+-			add_dtls_to_sdp(p->rtp, &a_audio);
++			add_dtls_to_sdp(p->rtp, p, &a_audio);
+ 		}
+ 	}
+ 
+@@ -33171,11 +33199,6 @@ static int process_crypto(struct sip_pvt *p, struct ast_rtp_instance *rtp, struc
+ 
+ 	ast_set_flag(*srtp, SRTP_CRYPTO_OFFER_OK);
+ 
+-	if ((dtls = ast_rtp_instance_get_dtls(rtp))) {
+-		dtls->stop(rtp);
+-		p->dtls_cfg.enabled = 0;
+-	}
+-
+ 	return TRUE;
+ }
+ 
+diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
+index e2dfc2e..c8d2e41 100644
+--- a/include/asterisk/rtp_engine.h
++++ b/include/asterisk/rtp_engine.h
+@@ -369,7 +369,11 @@ enum ast_rtp_dtls_connection {
+ 
+ /*! \brief DTLS fingerprint hashes */
+ enum ast_rtp_dtls_hash {
++	AST_RTP_DTLS_HASH_NONE, /* Uninitialized */
+ 	AST_RTP_DTLS_HASH_SHA1, /*!< SHA-1 fingerprint hash */
++	/*SRTP_DTLS */
++	AST_RTP_DTLS_HASH_SHA256, /*!< SHA-256 fingerprint hash */
++	/*SRTP_DTLS */
+ };
+ 
+ /*! \brief DTLS configuration structure */
+@@ -405,7 +409,7 @@ struct ast_rtp_engine_dtls {
+ 	/*! Set the remote fingerprint */
+ 	void (*set_fingerprint)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint);
+ 	/*! Get the local fingerprint */
+-	const char *(*get_fingerprint)(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash);
++	const char *(*get_fingerprint)(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg, enum ast_rtp_dtls_hash hash);
+ };
+ 
+ /*! Structure that represents an RTP stack (engine) */
+diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
+index 2231e8e..79d9cf9 100644
+--- a/res/res_rtp_asterisk.c
++++ b/res/res_rtp_asterisk.c
+@@ -127,6 +127,8 @@ static int rtpend = DEFAULT_RTP_END;			/*!< Last port for RTP sessions (set in r
+ static int rtpdebug;			/*!< Are we debugging? */
+ static int rtcpdebug;			/*!< Are we debugging RTCP? */
+ static int rtcpstats;			/*!< Are we debugging RTCP? */
++/* SRTP_DTLS */
++static int dtlsdebug;
+ static int rtcpinterval = RTCP_DEFAULT_INTERVALMS; /*!< Time between rtcp reports in millisecs */
+ static struct ast_sockaddr rtpdebugaddr;	/*!< Debug packets to/from this host */
+ static struct ast_sockaddr rtcpdebugaddr;	/*!< Debug RTCP packets to/from this host */
+@@ -270,6 +272,13 @@ struct ast_rtp {
+ 	ast_cond_t cond;            /*!< Condition for signaling */
+ 	unsigned int passthrough:1; /*!< Bit to indicate that the received packet should be passed through */
+ 	unsigned int ice_started:1; /*!< Bit to indicate ICE connectivity checks have started */
++	/* SRTP_DTLS */
++	unsigned int icecomplete:1; /*!< Bit to indicate ICE connectivity checks have completed */
++	unsigned int icedone:1; /*!< Bit to indicate ICE connectivity checks have completed (go on with RTP or DTLS) */
++	unsigned int dtlsinit:1; /*!< Bit to indicate DTLS-SRTP setup has been started (whether to start DTLS or not) */
++	unsigned int dtlsdone:1; /*!< Bit to indicate DTLS-SRTP setup has been completed (go on with RTP or DTLS) */
++	struct ast_rtp_instance *instance;
++	/* SRTP_DTLS */
+ 
+ 	char remote_ufrag[256];  /*!< The remote ICE username */
+ 	char remote_passwd[256]; /*!< The remote ICE password */
+@@ -289,7 +298,9 @@ struct ast_rtp {
+ 	enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
+ 	enum ast_srtp_suite suite;   /*!< SRTP crypto suite */
+ 	char local_fingerprint[160]; /*!< Fingerprint of our certificate */
++	enum ast_rtp_dtls_hash local_fingerprint_type; /*!< Local fingerprint type */
+ 	unsigned char remote_fingerprint[EVP_MAX_MD_SIZE]; /*!< Fingerprint of the peer certificate */
++	enum ast_rtp_dtls_hash remote_fingerprint_type; /*!< Remote fingerprint type */
+ 	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 */
+@@ -356,6 +367,28 @@ struct ast_rtcp {
+ 	double normdevrtt;
+ 	double stdevrtt;
+ 	unsigned int rtt_count;
++	/* VP8: sequence number for the RTCP FIR FCI */
++ 	int firseq;
++	/* SRTP_DTLS */
++        unsigned int icecomplete:1; /*!< Bit to indicate ICE connectivity checks have completed */
++        unsigned int icedone:1; /*!< Bit to indicate ICE connectivity checks have completed (go on with RTCP or DTLS) */
++        unsigned int dtlsdone:1; /*!< Bit to indicate DTLS-SRTP setup has been completed (go on with RTCP or DTLS) */
++#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 */
++        enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
++        enum ast_srtp_suite suite;   /*!< SRTP crypto suite */
++        char local_fingerprint[160]; /*!< Fingerprint of our certificate */
++        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 */
++#endif
++	/* SRTP_DTLS */
++
+ };
+ 
+ struct rtp_red {
+@@ -403,6 +436,9 @@ 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);
++/* SRTP_DTLS DTLS certificate verification callback */
++static int dtls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx);
++/* SRTP_DTLS */
+ #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);
+@@ -717,6 +753,10 @@ static void dtls_info_callback(const SSL *ssl, int where, int ret)
+ 	if (!(where & SSL_CB_ALERT)) {
+ 		return;
+ 	}
++	/* SRTP_DTLS */
++	ast_verbose(VERBOSE_PREFIX_3 "dtls_info_callback: %s, where=%d, ret=%d\n", (where & SSL_CB_READ)?"read":"write", where, ret);
++	ast_verbose(VERBOSE_PREFIX_3 "  >> %s, %s, %s\n", SSL_state_string(ssl), SSL_alert_type_string(ret), SSL_alert_desc_string(ret));
++	/* SRTP_DTLS */
+ 
+ 	rtp->dtls_failure = 1;
+ }
+@@ -737,7 +777,9 @@ 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);
++	/* SRTP_DTLS */
++	SSL_CTX_set_verify(rtp->ssl_ctx, dtls_cfg->verify ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, dtls_verify_callback);
++	/* SRTP_DTLS */
+ 
+ 	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");
+@@ -777,14 +819,17 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
+ 
+ 		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, EVP_sha256(), 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;
+ 		}
+-
++		else
++		{
++			rtp->local_fingerprint_type = AST_RTP_DTLS_HASH_SHA256;
++		}
+ 		for (i = 0; i < size; i++) {
+ 			sprintf(local_fingerprint, "%.2X:", fingerprint[i]);
+ 			local_fingerprint += 3;
+@@ -848,6 +893,112 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
+ 
+ 	rtp->connection = AST_RTP_DTLS_CONNECTION_NEW;
+ 
++	        /* SRTP_DTLS: do the same with RTCP */
++        if (!(rtp->rtcp->ssl_ctx = SSL_CTX_new(DTLSv1_method()))) {
++               return -1;
++        }
++        SSL_CTX_set_verify(rtp->rtcp->ssl_ctx, dtls_cfg->verify ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE, NULL);
++        if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_80) {
++                SSL_CTX_set_tlsext_use_srtp(rtp->rtcp->ssl_ctx, "SRTP_AES128_CM_SHA1_80");
++        } else if (dtls_cfg->suite == AST_AES_CM_128_HMAC_SHA1_32) {
++                SSL_CTX_set_tlsext_use_srtp(rtp->rtcp->ssl_ctx, "SRTP_AES128_CM_SHA1_32");
++        } else {
++                ast_log(LOG_ERROR, "Unsupported suite specified for DTLS-SRTP on RTCP instance '%p'\n", instance);
++                goto error;
++        }
++        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;
++                unsigned int size, i;
++                unsigned char fingerprint[EVP_MAX_MD_SIZE];
++                char *local_fingerprint = rtp->rtcp->local_fingerprint;
++                if (!SSL_CTX_use_certificate_file(rtp->rtcp->ssl_ctx, dtls_cfg->certfile, SSL_FILETYPE_PEM)) {
++                        ast_log(LOG_ERROR, "Specified certificate file '%s' for RTCP instance '%p' could not be used\n",
++                                dtls_cfg->certfile, instance);
++                        goto error;
++                }
++                if (!SSL_CTX_use_PrivateKey_file(rtp->rtcp->ssl_ctx, private, SSL_FILETYPE_PEM) ||
++                    !SSL_CTX_check_private_key(rtp->rtcp->ssl_ctx)) {
++                        ast_log(LOG_ERROR, "Specified private key file '%s' for RTCP instance '%p' could not be used\n",
++                                private, instance);
++                        goto error;
++                }
++                if (!(certbio = BIO_new(BIO_s_file()))) {
++                        ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTCP instance '%p'\n",
++                                instance);
++                        goto error;
++                }
++		if (!(certbio = BIO_new(BIO_s_file()))) {
++			ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTCP instance '%p'\n",
++				instance);
++			goto error;
++		}
++		if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||
++		    !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||
++		    /* SRTP_DTLS: use SHA256 for DTLS-SRTP Fingerprint */
++		    !X509_digest(cert, EVP_sha256(), fingerprint, &size) ||
++		    !size) {
++			ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTCP instance '%p'\n",
++				dtls_cfg->certfile, instance);
++			BIO_free_all(certbio);
++			goto error;
++		}
++		for (i = 0; i < size; i++) {
++			sprintf(local_fingerprint, "%.2X:", fingerprint[i]);
++			local_fingerprint += 3;
++		}
++  	*(local_fingerprint-1) = 0;
++ 	BIO_free_all(certbio);
++	}
++
++        if (!ast_strlen_zero(dtls_cfg->cipher)) {
++                if (!SSL_CTX_set_cipher_list(rtp->rtcp->ssl_ctx, dtls_cfg->cipher)) {
++                        ast_log(LOG_ERROR, "Invalid cipher specified in cipher list '%s' for RTCP instance '%p'\n",
++                                dtls_cfg->cipher, instance);
++                        goto error;
++                }
++        }
++        if (!ast_strlen_zero(dtls_cfg->cafile) || !ast_strlen_zero(dtls_cfg->capath)) {
++                if (!SSL_CTX_load_verify_locations(rtp->rtcp->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 RTCP instance '%p'\n",
++                                S_OR(dtls_cfg->cafile, ""), S_OR(dtls_cfg->capath, ""), instance);
++                        goto error;
++                }
++        }
++
++	rtp->rtcp->rekey = dtls_cfg->rekey;
++        rtp->rtcp->dtls_setup = dtls_cfg->default_setup;
++        rtp->rtcp->suite = dtls_cfg->suite;
++        if (!(rtp->rtcp->ssl = SSL_new(rtp->rtcp->ssl_ctx))) {
++                ast_log(LOG_ERROR, "Failed to allocate memory for SSL context on RTCP instance '%p'\n",
++                        instance);
++                goto error;
++        }
++        SSL_set_ex_data(rtp->rtcp->ssl, 0, rtp);
++        SSL_set_info_callback(rtp->rtcp->ssl, dtls_info_callback);
++        if (!(rtp->rtcp->read_bio = BIO_new(BIO_s_mem()))) {
++                ast_log(LOG_ERROR, "Failed to allocate memory for inbound SSL traffic on RTCP instance '%p'\n",
++                        instance);
++                goto error;
++        }
++        BIO_set_mem_eof_return(rtp->rtcp->read_bio, -1);
++        if (!(rtp->rtcp->write_bio = BIO_new(BIO_s_mem()))) {
++                ast_log(LOG_ERROR, "Failed to allocate memory for outbound SSL traffic on RTCP instance '%p'\n",
++                        instance);
++                goto error;
++        }
++        BIO_set_mem_eof_return(rtp->rtcp->write_bio, -1);
++
++	SSL_set_bio(rtp->rtcp->ssl, rtp->rtcp->read_bio, rtp->rtcp->write_bio);
++        if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
++                SSL_set_accept_state(rtp->rtcp->ssl);
++        } else {
++                SSL_set_connect_state(rtp->rtcp->ssl);
++        }
++        rtp->rtcp->connection = AST_RTP_DTLS_CONNECTION_NEW;
++
++	
+ 	return 0;
+ 
+ error:
+@@ -868,6 +1019,21 @@ error:
+ 
+ 	SSL_CTX_free(rtp->ssl_ctx);
+ 	rtp->ssl_ctx = NULL;
++	/* SRTP_DTLS: do the same with RTCP */
++	if (rtp->rtcp->read_bio) {
++		BIO_free(rtp->rtcp->read_bio);
++		rtp->rtcp->read_bio = NULL;
++	}
++	if (rtp->rtcp->write_bio) {
++		BIO_free(rtp->rtcp->write_bio);
++		rtp->rtcp->write_bio = NULL;
++	}
++	if (rtp->rtcp->ssl) {
++		SSL_free(rtp->rtcp->ssl);
++		rtp->rtcp->ssl = NULL;
++	}
++	SSL_CTX_free(rtp->rtcp->ssl_ctx);
++	rtp->rtcp->ssl_ctx = NULL;
+ 
+ 	return -1;
+ }
+@@ -875,7 +1041,6 @@ error:
+ static int ast_rtp_dtls_active(struct ast_rtp_instance *instance)
+ {
+ 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+-
+ 	return !rtp->ssl_ctx ? 0 : 1;
+ }
+ 
+@@ -883,6 +1048,8 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
+ {
+ 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+ 
++		ast_verbose(VERBOSE_PREFIX_3 "Stopping DTLS...\n");
++
+ 	if (rtp->ssl_ctx) {
+ 		SSL_CTX_free(rtp->ssl_ctx);
+ 		rtp->ssl_ctx = NULL;
+@@ -892,6 +1059,16 @@ static void ast_rtp_dtls_stop(struct ast_rtp_instance *instance)
+ 		SSL_free(rtp->ssl);
+ 		rtp->ssl = NULL;
+ 	}
++	
++	/* SRTP_DTLS: do the same with RTCP */
++	if (rtp->rtcp->ssl_ctx) {
++		SSL_CTX_free(rtp->rtcp->ssl_ctx);
++		rtp->rtcp->ssl_ctx = NULL;
++	}
++	if (rtp->rtcp->ssl) {
++		SSL_free(rtp->rtcp->ssl);
++		rtp->rtcp->ssl = NULL;
++	}
+ }
+ 
+ static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance)
+@@ -905,6 +1082,13 @@ static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance)
+ 
+ 	SSL_shutdown(rtp->ssl);
+ 	rtp->connection = AST_RTP_DTLS_CONNECTION_NEW;
++	
++	/* SRTP_DTLS: do the same with RTCP */
++	if (!SSL_is_init_finished(rtp->rtcp->ssl)) {
++		return;
++	}
++	SSL_shutdown(rtp->rtcp->ssl);
++	rtp->rtcp->connection = AST_RTP_DTLS_CONNECTION_NEW;
+ }
+ 
+ static enum ast_rtp_dtls_connection ast_rtp_dtls_get_connection(struct ast_rtp_instance *instance)
+@@ -964,6 +1148,16 @@ static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_r
+ 	} else {
+ 		return;
+ 	}
++	
++	/* SRTP_DTLS: do the same with RTCP */
++	rtp->rtcp->dtls_setup = rtp->dtls_setup;
++	if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) {
++		SSL_set_connect_state(rtp->rtcp->ssl);
++	} else if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
++		SSL_set_accept_state(rtp->rtcp->ssl);
++	} else {
++		return;
++	}
+ }
+ 
+ static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash, const char *fingerprint)
+@@ -972,24 +1166,104 @@ static void ast_rtp_dtls_set_fingerprint(struct ast_rtp_instance *instance, enum
+ 	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)
++	{
++		rtp->remote_fingerprint_type = AST_RTP_DTLS_HASH_SHA1;
++	}
++	else if(hash == AST_RTP_DTLS_HASH_SHA256)
++	{
++		rtp->remote_fingerprint_type = AST_RTP_DTLS_HASH_SHA256;
++	}
++	else
++	{
+ 		return;
+ 	}
+ 
+ 	while ((value = strsep(&tmp, ":")) && (pos != (EVP_MAX_MD_SIZE - 1))) {
+ 		sscanf(value, "%02x", (unsigned int*)&rtp->remote_fingerprint[pos++]);
+ 	}
++	
++	/* SRTP_DTLS: do the same with RTCP */
++	while ((value = strsep(&tmp, ":")) && (pos != (EVP_MAX_MD_SIZE - 1))) {
++		sscanf(value, "%02x", (unsigned int*)&rtp->rtcp->remote_fingerprint[pos++]);
++	}
+ }
+ 
+-static const char *ast_rtp_dtls_get_fingerprint(struct ast_rtp_instance *instance, enum ast_rtp_dtls_hash hash)
++static const char *ast_rtp_dtls_get_fingerprint(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg, enum ast_rtp_dtls_hash fingerprint_type)
+ {
+ 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+ 
+-	if (hash != AST_RTP_DTLS_HASH_SHA1) {
++        ast_debug(2, "SRTP_DTLS--Inside ast_rtp_dtls_get_fingerprint\n");
++	if (rtp->remote_fingerprint_type != fingerprint_type)
++	{
+ 		return NULL;
+ 	}
++		if (rtp->local_fingerprint_type == rtp->remote_fingerprint_type)
++	{
++		return rtp->local_fingerprint;
++	}
++	else
++	{
++		/* Remote fingerprint type is different from local fingerprint type
++		   recaclulate the local fingerprint */
++		if (dtls_cfg != NULL && dtls_cfg->certfile != NULL)
++		{
++			BIO *certbio;
++			unsigned char fingerprint[EVP_MAX_MD_SIZE];
++			char *local_fingerprint = rtp->local_fingerprint;
++			unsigned int size = 0;
++			unsigned int i = 0;
++			X509 *cert;
++			unsigned int failed = 0;
++			if (!(certbio = BIO_new(BIO_s_file()))) {
++				ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
++				instance);
++				return NULL;
++			}
+ 
+-	return rtp->local_fingerprint;
++			if (rtp->remote_fingerprint_type == AST_RTP_DTLS_HASH_SHA256)
++			{
++				if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||
++		                  !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||
++		                  !X509_digest(cert, EVP_sha256(), fingerprint, &size) ||
++		                  !size) {
++					failed = 1;
++					ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n",
++					        dtls_cfg->certfile, instance);
++				}
++			}
++			else if (rtp->remote_fingerprint_type == AST_RTP_DTLS_HASH_SHA1)
++			{
++				if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||
++		                  !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||
++		                  !X509_digest(cert, EVP_sha1(), fingerprint, &size) ||
++		                  !size) {
++					failed = 1;
++					ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n",
++					        dtls_cfg->certfile, instance);
++				}
++			}
++			BIO_free_all(certbio);
++			if (!failed)
++			{
++			    for (i = 0; i < size; i++) {
++			    	sprintf(local_fingerprint, "%.2X:", fingerprint[i]);
++		     	    	local_fingerprint += 3;
++			    }
++			    *(local_fingerprint-1) = 0;
++			    rtp->local_fingerprint_type = rtp->remote_fingerprint_type;
++			    return rtp->local_fingerprint;
++			}
++			else
++			{
++			    return NULL;
++			}
++		}
++		else
++		{
++			return NULL;
++		}
++	}
+ }
+ 
+ /* DTLS RTP Engine interface declaration */
+@@ -1046,18 +1320,11 @@ static struct ast_rtp_engine asterisk_rtp_engine = {
+ static void rtp_learning_seq_init(struct rtp_learning_info *info, uint16_t seq);
+ 
+ #ifdef USE_PJPROJECT
+-static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status)
+-{
+-	struct ast_rtp *rtp = ice->user_data;
+-
+-	if (!strictrtp) {
+-		return;
+-	}
+-
+-	rtp->strict_rtp_state = STRICT_RTP_LEARN;
+-	rtp_learning_seq_init(&rtp->rtp_source_learn, (uint16_t)rtp->seqno);
+-}
+-
++/* SRTP_DTLS: callback to known when ICE is complete */
++#ifdef HAVE_OPENSSL_SRTP
++static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp);
++#endif
++/*SRTP_DTLS */
+ 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;
+@@ -1075,6 +1342,16 @@ static pj_status_t ast_rtp_on_ice_tx_pkt(pj_ice_sess *ice, unsigned comp_id, uns
+ 
+ 	if (transport_id == TRANSPORT_SOCKET_RTP) {
+ 		/* Traffic is destined to go right out the RTP socket we already have */
++				/* SRTP_DTLS : are we sending DTLS? */
++		if(dtlsdebug > 1)
++			ast_verbose(VERBOSE_PREFIX_3 "[RTP] ast_rtp_on_ice_tx_pkt (%zu)\n", size);
++		const char *out = pkt;
++		if ((*out >= 20) && (*out <= 64)) {
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTP] Sending DTLS data (%zu)\n", size);
++			}
++		}
+ 		status = pj_sock_sendto(rtp->s, pkt, &_size, 0, dst_addr, dst_addr_len);
+ 		/* sendto on a connectionless socket should send all the data, or none at all */
+ 		ast_assert(_size == size || status != PJ_SUCCESS);
+@@ -1102,6 +1379,48 @@ static pj_status_t ast_rtp_on_ice_tx_pkt(pj_ice_sess *ice, unsigned comp_id, uns
+ 	return status;
+ }
+ 
++static void ast_rtp_on_ice_complete(pj_ice_sess *ice, pj_status_t status) {
++	struct ast_rtp *rtp = ice->user_data;
++	ast_verbose(VERBOSE_PREFIX_3 "ICE is now complete\n");
++	rtp->icecomplete = 1;
++	/* SRTP_DTLS: do the same with RTCP (FIXME is this true??) */
++	rtp->rtcp->icecomplete = 1;
++	/* SRTP_DTLS: since ICE has been completed, we can do the DTLS handshake */
++	if(rtp->icecomplete) {
++		if(dtlsdebug)
++		{
++			ast_verbose(VERBOSE_PREFIX_3 "[RTP] ICE has been completed, yay!\n");
++		}
++		rtp->icecomplete = 0;
++		rtp->icedone = 1;
++		if (rtp->ssl) {
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTP]    >> Doing DTLS handshake as well...\n");
++			}
++			SSL_do_handshake(rtp->ssl);
++			dtls_srtp_check_pending(rtp->instance, rtp);
++		}
++	}
++	/* SRTP_DTLS: do the same with RTCP */
++	if(rtp->rtcp->icecomplete) {
++		if(dtlsdebug)
++		{
++			ast_verbose(VERBOSE_PREFIX_3 "[RTCP] ICE has been completed, yay!\n");
++		}
++		rtp->rtcp->icecomplete = 0;
++		rtp->rtcp->icedone = 1;
++		if (rtp->rtcp->ssl) {
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> Doing DTLS handshake as well...\n");
++			}
++			SSL_do_handshake(rtp->rtcp->ssl);
++			dtls_srtp_check_pending(rtp->instance, rtp);
++		}
++	}
++}
++
+ /* ICE Session interface declaration */
+ static pj_ice_sess_cb ast_rtp_ice_sess_cb = {
+ 	.on_ice_complete = ast_rtp_on_ice_complete,
+@@ -1248,6 +1567,12 @@ static inline int rtcp_debug_test_addr(struct ast_sockaddr *addr)
+ }
+ 
+ #ifdef HAVE_OPENSSL_SRTP
++/* SRTP_DTLS: DTLS certificate verification callback */
++static int dtls_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
++	/* We just use the verify_callback to request a certificate from the client */
++	return 1;
++}
++/*SRTP_DTLS */
+ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp)
+ {
+ 	size_t pending = BIO_ctrl_pending(rtp->write_bio);
+@@ -1258,6 +1583,12 @@ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct as
+ 		struct ast_sockaddr remote_address = { {0, } };
+ 		int ice;
+ 
++				/*SRTP_DTLS */
++		if(dtlsdebug)
++		{
++			ast_verbose(VERBOSE_PREFIX_3 "[RTP]   >> Going to send DTLS data: %zu bytes\n", pending);
++		}
++		/*SRTP_DTLS */
+ 		ast_rtp_instance_get_remote_address(instance, &remote_address);
+ 
+ 		/* If we do not yet know an address to send this to defer it until we do */
+@@ -1266,9 +1597,51 @@ static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct as
+ 		}
+ 
+ 		out = BIO_read(rtp->write_bio, outgoing, sizeof(outgoing));
++		/*SRTP_DTLS */
++		if(dtlsdebug)
++		{
++			ast_verbose(VERBOSE_PREFIX_3 "[RTP]   >> >> Read %zu bytes from the write_BIO...\n", pending);
++		}
++		/*SRTP_DTLS */
+ 
+ 		__rtp_sendto(instance, outgoing, out, 0, &remote_address, 0, &ice, 0);
++				/*SRTP_DTLS */
++		if(dtlsdebug)
++		{
++			ast_verbose(VERBOSE_PREFIX_3 "[RTP]   >> >> Called __rtp_sendto! (%zu)\n", pending);
++		}
++		/*SRTP_DTLS */
+ 	}
++
++	/* SRTP_DTLS: do the same with RTCP */
++	pending = BIO_ctrl_pending(rtp->rtcp->write_bio);
++	if (pending > 0) {
++		if(dtlsdebug)
++		ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> Going to send DTLS data: %zu bytes\n", pending);
++		char outgoing[pending];
++		size_t out;
++		struct ast_sockaddr remote_address = { {0, } };
++		int ice;
++		//~ ast_rtp_instance_get_remote_address(instance, &remote_address);
++		if (ast_sockaddr_isnull(&rtp->rtcp->them)) {
++			return;
++		}
++		ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
++		if (ast_sockaddr_isnull(&remote_address)) {
++			return;
++		}
++		out = BIO_read(rtp->rtcp->write_bio, outgoing, sizeof(outgoing));
++		if(dtlsdebug)
++		{
++			ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> >> Read %zu bytes from the write_BIO...\n", pending);
++		}
++		__rtp_sendto(instance, outgoing, out, 0, &remote_address, 1, &ice, 0);
++		if(dtlsdebug)
++		{
++			ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> >> Called __rtp_sendto! (%zu)\n", pending);
++		}
++	}
++	/* SRTP_DTLS: */
+ }
+ 
+ static int dtls_srtp_renegotiate(const void *data)
+@@ -1278,6 +1651,9 @@ static int dtls_srtp_renegotiate(const void *data)
+ 
+ 	SSL_renegotiate(rtp->ssl);
+ 	SSL_do_handshake(rtp->ssl);
++		/* SRTP_DTLS: do the same with RTCP */
++	SSL_do_handshake(rtp->rtcp->ssl);
++	/*SRTP_DTLS */
+ 	dtls_srtp_check_pending(instance, rtp);
+ 
+ 	rtp->rekeyid = -1;
+@@ -1307,25 +1683,40 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as
+ 			unsigned char fingerprint[EVP_MAX_MD_SIZE];
+ 			unsigned int size;
+ 
+-			if (!X509_digest(certificate, EVP_sha1(), fingerprint, &size) ||
+-			    !size ||
+-			    memcmp(fingerprint, rtp->remote_fingerprint, size)) {
+-				X509_free(certificate);
+-				ast_log(LOG_WARNING, "Fingerprint provided by remote party does not match that of peer certificate on RTP instance '%p'\n",
++			if (rtp->remote_fingerprint_type == AST_RTP_DTLS_HASH_SHA1)
++			{
++				if (!X509_digest(certificate, EVP_sha1(), fingerprint, &size) ||
++			    	   !size ||
++			    	   memcmp(fingerprint, rtp->remote_fingerprint, size)) {
++					X509_free(certificate);
++					ast_log(LOG_WARNING, "Fingerprint provided by remote party does not match that of peer certificate on RTP instance '%p'\n",
+ 					instance);
+-				return -1;
++					return -1;
++				}
++			}
++			else if (rtp->remote_fingerprint_type == AST_RTP_DTLS_HASH_SHA256 )
++			{
++				if (!X509_digest(certificate, EVP_sha256(), fingerprint, &size) ||
++			    	   !size ||
++			    	   memcmp(fingerprint, rtp->remote_fingerprint, size)) {
++					X509_free(certificate);
++					ast_log(LOG_WARNING, "Fingerprint provided by remote party does not match that of peer certificate on RTP instance '%p'\n",
++					instance);
++				   return -1;
++
++				}
+ 			}
+ 		}
+ 
+ 		X509_free(certificate);
+ 	}
+ 
+-	/* Ensure that certificate verification was successful */
+-	if (SSL_get_verify_result(rtp->ssl) != X509_V_OK) {
+-		ast_log(LOG_WARNING, "Peer certificate on RTP instance '%p' failed verification test\n",
+-			instance);
+-		return -1;
+-	}
++	/* SRTP_DTLS */
++	if(dtlsdebug)
++	{
++		ast_verbose(VERBOSE_PREFIX_3 "Verification was ok :-)\n");
++ 	}
++	/* SRTP_DTLS */
+ 
+ 	/* 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)) {
+@@ -1395,6 +1786,10 @@ static int dtls_srtp_setup(struct ast_rtp *rtp, struct ast_srtp *srtp, struct as
+ 			goto error;
+ 		}
+ 	}
++	/* SRTP_DTLS: done with DTLS-SRTP */
++	ast_verbose(VERBOSE_PREFIX_3 "Looks like SRTP setup was completed...\n");
++	rtp->dtlsdone = 1;
++	/* SRTP_DTLS */
+ 
+ 	return 0;
+ 
+@@ -1426,6 +1821,12 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
+ 
+ 		/* If this is an SSL packet pass it to OpenSSL for processing */
+ 		if ((*in >= 20) && (*in <= 64)) {
++					/* SRTP_DTLS */
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTP] Received a DTLS message\n");
++			}
++			/* SRTP_DTLS */
+ 			int res = 0;
+ 
+ 			/* If no SSL session actually exists terminate things */
+@@ -1443,10 +1844,27 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
+ 
+ 			dtls_srtp_check_pending(instance, rtp);
+ 
+-			BIO_write(rtp->read_bio, buf, len);
++			/* SRTP_DTLS */
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTP]   >> >> writing %d bytes on read_BIO (to have it read later)\n", len);
++			}
++			int written = BIO_write(rtp->read_bio, buf, len);
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTP]   >> >> >> actually wrote %d bytes (%s)\n", written, BIO_should_retry(rtp->read_bio) ? "should retry" : "should NOT retry");
++			}
++			/* SRTP_DTLS */
+ 
+ 			len = SSL_read(rtp->ssl, buf, len);
+ 
++						/* SRTP_DTLS */
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTP]  >> >> read %d bytes from SSL\n", len);
++			}
++			/* SRTP_DTLS */
++
+ 			dtls_srtp_check_pending(instance, rtp);
+ 
+ 			if (rtp->dtls_failure) {
+@@ -1457,6 +1875,7 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
+ 
+ 			if (SSL_is_init_finished(rtp->ssl)) {
+ 				/* Any further connections will be existing since this is now established */
++				ast_verbose(VERBOSE_PREFIX_3 "[RTP]   >> DTLS established, yay!\n");
+ 				rtp->connection = AST_RTP_DTLS_CONNECTION_EXISTING;
+ 
+ 				/* Use the keying material to set up key/salt information */
+@@ -1465,6 +1884,70 @@ static int __rtp_recvfrom(struct ast_rtp_instance *instance, void *buf, size_t s
+ 
+ 			return res;
+ 		}
++	} /* SRTP_DTLS -- since we don't do RTCP mux, we need DTLS for RTCP as well */
++	else
++	{
++		char *in = buf;
++
++		dtls_srtp_check_pending(instance, rtp);
++
++		/* If this is an SSL packet pass it to OpenSSL for processing */
++		if ((*in >= 20) && (*in <= 64)) {
++			if(dtlsdebug)
++			ast_verbose(VERBOSE_PREFIX_3 "[RTCP] Received a DTLS message\n");
++			int res = 0;
++
++			/* If no SSL session actually exists terminate things */
++			if (!rtp->rtcp->ssl) {
++				ast_log(LOG_ERROR, "Received SSL traffic on RTP instance '%p' without an SSL session\n",
++					instance);
++				return -1;
++			}
++
++			/* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */
++			if (rtp->rtcp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
++				rtp->rtcp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
++				SSL_set_accept_state(rtp->rtcp->ssl);
++			}
++
++			dtls_srtp_check_pending(instance, rtp);
++
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> >> writing %d bytes on read_BIO (to have it read later)\n", len);
++			}
++			int written = BIO_write(rtp->rtcp->read_bio, buf, len);
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> >> >> actually wrote %d bytes (%s)\n", written, BIO_should_retry(rtp->rtcp->read_bio) ? "should retry" : "should NOT retry");
++			}
++
++			len = SSL_read(rtp->rtcp->ssl, buf, len);
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTCP]  >> >> read %d bytes from SSL\n", len);
++			}
++
++			dtls_srtp_check_pending(instance, rtp);
++
++			if (rtp->rtcp->dtls_failure) {
++				ast_log(LOG_ERROR, "DTLS failure occurred on RTCP instance '%p', terminating\n",
++					instance);
++				return -1;
++			}
++
++			if (SSL_is_init_finished(rtp->rtcp->ssl)) {
++				ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> DTLS established, yay!\n");
++				/* Any further connections will be existing since this is now established */
++				rtp->rtcp->connection = AST_RTP_DTLS_CONNECTION_EXISTING;
++
++				/* Use the keying material to set up key/salt information */
++				//~ res = dtls_srtp_setup(rtp, srtp, instance);
++				rtp->rtcp->dtlsdone = 1;
++			}
++
++			return res;
++		}
+ 	}
+ #endif
+ 
+@@ -1542,11 +2025,44 @@ static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t siz
+ 
+ static int rtcp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice)
+ {
++	/* SRTP_DTLS: don't send RTCP until ICE completed (FIXME useless? pjnath already does this?) */
++	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++	if(rtp->rtcp->ssl && !rtp->rtcp->dtlsdone) {
++		const char *out = buf;
++		if ((*out >= 20) && (*out <= 64)) {
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTCP] Sending DTLS data (%zu)\n", size);
++			}
++		} else if(rtp->rtcp->connection == AST_RTP_DTLS_CONNECTION_NEW) {
++			if(dtlsdebug)
++			{
++				ast_verbose(VERBOSE_PREFIX_3 "[RTCP]   >> Still waiting for the DTLS handshake to complete, discarding packet (%zu)\n", size);
++			}
++			return 0;
++		}
++	}
++	/* SRTP_DTLS */
+ 	return __rtp_sendto(instance, buf, size, flags, sa, 1, ice, 1);
+ }
+ 
+ static int rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int *ice)
+ {
++	/*SRTP_DTLS */
++	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
++	/* don't send RTP until DTLS handshake has been completed */
++	if(rtp->ssl && !rtp->dtlsdone) {
++		const char *out = buf;
++		if ((*out >= 20) && (*out <= 64)) {
++			if(dtlsdebug)
++			ast_verbose(VERBOSE_PREFIX_3 "[RTP] Sending DTLS data (%zu)\n", size);
++		} else if(rtp->connection == AST_RTP_DTLS_CONNECTION_NEW) {
++			if(dtlsdebug)
++			ast_verbose(VERBOSE_PREFIX_3 "[RTP]   >> Still waiting for the DTLS handshake to complete, discarding packet (%zu)\n", size);
++			return 0;
++		}
++	}
++	/*SRTP_DTLS */
+ 	return __rtp_sendto(instance, buf, size, flags, sa, 0, ice, 1);
+ }
+ 
+@@ -1851,7 +2367,13 @@ static int ast_rtp_new(struct ast_rtp_instance *instance,
+ 
+ #ifdef HAVE_OPENSSL_SRTP
+ 	rtp->rekeyid = -1;
++	rtp->local_fingerprint_type = AST_RTP_DTLS_HASH_NONE;
++	rtp->remote_fingerprint_type = AST_RTP_DTLS_HASH_NONE;
++
+ #endif
++	/* SRTP_DTLS: make rtp aware of instance as well... */
++	rtp->instance = instance;
++	/*SRTP_DTLS */
+ 
+ 	return 0;
+ }
+@@ -4261,14 +4783,19 @@ static int ast_rtp_sendcng(struct ast_rtp_instance *instance, int level)
+ static int ast_rtp_activate(struct ast_rtp_instance *instance)
+ {
+ 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+-
+ 	if (!rtp->ssl) {
+ 		return 0;
+ 	}
+ 
+-	SSL_do_handshake(rtp->ssl);
+-
+-	dtls_srtp_check_pending(instance, rtp);
++	/* SRTP_DTLS: only do the DTLS handshake right now if there's no ICE or if it has completed */
++	if(!rtp->ice || rtp->icedone) {
++		ast_verbose(VERBOSE_PREFIX_3 "  >> Doing DTLS handshake as well...\n");
++		SSL_do_handshake(rtp->ssl);
++		/* Meetecho: do the same with RTCP */
++		SSL_do_handshake(rtp->rtcp->ssl);
++		ast_verbose(VERBOSE_PREFIX_3 "  >> [activate] check pending...\n");
++		dtls_srtp_check_pending(instance, rtp);
++	}
+ 
+ 	return 0;
+ }
+@@ -4400,11 +4927,49 @@ static char *handle_cli_rtcp_set_stats(struct ast_cli_entry *e, int cmd, struct
+ 	ast_cli(a->fd, "RTCP Stats %s\n", rtcpstats ? "Enabled" : "Disabled");
+ 	return CLI_SUCCESS;
+ }
++/* SRTP_DTLS: add DTLS debugging */
++static char *handle_cli_dtls_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
++{
++	switch (cmd) {
++	case CLI_INIT:
++		e->command = "dtls set debug";
++		e->usage =
++			"Usage: dtls set debug {status|none|normal|huge}\n"
++			"       Enable/Disable DTLS debugging: normal only debugs setup and errors, huge debugs every single packet\n";
++		return NULL;
++	case CLI_GENERATE:
++		return NULL;
++	}
++
++	if (a->argc != 4)
++		return CLI_SHOWUSAGE;
++
++	if (!strncasecmp(a->argv[a->argc-1], "status", 6)) {
++		ast_cli(a->fd, "DTLS debugging %s\n", dtlsdebug > 1 ? "huge" : dtlsdebug > 0 ? "normal" : "none");
++		return CLI_SUCCESS;
++	}
++	if (!strncasecmp(a->argv[a->argc-1], "huge", 4))
++		dtlsdebug = 2;
++	else if (!strncasecmp(a->argv[a->argc-1], "normal", 6))
++		dtlsdebug = 1;
++	else if (!strncasecmp(a->argv[a->argc-1], "none", 4))
++		dtlsdebug = 0;
++	else
++		return CLI_SHOWUSAGE;
++
++	ast_cli(a->fd, "DTLS debugging %s\n", dtlsdebug > 1 ? "huge" : dtlsdebug > 0 ? "normal" : "none");
++	return CLI_SUCCESS;
++}
++/*SRTP_DTLS */
++
+ 
+ static struct ast_cli_entry cli_rtp[] = {
+ 	AST_CLI_DEFINE(handle_cli_rtp_set_debug,  "Enable/Disable RTP debugging"),
+ 	AST_CLI_DEFINE(handle_cli_rtcp_set_debug, "Enable/Disable RTCP debugging"),
+ 	AST_CLI_DEFINE(handle_cli_rtcp_set_stats, "Enable/Disable RTCP stats"),
++	/* SRTP_DTLS: add DTLS debugging */
++	AST_CLI_DEFINE(handle_cli_dtls_set_debug, "Enable/Disable DTLS debugging"),
++	/*SRTP_DTLS */
+ };
+ 
+ static int rtp_reload(int reload)
diff --git a/debian/patches/series b/debian/patches/series
index e10e909..974966f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -32,3 +32,6 @@ reenable
 freeradius-client
 ignore_failed_channels.patch
 suppress_warning_rasterisk.patch
+
+dtls_srtp_patch
+

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/asterisk.git



More information about the Pkg-voip-commits mailing list