aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authortwilson <twilson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-06-08 05:29:08 +0000
committertwilson <twilson@f38db490-d61c-443f-a65b-d21fe96a405b>2010-06-08 05:29:08 +0000
commit9b1a36a294342fc418d9a359a4cf06bd90c4acb9 (patch)
treeecc27fc0db142ea1cd335a74cd1265f993fecd11 /main
parent5f87b66641d86dbe7afec3b083016b2b1aceafc7 (diff)
Add SRTP support for Asterisk
After 5 years in mantis and over a year on reviewboard, SRTP support is finally being comitted. This includes generic CHANNEL dialplan functions that work for getting the status of whether a call has secure media or signaling as defined by the underlying channel technology and for setting whether or not a new channel being bridged to a calling channel should have secure signaling or media. See doc/tex/secure-calls.tex for examples. Original patch by mikma, updated for trunk and revised by me. (closes issue #5413) Reported by: mikma Tested by: twilson, notthematrix, hemanshurpatel Review: https://reviewboard.asterisk.org/r/191/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@268894 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/asterisk.exports.in3
-rw-r--r--main/channel.c48
-rw-r--r--main/global_datastores.c26
-rw-r--r--main/rtp_engine.c49
4 files changed, 126 insertions, 0 deletions
diff --git a/main/asterisk.exports.in b/main/asterisk.exports.in
index ef1dcddc2..b02550fdb 100644
--- a/main/asterisk.exports.in
+++ b/main/asterisk.exports.in
@@ -40,6 +40,9 @@
LINKER_SYMBOL_PREFIXgetloadavg;
LINKER_SYMBOL_PREFIXntohll;
LINKER_SYMBOL_PREFIXhtonll;
+ LINKER_SYMBOL_PREFIXres_srtp;
+ LINKER_SYMBOL_PREFIXres_srtp_policy;
+ LINKER_SYMBOL_PREFIXsecure_call_info;
local:
*;
};
diff --git a/main/channel.c b/main/channel.c
index 42d42fb1b..c50cb6e13 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -65,6 +65,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/timing.h"
#include "asterisk/autochan.h"
#include "asterisk/stringfields.h"
+#include "asterisk/global_datastores.h"
#include "asterisk/data.h"
#ifdef HAVE_EPOLL
@@ -4803,6 +4804,46 @@ struct ast_channel *ast_request_and_dial(const char *type, format_t format, cons
return __ast_request_and_dial(type, format, requestor, data, timeout, outstate, cidnum, cidname, NULL);
}
+static int set_security_requirements(const struct ast_channel *requestor, struct ast_channel *out)
+{
+ int ops[2][2] = {
+ {AST_OPTION_SECURE_SIGNALING, 0},
+ {AST_OPTION_SECURE_MEDIA, 0},
+ };
+ int i;
+ struct ast_channel *r = (struct ast_channel *) requestor; /* UGLY */
+ struct ast_datastore *ds;
+
+ if (!requestor || !out) {
+ return 0;
+ }
+
+ ast_channel_lock(r);
+ if ((ds = ast_channel_datastore_find(r, &secure_call_info, NULL))) {
+ struct ast_secure_call_store *encrypt = ds->data;
+ ops[0][1] = encrypt->signaling;
+ ops[1][1] = encrypt->media;
+ } else {
+ ast_channel_unlock(r);
+ return 0;
+ }
+ ast_channel_unlock(r);
+
+ for (i = 0; i < 2; i++) {
+ if (ops[i][1]) {
+ if (ast_channel_setoption(out, ops[i][0], &ops[i][1], sizeof(ops[i][1]), 0)) {
+ /* We require a security feature, but the channel won't provide it */
+ return -1;
+ }
+ } else {
+ /* We don't care if we can't clear the option on a channel that doesn't support it */
+ ast_channel_setoption(out, ops[i][0], &ops[i][1], sizeof(ops[i][1]), 0);
+ }
+ }
+
+ return 0;
+}
+
struct ast_channel *ast_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
{
struct chanlist *chan;
@@ -4851,6 +4892,13 @@ struct ast_channel *ast_request(const char *type, format_t format, const struct
if (!(c = chan->tech->requester(type, capabilities | videoformat | textformat, requestor, data, cause)))
return NULL;
+ if (set_security_requirements(requestor, c)) {
+ ast_log(LOG_WARNING, "Setting security requirements failed\n");
+ c = ast_channel_release(c);
+ *cause = AST_CAUSE_BEARERCAPABILITY_NOTAVAIL;
+ return NULL;
+ }
+
/* no need to generate a Newchannel event here; it is done in the channel_alloc call */
return c;
}
diff --git a/main/global_datastores.c b/main/global_datastores.c
index 5b9630257..cddad6ec1 100644
--- a/main/global_datastores.c
+++ b/main/global_datastores.c
@@ -84,3 +84,29 @@ const struct ast_datastore_info dialed_interface_info = {
.destroy = dialed_interface_destroy,
.duplicate = dialed_interface_duplicate,
};
+
+static void secure_call_store_destroy(void *data)
+{
+ struct ast_secure_call_store *store = data;
+
+ ast_free(store);
+}
+
+static void *secure_call_store_duplicate(void *data)
+{
+ struct ast_secure_call_store *old = data;
+ struct ast_secure_call_store *new;
+
+ if (!(new = ast_calloc(1, sizeof(*new)))) {
+ return NULL;
+ }
+ new->signaling = old->signaling;
+ new->media = old->media;
+
+ return new;
+}
+const struct ast_datastore_info secure_call_info = {
+ .type = "encrypt-call",
+ .destroy = secure_call_store_destroy,
+ .duplicate = secure_call_store_duplicate,
+};
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 26881be80..2d23958ae 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -39,6 +39,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/pbx.h"
#include "asterisk/translate.h"
+struct ast_srtp_res *res_srtp = NULL;
+struct ast_srtp_policy_res *res_srtp_policy = NULL;
+
/*! Structure that represents an RTP session (instance) */
struct ast_rtp_instance {
/*! Engine that is handling this RTP instance */
@@ -67,6 +70,8 @@ struct ast_rtp_instance {
struct ast_rtp_glue *glue;
/*! Channel associated with the instance */
struct ast_channel *chan;
+ /*! SRTP info associated with the instance */
+ struct ast_srtp *srtp;
};
/*! List of RTP engines that are currently registered */
@@ -1670,3 +1675,47 @@ struct ast_channel *ast_rtp_instance_get_chan(struct ast_rtp_instance *instance)
{
return instance->chan;
}
+
+int ast_rtp_engine_register_srtp(struct ast_srtp_res *srtp_res, struct ast_srtp_policy_res *policy_res)
+{
+ if (res_srtp || res_srtp_policy) {
+ return -1;
+ }
+ if (!srtp_res || !policy_res) {
+ return -1;
+ }
+
+ res_srtp = srtp_res;
+ res_srtp_policy = policy_res;
+
+ return 0;
+}
+
+void ast_rtp_engine_unregister_srtp(void)
+{
+ res_srtp = NULL;
+ res_srtp_policy = NULL;
+}
+
+int ast_rtp_engine_srtp_is_registered(void)
+{
+ return res_srtp && res_srtp_policy;
+}
+
+int ast_rtp_instance_add_srtp_policy(struct ast_rtp_instance *instance, struct ast_srtp_policy *policy)
+{
+ if (!res_srtp) {
+ return -1;
+ }
+
+ if (!instance->srtp) {
+ return res_srtp->create(&instance->srtp, instance, policy);
+ } else {
+ return res_srtp->add_stream(instance->srtp, policy);
+ }
+}
+
+struct ast_srtp *ast_rtp_instance_get_srtp(struct ast_rtp_instance *instance)
+{
+ return instance->srtp;
+}