[asterisk-commits] file: branch file/sha256-a-harsh-reality r417132 - /team/file/sha256-a-harsh-...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Mon Jun 23 11:23:03 CDT 2014


Author: file
Date: Mon Jun 23 11:23:00 2014
New Revision: 417132

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=417132
Log:
Perform DTLS handshake on RTCP.

Modified:
    team/file/sha256-a-harsh-reality/res/res_rtp_asterisk.c

Modified: team/file/sha256-a-harsh-reality/res/res_rtp_asterisk.c
URL: http://svnview.digium.com/svn/asterisk/team/file/sha256-a-harsh-reality/res/res_rtp_asterisk.c?view=diff&rev=417132&r1=417131&r2=417132
==============================================================================
--- team/file/sha256-a-harsh-reality/res/res_rtp_asterisk.c (original)
+++ team/file/sha256-a-harsh-reality/res/res_rtp_asterisk.c Mon Jun 23 11:23:00 2014
@@ -361,6 +361,14 @@
 	double normdevrtt;
 	double stdevrtt;
 	unsigned int rtt_count;
+
+#ifdef HAVE_OPENSSL_SRTP
+	SSL *ssl;         /*!< SSL session */
+	BIO *read_bio;    /*!< Memory buffer for reading */
+	BIO *write_bio;   /*!< Memory buffer for writing */
+	enum ast_rtp_dtls_setup dtls_setup; /*!< Current setup state */
+	enum ast_rtp_dtls_connection connection; /*!< Whether this is a new or existing connection */
+#endif
 };
 
 struct rtp_red {
@@ -408,7 +416,7 @@
 
 #ifdef HAVE_OPENSSL_SRTP
 static int ast_rtp_activate(struct ast_rtp_instance *instance);
-static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp);
+static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp);
 #endif
 
 static int __rtp_sendto(struct ast_rtp_instance *instance, void *buf, size_t size, int flags, struct ast_sockaddr *sa, int rtcp, int *ice, int use_srtp);
@@ -804,6 +812,69 @@
 	return 1;
 }
 
+static int dtls_setup_rtcp(struct ast_rtp_instance *instance)
+{
+	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+
+	if (!rtp->ssl_ctx) {
+		return 0;
+	}
+
+	rtp->rtcp->dtls_setup = rtp->dtls_setup;
+
+	if (!(rtp->rtcp->ssl = SSL_new(rtp->ssl_ctx))) {
+		ast_log(LOG_ERROR, "Failed to allocate memory for SSL context on RTCP of RTP 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 of RTP 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 of RTP 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:
+	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;
+	}
+	return -1;
+}
+
 static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
@@ -992,19 +1063,26 @@
 		SSL_free(rtp->ssl);
 		rtp->ssl = NULL;
 	}
+
+	if (rtp->rtcp && rtp->rtcp->ssl) {
+		SSL_free(rtp->rtcp->ssl);
+		rtp->rtcp->ssl = NULL;
+	}
 }
 
 static void ast_rtp_dtls_reset(struct ast_rtp_instance *instance)
 {
 	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
 
-	/* If the SSL session is not yet finalized don't bother resetting */
-	if (!SSL_is_init_finished(rtp->ssl)) {
-		return;
-	}
-
-	SSL_shutdown(rtp->ssl);
-	rtp->connection = AST_RTP_DTLS_CONNECTION_NEW;
+	if (SSL_is_init_finished(rtp->ssl)) {
+		SSL_shutdown(rtp->ssl);
+		rtp->connection = AST_RTP_DTLS_CONNECTION_NEW;
+	}
+
+	if (rtp->rtcp && SSL_is_init_finished(rtp->rtcp->ssl)) {
+		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)
@@ -1021,26 +1099,25 @@
 	return rtp->dtls_setup;
 }
 
