diff options
author | twilson <twilson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-06-08 05:29:08 +0000 |
---|---|---|
committer | twilson <twilson@f38db490-d61c-443f-a65b-d21fe96a405b> | 2010-06-08 05:29:08 +0000 |
commit | 9b1a36a294342fc418d9a359a4cf06bd90c4acb9 (patch) | |
tree | ecc27fc0db142ea1cd335a74cd1265f993fecd11 /main | |
parent | 5f87b66641d86dbe7afec3b083016b2b1aceafc7 (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.in | 3 | ||||
-rw-r--r-- | main/channel.c | 48 | ||||
-rw-r--r-- | main/global_datastores.c | 26 | ||||
-rw-r--r-- | main/rtp_engine.c | 49 |
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; +} |