[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