diff --git a/modules/auth_xkeys/Makefile b/modules/auth_xkeys/Makefile new file mode 100644 index 00000000000..ecfed105021 --- /dev/null +++ b/modules/auth_xkeys/Makefile @@ -0,0 +1,14 @@ +# +# WARNING: do not run this directly, it should be run by the master Makefile + +include ../../Makefile.defs +auto_gen= +NAME=auth_xkeys.so +LIBS= + +DEFS+=-DKAMAILIO_MOD_INTERFACE + +SERLIBPATH=../../lib +SER_LIBS+=$(SERLIBPATH)/srutils/srutils +SER_LIBS+=$(SERLIBPATH)/kcore/kcore +include ../../Makefile.modules diff --git a/modules/auth_xkeys/README b/modules/auth_xkeys/README new file mode 100644 index 00000000000..10785f84598 --- /dev/null +++ b/modules/auth_xkeys/README @@ -0,0 +1,166 @@ +AUTH_XKEYS Module + +Daniel-Constantin Mierla + + + +Edited by + +Daniel-Constantin Mierla + + + + Copyright © 2015 asipto.com + __________________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1. Overview + 2. Dependencies + + 2.1. Kamailio Modules + 2.2. External Libraries or Applications + + 3. Parameters + + 3.1. xkey (str) + + 4. Functions + + 4.1. auth_xkeys_add(hdr, kid, alg, data) + 4.2. auth_xkeys_check(hdr, kid, alg, data) + + List of Examples + + 1.1. Set xkey parameter + 1.2. auth_xkeys_add usage + 1.3. auth_xkeys_check usage + +Chapter 1. Admin Guide + + Table of Contents + + 1. Overview + 2. Dependencies + + 2.1. Kamailio Modules + 2.2. External Libraries or Applications + + 3. Parameters + + 3.1. xkey (str) + + 4. Functions + + 4.1. auth_xkeys_add(hdr, kid, alg, data) + 4.2. auth_xkeys_check(hdr, kid, alg, data) + +1. Overview + + This module provides a custom mechanism to authenticate a SIP entity + using a list of shared keys. + + It is similar to the API key based authentication used by many web + services. In short, the sender adds a particular header with a hash + token computed with the shared key and some values from the SIP request + (e.g., local IP, From/To/R-URI username, Call-ID, CSeq). + + For proper protection, it is recommended to use this authentication + mechanism over a secure channel (e.g., TLS, VPN, private network). + + The benefit is avoiding the extra traffic and processing required by + WWW-Digest authentication schema (no more 401/407 and a follow up + request with credentials). + + Another goal is to provide more elasticity for scalability needs of the + core SIP network nodes. Most of the nodes in the core network or the + interconnecting peers trust each other based on IP address. But adding + a new node requires updates to the exiting ones to trust the IP address + of the new node. On large deployments, that can become rather complex. + For example, as a replacement for IP trust relationships, the sender + can hash the local IP with the secret shared key, add it in the header + and the receiver will check if the source ip hased with the key results + in the same value. + + Not being a challenge-reply mechanism, this can be used to authenticate + SIP responses from trusted peers. + +2. Dependencies + + 2.1. Kamailio Modules + 2.2. External Libraries or Applications + +2.1. Kamailio Modules + + The following modules must be loaded before this module: + * none. + +2.2. External Libraries or Applications + + The following libraries or applications must be installed before + running Kamailio with this module loaded: + * none + +3. Parameters + + 3.1. xkey (str) + +3.1. xkey (str) + + Specify the attributes for a shared secret. The value is in the format + 'name1=value1;name2=value2;...'. The attributes can be: + * id - the id of the group for keys + * name - the name of the key within group + * value - the value of the key + * expires - expiration time (seconds) + + Default value is empty. + + Example 1.1. Set xkey parameter +... +modparam("auth_xkeys", "xkey", "id=abc;name=xyz;value=secret;expires=72000") +... + +4. Functions + + 4.1. auth_xkeys_add(hdr, kid, alg, data) + 4.2. auth_xkeys_check(hdr, kid, alg, data) + +4.1. auth_xkeys_add(hdr, kid, alg, data) + + Add a header computed with the first key in the group kid, hasing with + algorithm alg over the content of parameter data. The parameters can + include variables. + + The algorithm can be: sha256, sha384, sha512. + + This function can be used from ANY_ROUTE. + + Example 1.2. auth_xkeys_add usage +... +auth_xkeys_add("X-My-Key", "abc", "sha256", "$Ri:$fu:$ru:$hdr(CSeq)"); +... + +4.2. auth_xkeys_check(hdr, kid, alg, data) + + Check if the value of header hdr matches the value computed with the + first key in the group kid, hasing with algorithm alg over the content + of parameter data. The parameters can include variables. + + The algorithm can be: sha256, sha384, sha512. + + Note that the header is not removed by the function, it is recommended + to remove it if sending to untrusted destination. + + This function can be used from ANY_ROUTE. + + Example 1.3. auth_xkeys_check usage +... +if(!auth_xkeys_add("X-My-Key", "abc", "sha256", "$si:$fu:$ru:$hdr(CSeq)")) { + send_reply("403", "Forbidden"); + exit; +} +remove_hf("X-My-Key"); +... diff --git a/modules/auth_xkeys/auth_xkeys.c b/modules/auth_xkeys/auth_xkeys.c new file mode 100644 index 00000000000..2dbc0837264 --- /dev/null +++ b/modules/auth_xkeys/auth_xkeys.c @@ -0,0 +1,382 @@ +/** + * Copyright (C) 2015 Daniel-Constantin Mierla (asipto.com) + * + * This file is part of Kamailio, a free SIP server. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include "../../dprint.h" +#include "../../ut.h" +#include "../../trim.h" +#include "../../pvapi.h" +#include "../../data_lump.h" +#include "../../mem/shm_mem.h" +#include "../../parser/hf.h" +#include "../../parser/parse_param.h" +#include "../../parser/msg_parser.h" +#include "../../lib/srutils/shautils.h" +#include "../../lib/kcore/cmpapi.h" + +#include "auth_xkeys.h" + +typedef struct _auth_xkey { + str kid; + str kname; + str kvalue; + time_t kexpires; + struct _auth_xkey *next; + struct _auth_xkey *next_id; +} auth_xkey_t; + +static auth_xkey_t **_auth_xkeys_list = NULL; + +/** + * + */ +int auth_xkeys_list_init(void) +{ + if(_auth_xkeys_list!=NULL) + return 0; + _auth_xkeys_list = shm_malloc(sizeof(auth_xkey_t)); + if(_auth_xkeys_list==NULL) { + LM_ERR("no more shared memory\n"); + return -1; + } + memset(_auth_xkeys_list, 0, sizeof(auth_xkey_t*)); + return 0; +} + +/** + * + */ +int authx_xkey_insert(auth_xkey_t *nkey) +{ + auth_xkey_t *ukey; + auth_xkey_t *itp; + auth_xkey_t *itc; + int ksize; + char *p; + + if(auth_xkeys_list_init()) + return -1; + if(nkey==NULL) + return -1; + + ksize = sizeof(auth_xkey_t) + nkey->kid.len + nkey->kname.len + + nkey->kvalue.len + 3; + ukey = (auth_xkey_t*)shm_malloc(ksize); + if(ukey==NULL) { + LM_ERR("no more shared memory\n"); + return -1; + } + memset(ukey, 0, ksize); + p = (char*)ukey + sizeof(auth_xkey_t); + + ukey->kid.len = nkey->kid.len; + ukey->kid.s = p; + strncpy(ukey->kid.s, nkey->kid.s, ukey->kid.len); + ukey->kid.s[ukey->kid.len] = '\0'; + p += ukey->kid.len + 1; + + ukey->kname.len = nkey->kname.len; + ukey->kname.s = p; + strncpy(ukey->kname.s, nkey->kname.s, ukey->kname.len); + ukey->kname.s[ukey->kname.len] = '\0'; + p += ukey->kname.len + 1; + + ukey->kvalue.len = nkey->kvalue.len; + ukey->kvalue.s = p; + strncpy(ukey->kvalue.s, nkey->kvalue.s, ukey->kvalue.len); + ukey->kvalue.s[ukey->kvalue.len] = '\0'; + p += ukey->kvalue.len + 1; + + ukey->kexpires = nkey->kexpires; + + if(*_auth_xkeys_list==NULL) { + *_auth_xkeys_list = ukey; + return 0; + } + + itp = NULL; + for(itc = *_auth_xkeys_list; itc; itc = itc->next_id) { + if(itc->kid.len==ukey->kid.len + && strncasecmp(itc->kid.s, ukey->kid.s, ukey->kid.len)==0) + break; + itp = itc; + } + if(itc==NULL) { + /* new id */ + ukey->next_id = *_auth_xkeys_list; + *_auth_xkeys_list = ukey; + return 0; + } + + if(itp!=NULL) { + itp->next_id = ukey; + } else { + *_auth_xkeys_list = ukey; + } + ukey->next_id = itc->next_id; + ukey->next = itc; + itc->next_id = NULL; + return 0; +} + +/** + * + */ +int authx_xkey_add_params(str *sparam) +{ + param_t* params_list = NULL; + param_hooks_t phooks; + param_t *pit=NULL; + auth_xkey_t tmp; + unsigned int uv; + + if (parse_params(sparam, CLASS_ANY, &phooks, ¶ms_list)<0) + return -1; + + memset(&tmp, 0, sizeof(auth_xkey_t)); + + for (pit = params_list; pit; pit=pit->next) + { + if (pit->name.len==2 + && strncasecmp(pit->name.s, "id", 2)==0) { + tmp.kid = pit->body; + } else if(pit->name.len==4 + && strncasecmp(pit->name.s, "name", 4)==0) { + tmp.kname = pit->body; + } else if(pit->name.len==5 + && strncasecmp(pit->name.s, "value", 5)==0) { + tmp.kvalue = pit->body; + } else if(pit->name.len==7 + && strncasecmp(pit->name.s, "expires", 7)==0) { + str2int(&pit->body, &uv); + tmp.kexpires = time(NULL) + uv; + } + } + if(tmp.kid.len<=0 || tmp.kname.len<=0 || tmp.kvalue.len<=0) { + LM_ERR("invalid parameters (%d/%d/%d)\n", tmp.kid.len, + tmp.kname.len, tmp.kvalue.len); + return -1; + } + + if(authx_xkey_insert(&tmp)<0) { + LM_ERR("unable to insert the key [%.*s:%.*s]\n", + tmp.kid.len, tmp.kid.s, tmp.kname.len, tmp.kname.s); + return -1; + } + + return 0; +} + +/** + * + */ +int auth_xkeys_add(sip_msg_t* msg, str *hdr, str *key, + str *alg, str *data) +{ + str xdata; + str hbody; + auth_xkey_t *itc; + char xout[SHA512_DIGEST_STRING_LENGTH]; + struct lump* anchor; + + if(_auth_xkeys_list==NULL || _auth_xkeys_list==NULL) { + LM_ERR("no stored keys\n"); + return -1; + } + if(parse_headers(msg, HDR_EOH_F, 0)<0) { + LM_ERR("error parsing headers\n"); + return -1; + } + + for(itc = *_auth_xkeys_list; itc; itc = itc->next_id) { + if(itc->kid.len==key->len + && strncasecmp(itc->kid.s, key->s, key->len)==0) + break; + } + if(itc==NULL) { + LM_DBG("no key chain id [%.*s]\n", key->len, key->s); + return -1; + } + + xdata.s = pv_get_buffer(); + xdata.len = data->len + itc->kvalue.len + 1; + if(xdata.len + 1 >= pv_get_buffer_size()) { + LM_ERR("size of data and key is too big\n"); + return -1; + } + + strncpy(xdata.s, itc->kvalue.s, itc->kvalue.len); + xdata.s[itc->kvalue.len] = ':'; + strncpy(xdata.s + itc->kvalue.len + 1, data->s, data->len); + if(alg->len==6 && strncasecmp(alg->s, "sha256", 6)==0) { + compute_sha256(xout, (u_int8_t*)xdata.s, xdata.len); + xdata.len = SHA256_DIGEST_STRING_LENGTH - 1; + } else if(alg->len==6 && strncasecmp(alg->s, "sha384", 6)==0) { + compute_sha384(xout, (u_int8_t*)xdata.s, xdata.len); + xdata.len = SHA384_DIGEST_STRING_LENGTH - 1; + } else if(alg->len==6 && strncasecmp(alg->s, "sha512", 6)==0) { + compute_sha512(xout, (u_int8_t*)xdata.s, xdata.len); + xdata.len = SHA512_DIGEST_STRING_LENGTH - 1; + } else { + LM_ERR("unknown algorithm [%.*s]\n", alg->len, alg->s); + return -1; + } + + if(xdata.len + hdr->len + 6 >= pv_get_buffer_size()) { + LM_ERR("size of new header is too big for pv buffer\n"); + return -1; + } + + strncpy(xdata.s, hdr->s, hdr->len); + xdata.s[hdr->len] = ':'; + xdata.s[hdr->len+1] = ' '; + strncpy(xdata.s + hdr->len + 2, xout, xdata.len); + xdata.len += hdr->len + 2; + xdata.s[xdata.len] = '\r'; + xdata.s[xdata.len+1] = '\n'; + xdata.s[xdata.len+2] = '\0'; + xdata.len += 2; + + anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0); + if(anchor == 0) { + LM_ERR("can't get anchor\n"); + return -1; + } + if (insert_new_lump_before(anchor, xdata.s, xdata.len, 0) == 0) { + LM_ERR("cannot insert the new header [%.*s]\n", hdr->len, hdr->s); + return -1; + } + return 0; +} + +/** + * + */ +int auth_xkeys_check(sip_msg_t* msg, str *hdr, str *key, + str *alg, str *data) +{ + hdr_field_t *hf; + str xdata; + auth_xkey_t *itc; + char xout[SHA512_DIGEST_STRING_LENGTH]; + str hbody; + + if(_auth_xkeys_list==NULL || _auth_xkeys_list==NULL) { + LM_ERR("no stored keys\n"); + return -1; + } + if(parse_headers(msg, HDR_EOH_F, 0)<0) { + LM_ERR("error parsing headers\n"); + return -1; + } + + for (hf=msg->headers; hf; hf=hf->next) { + if (cmp_hdrname_str(&hf->name, hdr)==0) + break; + } + if(hf==NULL) { + LM_DBG("no header with name [%.*s]\n", hdr->len, hdr->s); + return -1; + } + if(hf->body.len<=0) { + LM_DBG("empty header with name [%.*s]\n", hdr->len, hdr->s); + return -1; + } + hbody = hf->body; + trim(&hbody); + if(hbody.len!=SHA256_DIGEST_STRING_LENGTH-1 + && hbody.len!=SHA384_DIGEST_STRING_LENGTH-1 + && hbody.len!=SHA512_DIGEST_STRING_LENGTH-1) { + LM_DBG("not maching digest size for [%.*s]\n", + hf->body.len, hf->body.s); + return -1; + } + + for(itc = *_auth_xkeys_list; itc; itc = itc->next_id) { + if(itc->kid.len==key->len + && strncasecmp(itc->kid.s, key->s, key->len)==0) + break; + } + if(itc==NULL) { + LM_DBG("no key chain id [%.*s]\n", key->len, key->s); + return -1; + } + xdata.s = pv_get_buffer(); + for(; itc; itc = itc->next) { + xdata.len = data->len + itc->kvalue.len + 1; + if(xdata.len + 1 >= pv_get_buffer_size()) { + LM_WARN("size of data and key is too big - ignoring\n"); + continue; + } + strncpy(xdata.s, itc->kvalue.s, itc->kvalue.len); + xdata.s[itc->kvalue.len] = ':'; + strncpy(xdata.s + itc->kvalue.len + 1, data->s, data->len); + if(alg->len==6 && strncasecmp(alg->s, "sha256", 6)==0) { + if(hbody.len!=SHA256_DIGEST_STRING_LENGTH-1) { + LM_DBG("not maching sha256 digest size for [%.*s]\n", + hf->body.len, hf->body.s); + return -1; + } + compute_sha256(xout, (u_int8_t*)xdata.s, xdata.len); + if(strncasecmp(xout, hbody.s, hbody.len)==0) { + LM_DBG("no digest sha256 matched for key [%.*s:%.*s]\n", + key->len, key->s, itc->kname.len, itc->kname.s); + return 0; + } + } else if(alg->len==6 && strncasecmp(alg->s, "sha384", 6)==0) { + if(hbody.len!=SHA384_DIGEST_STRING_LENGTH-1) { + LM_DBG("not maching sha384 digest size for [%.*s]\n", + hf->body.len, hf->body.s); + return -1; + } + compute_sha384(xout, (u_int8_t*)xdata.s, xdata.len); + if(strncasecmp(xout, hbody.s, hbody.len)==0) { + LM_DBG("no digest sha384 matched for key [%.*s:%.*s]\n", + key->len, key->s, itc->kname.len, itc->kname.s); + return 0; + } + } else if(alg->len==6 && strncasecmp(alg->s, "sha512", 6)==0) { + if(hbody.len!=SHA512_DIGEST_STRING_LENGTH-1) { + LM_DBG("not maching sha512 digest size for [%.*s]\n", + hf->body.len, hf->body.s); + return -1; + } + compute_sha512(xout, (u_int8_t*)xdata.s, xdata.len); + if(strncasecmp(xout, hbody.s, hbody.len)==0) { + LM_DBG("no digest sha512 matched for key [%.*s:%.*s]\n", + key->len, key->s, itc->kname.len, itc->kname.s); + return 0; + } + } else { + LM_ERR("unknown algorithm [%.*s]\n", alg->len, alg->s); + return -1; + } + } + + LM_DBG("no digest matched for key [%.*s]\n", key->len, key->s); + return -1; +} + diff --git a/modules/auth_xkeys/auth_xkeys.h b/modules/auth_xkeys/auth_xkeys.h new file mode 100644 index 00000000000..5bb7282fbab --- /dev/null +++ b/modules/auth_xkeys/auth_xkeys.h @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2015 Daniel-Constantin Mierla (asipto.com) + * + * This file is part of Kamailio, a free SIP server. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _AUTH_XKEYS_H_ +#define _AUTH_XKEYS_H_ + +#include "../../str.h" + +int authx_xkey_add_params(str *sparam); +int auth_xkeys_add(sip_msg_t* msg, str *hdr, str *key, + str *alg, str *data); +int auth_xkeys_check(sip_msg_t* msg, str *hdr, str *key, + str *alg, str *data); + +#endif diff --git a/modules/auth_xkeys/auth_xkeys_mod.c b/modules/auth_xkeys/auth_xkeys_mod.c new file mode 100644 index 00000000000..e36cc7a53cb --- /dev/null +++ b/modules/auth_xkeys/auth_xkeys_mod.c @@ -0,0 +1,207 @@ +/** + * Copyright (C) 2015 Daniel-Constantin Mierla (asipto.com) + * + * This file is part of Kamailio, a free SIP server. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include + +#include "../../sr_module.h" +#include "../../dprint.h" +#include "../../ut.h" +#include "../../pvar.h" +#include "../../mod_fix.h" +#include "../../timer_proc.h" +#include "../../route_struct.h" + +#include "auth_xkeys.h" + +MODULE_VERSION + + +static int mod_init(void); +static int child_init(int); +static void mod_destroy(void); + +int authx_xkey_param(modparam_t type, void* val); + +static int w_auth_xkeys_add(sip_msg_t* msg, char* hdr, char* key, + char* alg, char* data); +static int fixup_auth_xkeys_add(void** param, int param_no); +static int w_auth_xkeys_check(sip_msg_t* msg, char* hdr, char* key, + char* alg, char* data); +static int fixup_auth_xkeys_check(void** param, int param_no); + +/* timer for cleaning up the expired keys */ +/* int auth_xkeys_timer_mode = 0; */ + + +static cmd_export_t cmds[]={ + {"auth_xkeys_add", (cmd_function)w_auth_xkeys_add, + 4, fixup_auth_xkeys_add, + 0, ANY_ROUTE}, + {"auth_xkeys_check", (cmd_function)w_auth_xkeys_check, + 4, fixup_auth_xkeys_check, + 0, ANY_ROUTE}, + {0, 0, 0, 0, 0, 0} +}; + +static param_export_t params[]={ + {"xkey", PARAM_STRING|USE_FUNC_PARAM, (void*)authx_xkey_param}, + /* {"timer_mode", PARAM_INT, &auth_xkeys_timer_mode}, */ + {0, 0, 0} +}; + +struct module_exports exports = { + "auth_xkeys", + DEFAULT_DLFLAGS, /* dlopen flags */ + cmds, + params, + 0, + 0, /* exported MI functions */ + 0, /* exported pseudo-variables */ + 0, /* extra processes */ + mod_init, /* module initialization function */ + 0, /* response function */ + mod_destroy, /* destroy function */ + child_init /* per child init function */ +}; + + + +/** + * init module function + */ +static int mod_init(void) +{ + return 0; +} + +/** + * @brief Initialize async module children + */ +static int child_init(int rank) +{ + return 0; +} +/** + * destroy module function + */ +static void mod_destroy(void) +{ +} + + +static int w_auth_xkeys_add(sip_msg_t* msg, char* hdr, char* key, + char* alg, char* data) +{ + str shdr; + str skey; + str salg; + str sdata; + + if(fixup_get_svalue(msg, (gparam_t*)hdr, &shdr)!=0) + { + LM_ERR("cannot get the header name\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)key, &skey)!=0) + { + LM_ERR("cannot get the key id\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)alg, &salg)!=0) + { + LM_ERR("cannot get the algorithm\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)data, &sdata)!=0) + { + LM_ERR("cannot get the hasing data\n"); + return -1; + } + + if(auth_xkeys_add(msg, &shdr, &skey, &salg, &sdata)<0) + return -1; + + return 1; +} + +static int w_auth_xkeys_check(sip_msg_t* msg, char* hdr, char* key, + char* alg, char* data) +{ + str shdr; + str skey; + str salg; + str sdata; + + if(fixup_get_svalue(msg, (gparam_t*)hdr, &shdr)!=0) + { + LM_ERR("cannot get the header name\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)key, &skey)!=0) + { + LM_ERR("cannot get the key id\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)alg, &salg)!=0) + { + LM_ERR("cannot get the algorithm\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_t*)data, &sdata)!=0) + { + LM_ERR("cannot get the hasing data\n"); + return -1; + } + + if(auth_xkeys_check(msg, &shdr, &skey, &salg, &sdata)<0) + return -1; + + return 1; +} + +static int fixup_auth_xkeys_add(void** param, int param_no) +{ + if(fixup_spve_null(param, 1)<0) + return -1; + return 0; +} + +static int fixup_auth_xkeys_check(void** param, int param_no) +{ + if(fixup_spve_null(param, 1)<0) + return -1; + return 0; +} + +int authx_xkey_param(modparam_t type, void* val) +{ + str s; + + if(val==NULL) + return -1; + s.s = (char*)val; + s.len = strlen(s.s); + return authx_xkey_add_params(&s); +} diff --git a/modules/auth_xkeys/doc/Makefile b/modules/auth_xkeys/doc/Makefile new file mode 100644 index 00000000000..7efb7b95e94 --- /dev/null +++ b/modules/auth_xkeys/doc/Makefile @@ -0,0 +1,4 @@ +docs = auth_xkeys.xml + +docbook_dir = ../../../docbook +include $(docbook_dir)/Makefile.module diff --git a/modules/auth_xkeys/doc/auth_xkeys.xml b/modules/auth_xkeys/doc/auth_xkeys.xml new file mode 100644 index 00000000000..f77f913fc14 --- /dev/null +++ b/modules/auth_xkeys/doc/auth_xkeys.xml @@ -0,0 +1,36 @@ + + + +%docentities; + +]> + + + + AUTH_XKEYS Module + kamailio.org + + + Daniel-Constantin + Mierla + miconda@gmail.com + + + Daniel-Constantin + Mierla + miconda@gmail.com + + + + 2015 + asipto.com + + + + + + + diff --git a/modules/auth_xkeys/doc/auth_xkeys_admin.xml b/modules/auth_xkeys/doc/auth_xkeys_admin.xml new file mode 100644 index 00000000000..51002cdb59e --- /dev/null +++ b/modules/auth_xkeys/doc/auth_xkeys_admin.xml @@ -0,0 +1,193 @@ + + + +%docentities; + +]> + + + + + &adminguide; + +
+ Overview + + This module provides a custom mechanism to authenticate a SIP entity + using a list of shared keys. + + + It is similar to the API key based authentication used by many web + services. In short, the sender adds a particular header with a hash + token computed with the shared key and some values from the SIP + request (e.g., local IP, From/To/R-URI username, Call-ID, CSeq). + + + For proper protection, it is recommended to use this + authentication mechanism over a secure channel (e.g., TLS, VPN, + private network). + + + The benefit is avoiding the extra traffic and processing required + by WWW-Digest authentication schema (no more 401/407 and a follow up + request with credentials). + + + Another goal is to provide more elasticity for scalability needs of + the core SIP network nodes. Most of the nodes in the core network or + the interconnecting peers trust each other based on IP address. But + adding a new node requires updates to the exiting ones to trust the + IP address of the new node. On large deployments, that can become + rather complex. For example, as a replacement for IP trust + relationships, the sender can hash the local IP with the secret + shared key, add it in the header and the receiver will check if the + source ip hased with the key results in the same value. + + + Not being a challenge-reply mechanism, this can be used to authenticate + SIP responses from trusted peers. + +
+ +
+ Dependencies +
+ &kamailio; Modules + + The following modules must be loaded before this module: + + + + none. + + + + +
+
+ External Libraries or Applications + + The following libraries or applications must be installed before running + &kamailio; with this module loaded: + + + + none + + + + +
+
+
+ Parameters +
+ <varname>xkey</varname> (str) + + Specify the attributes for a shared secret. The value is in + the format 'name1=value1;name2=value2;...'. The attributes can be: + + + + + id - the id of the group for keys + + + + + name - the name of the key within group + + + + + value - the value of the key + + + + + expires - expiration time (seconds) + + + + + + Default value is empty. + + + + Set <varname>xkey</varname> parameter + +... +modparam("auth_xkeys", "xkey", "id=abc;name=xyz;value=secret;expires=72000") +... + + +
+
+ +
+ Functions +
+ + <function moreinfo="none">auth_xkeys_add(hdr, kid, alg, data)</function> + + + Add a header computed with the first key in the group kid, hasing with + algorithm alg over the content of parameter data. The parameters can + include variables. + + + The algorithm can be: sha256, sha384, sha512. + + + This function can be used from ANY_ROUTE. + + + <function>auth_xkeys_add</function> usage + +... +auth_xkeys_add("X-My-Key", "abc", "sha256", "$Ri:$fu:$ru:$hdr(CSeq)"); +... + + +
+ +
+ + <function moreinfo="none">auth_xkeys_check(hdr, kid, alg, data)</function> + + + Check if the value of header hdr matches the value computed with the + first key in the group kid, hasing with algorithm alg over the content + of parameter data. The parameters can include variables. + + + The algorithm can be: sha256, sha384, sha512. + + + Note that the header is not removed by the function, it is recommended + to remove it if sending to untrusted destination. + + + This function can be used from ANY_ROUTE. + + + <function>auth_xkeys_check</function> usage + +... +if(!auth_xkeys_add("X-My-Key", "abc", "sha256", "$si:$fu:$ru:$hdr(CSeq)")) { + send_reply("403", "Forbidden"); + exit; +} +remove_hf("X-My-Key"); +... + + +
+ +
+
+