-static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup)
-{
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-	enum ast_rtp_dtls_setup old = rtp->dtls_setup;
+static void dtls_set_setup(enum ast_rtp_dtls_setup *dtls_setup, enum ast_rtp_dtls_setup setup, SSL *ssl)
+{
+	enum ast_rtp_dtls_setup old = *dtls_setup;
 
 	switch (setup) {
 	case AST_RTP_DTLS_SETUP_ACTIVE:
-		rtp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
+		*dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
 		break;
 	case AST_RTP_DTLS_SETUP_PASSIVE:
-		rtp->dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE;
+		*dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE;
 		break;
 	case AST_RTP_DTLS_SETUP_ACTPASS:
 		/* We can't respond to an actpass setup with actpass ourselves... so respond with active, as we can initiate connections */
-		if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
-			rtp->dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE;
+		if (*dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
+			*dtls_setup = AST_RTP_DTLS_SETUP_ACTIVE;
 		}
 		break;
 	case AST_RTP_DTLS_SETUP_HOLDCONN:
-		rtp->dtls_setup = AST_RTP_DTLS_SETUP_HOLDCONN;
+		*dtls_setup = AST_RTP_DTLS_SETUP_HOLDCONN;
 		break;
 	default:
 		/* This should never occur... if it does exit early as we don't know what state things are in */
@@ -1048,21 +1125,34 @@
 	}
 
 	/* If the setup state did not change we go on as if nothing happened */
-	if (old == rtp->dtls_setup) {
+	if (old == *dtls_setup) {
 		return;
 	}
 
 	/* If they don't want us to establish a connection wait until later */
-	if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_HOLDCONN) {
+	if (*dtls_setup == AST_RTP_DTLS_SETUP_HOLDCONN) {
 		return;
 	}
 
-	if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) {
-		SSL_set_connect_state(rtp->ssl);
-	} else if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
-		SSL_set_accept_state(rtp->ssl);
+	if (*dtls_setup == AST_RTP_DTLS_SETUP_ACTIVE) {
+		SSL_set_connect_state(ssl);
+	} else if (*dtls_setup == AST_RTP_DTLS_SETUP_PASSIVE) {
+		SSL_set_accept_state(ssl);
 	} else {
 		return;
+	}
+}
+
+static void ast_rtp_dtls_set_setup(struct ast_rtp_instance *instance, enum ast_rtp_dtls_setup setup)
+{
+	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+
+	if (rtp->ssl) {
+		dtls_set_setup(&rtp->dtls_setup, setup, rtp->ssl);
+	}
+
+	if (rtp->rtcp && rtp->rtcp->ssl) {
+		dtls_set_setup(&rtp->rtcp->dtls_setup, setup, rtp->rtcp->ssl);
 	}
 }
 
@@ -1160,7 +1250,12 @@
 #ifdef HAVE_OPENSSL_SRTP
 	if (rtp->ssl) {
 		SSL_do_handshake(rtp->ssl);
-		dtls_srtp_check_pending(instance, rtp);
+		dtls_srtp_check_pending(instance, rtp, 0);
+	}
+
+	if (rtp->rtcp && rtp->rtcp->ssl) {
+		SSL_do_handshake(rtp->rtcp->ssl);
+		dtls_srtp_check_pending(instance, rtp, 1);
 	}
 #endif
 
@@ -1386,21 +1481,33 @@
 	rtp->dtlstimerid = -1;
 	ast_mutex_unlock(&rtp->dtls_timer_lock);
 
-	if (rtp->ssl) {
+	if (rtp->ssl && !SSL_is_init_finished(rtp->ssl)) {
 		DTLSv1_handle_timeout(rtp->ssl);
 	}
-
-	dtls_srtp_check_pending(instance, rtp);
+	dtls_srtp_check_pending(instance, rtp, 0);
+
+	if (rtp->rtcp && rtp->rtcp->ssl && !SSL_is_init_finished(rtp->rtcp->ssl)) {
+		DTLSv1_handle_timeout(rtp->rtcp->ssl);
+	}
+	dtls_srtp_check_pending(instance, rtp, 1);
 
 	ao2_ref(instance, -1);
 
 	return 0;
 }
 
-static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp)
-{
-	size_t pending = BIO_ctrl_pending(rtp->write_bio);
+static void dtls_srtp_check_pending(struct ast_rtp_instance *instance, struct ast_rtp *rtp, int rtcp)
+{
+	SSL *ssl = !rtcp ? rtp->ssl : rtp->rtcp->ssl;
+	BIO *write_bio = !rtcp ? rtp->write_bio : rtp->rtcp->write_bio;
+	size_t pending;
 	struct timeval dtls_timeout; /* timeout on DTLS  */
+
+	if (!ssl || !write_bio) {
+		return;
+	}
+
+	pending = BIO_ctrl_pending(write_bio);
 
 	if (pending > 0) {
 		char outgoing[pending];
@@ -1408,14 +1515,18 @@
 		struct ast_sockaddr remote_address = { {0, } };
 		int ice;
 
-		ast_rtp_instance_get_remote_address(instance, &remote_address);
+		if (!rtcp) {
+			ast_rtp_instance_get_remote_address(instance, &remote_address);
+		} else {
+			ast_sockaddr_copy(&remote_address, &rtp->rtcp->them);
+		}
 
 		/* If we do not yet know an address to send this to defer it until we do */
 		if (ast_sockaddr_isnull(&remote_address)) {
 			return;
 		}
 
-		out = BIO_read(rtp->write_bio, outgoing, sizeof(outgoing));
+		out = BIO_read(write_bio, outgoing, sizeof(outgoing));
 
 		/* Stop existing DTLS timer if running */
 		ast_mutex_lock(&rtp->dtls_timer_lock);
@@ -1424,7 +1535,7 @@
 			rtp->dtlstimerid = -1;
 		}
 
-		if (DTLSv1_get_timeout(rtp->ssl, &dtls_timeout)) {
+		if (DTLSv1_get_timeout(ssl, &dtls_timeout)) {
 			int timeout = dtls_timeout.tv_sec * 1000 + dtls_timeout.tv_usec / 1000;
 			ao2_ref(instance, +1);
 			if ((rtp->dtlstimerid = ast_sched_add(rtp->sched, timeout, dtls_srtp_handle_timeout, instance)) < 0) {
@@ -1434,7 +1545,7 @@
 		}
 		ast_mutex_unlock(&rtp->dtls_timer_lock);
 
-		__rtp_sendto(instance, outgoing, out, 0, &remote_address, 0, &ice, 0);
+		__rtp_sendto(instance, outgoing, out, 0, &remote_address, rtcp, &ice, 0);
 	}
 }
 
@@ -1445,7 +1556,13 @@
 
 	SSL_renegotiate(rtp->ssl);
 	SSL_do_handshake(rtp->ssl);
-	dtls_srtp_check_pending(instance, rtp);
+	dtls_srtp_check_pending(instance, rtp, 0);
+
+	if (rtp->rtcp && rtp->rtcp->ssl) {
+		SSL_renegotiate(rtp->rtcp->ssl);
+		SSL_do_handshake(rtp->rtcp->ssl);
+		dtls_srtp_check_pending(instance, rtp, 1);
+	}
 
 	rtp->rekeyid = -1;
 	ao2_ref(instance, -1);
@@ -1598,50 +1715,53 @@
 	}
 
 #ifdef HAVE_OPENSSL_SRTP
-	if (!rtcp) {
-		dtls_srtp_check_pending(instance, rtp);
-
-		/* If this is an SSL packet pass it to OpenSSL for processing */
-		if ((*in >= 20) && (*in <= 64)) {
-			int res = 0;
-
-			/* If no SSL session actually exists terminate things */
-			if (!rtp->ssl) {
-				ast_log(LOG_ERROR, "Received SSL traffic on RTP instance '%p' without an SSL session\n",
-					instance);
-				return -1;
-			}
-
-			/* If we don't yet know if we are active or passive and we receive a packet... we are obviously passive */
-			if (rtp->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
-				rtp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
-				SSL_set_accept_state(rtp->ssl);
-			}
-
-			dtls_srtp_check_pending(instance, rtp);
-
-			BIO_write(rtp->read_bio, buf, len);
-
-			len = SSL_read(rtp->ssl, buf, len);
-
-			dtls_srtp_check_pending(instance, rtp);
-
-			if (rtp->dtls_failure) {
-				ast_log(LOG_ERROR, "DTLS failure occurred on RTP instance '%p', terminating\n",
-					instance);
-				return -1;
-			}
-
-			if (SSL_is_init_finished(rtp->ssl)) {
-				/* Any further connections will be existing since this is now established */
+	dtls_srtp_check_pending(instance, rtp, rtcp);
+
+	/* If this is an SSL packet pass it to OpenSSL for processing */
+	if ((*in >= 20) && (*in <= 64)) {
+		SSL *ssl = !rtcp ? rtp->ssl : rtp->rtcp->ssl;
+		BIO *read_bio = !rtcp ? rtp->read_bio : rtp->rtcp->read_bio;
+		int res = 0;
+
+		/* If no SSL session actually exists terminate things */
+		if (!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->dtls_setup == AST_RTP_DTLS_SETUP_ACTPASS) {
+			rtp->dtls_setup = AST_RTP_DTLS_SETUP_PASSIVE;
+			SSL_set_accept_state(ssl);
+		}
+
+		dtls_srtp_check_pending(instance, rtp, rtcp);
+
+		BIO_write(read_bio, buf, len);
+
+		len = SSL_read(ssl, buf, len);
+
+		dtls_srtp_check_pending(instance, rtp, rtcp);
+
+		if (rtp->dtls_failure) {
+			ast_log(LOG_ERROR, "DTLS failure occurred on RTP instance '%p', terminating\n",
+				instance);
+			return -1;
+		}
+
+		if (SSL_is_init_finished(ssl)) {
+			/* Any further connections will be existing since this is now established */
+			if (!rtcp) {
 				rtp->connection = AST_RTP_DTLS_CONNECTION_EXISTING;
-
 				/* Use the keying material to set up key/salt information */
 				res = dtls_srtp_setup(rtp, srtp, instance);
+			} else {
+				rtp->rtcp->connection = AST_RTP_DTLS_CONNECTION_EXISTING;
 			}
-
-			return res;
-		}
+		}
+
+		return res;
 	}
 #endif
 
@@ -2107,6 +2227,11 @@
 		 * RTP instance while it's active.
 		 */
 		close(rtp->rtcp->s);
+#ifdef HAVE_OPENSSL_SRTP
+		if (rtp->rtcp->ssl) {
+			SSL_free(rtp->rtcp->ssl);
+		}
+#endif
 		ast_free(rtp->rtcp);
 	}
 
@@ -4183,6 +4308,10 @@
 			}
 #endif
 
+#ifdef HAVE_OPENSSL_SRTP
+			dtls_setup_rtcp(instance);
+#endif
+
 			return;
 		} else {
 			if (rtp->rtcp) {
@@ -4198,6 +4327,11 @@
 					rtp->rtcp->schedid = -1;
 				}
 				close(rtp->rtcp->s);
+#ifdef HAVE_OPENSSL_SRTP
+				if (rtp->rtcp->ssl) {
+					SSL_free(rtp->rtcp->ssl);
+				}
+#endif
 				ast_free(rtp->rtcp);
 				rtp->rtcp = NULL;
 			}
@@ -4496,16 +4630,19 @@
 
 	/* If ICE negotiation is enabled the DTLS Handshake will be performed upon completion of it */
 #ifdef USE_PJPROJECT
-	if (!rtp->ssl || rtp->ice) {
-#else
-	if (!rtp->ssl) {
+	if (rtp->ice) {
+		return 0;
+	}
 #endif
-		return 0;
-	}
-
-	SSL_do_handshake(rtp->ssl);
-
-	dtls_srtp_check_pending(instance, rtp);
+
+	if (rtp->ssl) {
+		SSL_do_handshake(rtp->ssl);
+		dtls_srtp_check_pending(instance, rtp, 0);
+	}
+	if (rtp->rtcp && rtp->rtcp->ssl) {
+		SSL_do_handshake(rtp->rtcp->ssl);
+		dtls_srtp_check_pending(instance, rtp, 1);
+	}
 
 	return 0;
 }




More information about the asterisk-commits mailing list