123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- /*
- * $Id$
- *
- * Challenge related functions
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser 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
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser 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
- *
- * History:
- * --------
- * 2003-01-20 snprintf in build_auth_hf replaced with memcpy to avoid
- * possible issues with too small buffer
- * 2003-01-26 consume_credentials no longer complains about ACK/CANCEL(jiri)
- * 2007-10-19 auth extra checks: longer nonces that include selected message
- * parts to protect against various reply attacks without keeping
- * state (andrei)
- * 2008-07-08 nonce-count (nc) support (andrei)
- */
- #include "../../data_lump.h"
- #include "../../mem/mem.h"
- #include "../../parser/digest/digest.h"
- #include "../../usr_avp.h"
- #include "../../ut.h"
- #include "auth_mod.h"
- #include "challenge.h"
- #include "nonce.h"
- #include "api.h"
- #include "nc.h"
- #include "ot_nonce.h"
- #define QOP_PARAM_START ", qop=\""
- #define QOP_PARAM_START_LEN (sizeof(QOP_PARAM_START)-1)
- #define QOP_PARAM_END "\""
- #define QOP_PARAM_END_LEN (sizeof(QOP_PARAM_END)-1)
- #define STALE_PARAM ", stale=true"
- #define STALE_PARAM_LEN (sizeof(STALE_PARAM)-1)
- #define DIGEST_REALM ": Digest realm=\""
- #define DIGEST_REALM_LEN (sizeof(DIGEST_REALM)-1)
- #define DIGEST_NONCE "\", nonce=\""
- #define DIGEST_NONCE_LEN (sizeof(DIGEST_NONCE)-1)
- #define DIGEST_MD5 ", algorithm=MD5"
- #define DIGEST_MD5_LEN (sizeof(DIGEST_MD5)-1)
- #define DIGEST_ALGORITHM ", algorithm="
- #define DIGEST_ALGORITHM_LEN (sizeof(DIGEST_ALGORITHM)-1)
- extern str auth_realm_prefix;
- /**
- * @brief Strip the beginning of a realm string
- *
- * Strip the beginning of a realm string, depending on the length of
- * the realm_prefix.
- * @param _realm realm string
- */
- void strip_realm(str* _realm)
- {
- /* no param defined -- return */
- if (!auth_realm_prefix.len) return;
- /* prefix longer than realm -- return */
- if (auth_realm_prefix.len > _realm->len) return;
- /* match ? -- if so, shorten realm -*/
- if (memcmp(auth_realm_prefix.s, _realm->s, auth_realm_prefix.len) == 0) {
- _realm->s += auth_realm_prefix.len;
- _realm->len -= auth_realm_prefix.len;
- }
- return;
- }
- /**
- * Create and return {WWW,Proxy}-Authenticate header field
- * @param nonce nonce value
- * @param algorithm algorithm value
- * @param qop qop value
- * @return -1 on error, 0 on success
- *
- * The result is stored in param ahf.
- * If nonce is not null that it is used, instead of call calc_nonce.
- * If algorithm is not null that it is used irrespective of _PRINT_MD5
- *
- * Major usage of nonce and algorithm params is AKA authentication.
- */
- int get_challenge_hf(struct sip_msg* msg, int stale, str* realm,
- str* nonce, str* algorithm, struct qp* qop, int hftype, str *ahf)
- {
- char *p;
- str* hfn, hf;
- int nonce_len, l, cfg;
- int t;
- #if defined USE_NC || defined USE_OT_NONCE
- unsigned int n_id;
- unsigned char pool;
- unsigned char pool_flags;
- #endif
- if(!ahf)
- {
- LM_ERR("invalid output parameter\n");
- return -1;
- }
- strip_realm(realm);
- if (realm) {
- DEBUG("build_challenge_hf: realm='%.*s'\n", realm->len, realm->s);
- }
- if (nonce) {
- DEBUG("build_challenge_hf: nonce='%.*s'\n", nonce->len, nonce->s);
- }
- if (algorithm) {
- DEBUG("build_challenge_hf: algorithm='%.*s'\n", algorithm->len,
- algorithm->s);
- }
- if (qop && qop->qop_parsed != QOP_UNSPEC) {
- DEBUG("build_challenge_hf: qop='%.*s'\n", qop->qop_str.len,
- qop->qop_str.s);
- }
- if (hftype == HDR_PROXYAUTH_T) {
- hfn = &proxy_challenge_header;
- } else {
- hfn = &www_challenge_header;
- }
-
- cfg = get_auth_checks(msg);
- nonce_len = get_nonce_len(cfg, nc_enabled || otn_enabled);
- hf.len = hfn->len;
- if (realm) {
- hf.len += DIGEST_REALM_LEN
- + realm->len;
- }
- hf.len += DIGEST_NONCE_LEN;
- if (nonce) {
- hf.len += nonce->len
- + 1; /* '"' */
- }
- else {
- hf.len += nonce_len
- + 1; /* '"' */
- }
- hf.len += ((stale) ? STALE_PARAM_LEN : 0);
- if (algorithm) {
- hf.len += DIGEST_ALGORITHM_LEN + algorithm->len;
- }
- else {
- hf.len += 0
- #ifdef _PRINT_MD5
- +DIGEST_MD5_LEN
- #endif
- ;
- }
-
- if (qop && qop->qop_parsed != QOP_UNSPEC) {
- hf.len += QOP_PARAM_START_LEN + qop->qop_str.len + QOP_PARAM_END_LEN;
- }
- hf.len += CRLF_LEN;
- p = hf.s = pkg_malloc(hf.len);
- if (!hf.s) {
- ERR("auth: No memory left (%d bytes)\n", hf.len);
- return -1;
- }
- memcpy(p, hfn->s, hfn->len); p += hfn->len;
- if(realm){
- memcpy(p, DIGEST_REALM, DIGEST_REALM_LEN); p += DIGEST_REALM_LEN;
- memcpy(p, realm->s, realm->len); p += realm->len;
- }
- memcpy(p, DIGEST_NONCE, DIGEST_NONCE_LEN); p += DIGEST_NONCE_LEN;
- if (nonce) {
- memcpy(p, nonce->s, nonce->len); p += nonce->len;
- }
- else {
- l=nonce_len;
- t=time(0);
- #if defined USE_NC || defined USE_OT_NONCE
- if (nc_enabled || otn_enabled){
- pool=nid_get_pool();
- n_id=nid_inc(pool);
- pool_flags=0;
- #ifdef USE_NC
- if (nc_enabled){
- nc_new(n_id, pool);
- pool_flags|= NF_VALID_NC_ID;
- }
- #endif
- #ifdef USE_OT_NONCE
- if (otn_enabled){
- otn_new(n_id, pool);
- pool_flags|= NF_VALID_OT_ID;
- }
- #endif
- }else{
- pool=0;
- pool_flags=0;
- n_id=0;
- }
- if (calc_nonce(p, &l, cfg, t, t + nonce_expire, n_id,
- pool | pool_flags,
- &secret1, &secret2, msg) != 0)
- #else /* USE_NC || USE_OT_NONCE*/
- if (calc_nonce(p, &l, cfg, t, t + nonce_expire,
- &secret1, &secret2, msg) != 0)
- #endif /* USE_NC || USE_OT_NONCE */
- {
- ERR("auth: calc_nonce failed (len %d, needed %d)\n",
- nonce_len, l);
- pkg_free(hf.s);
- return -1;
- }
- p += l;
- }
- *p = '"'; p++;
- if (qop && qop->qop_parsed != QOP_UNSPEC) {
- memcpy(p, QOP_PARAM_START, QOP_PARAM_START_LEN);
- p += QOP_PARAM_START_LEN;
- memcpy(p, qop->qop_str.s, qop->qop_str.len);
- p += qop->qop_str.len;
- memcpy(p, QOP_PARAM_END, QOP_PARAM_END_LEN);
- p += QOP_PARAM_END_LEN;
- }
- if (stale) {
- memcpy(p, STALE_PARAM, STALE_PARAM_LEN);
- p += STALE_PARAM_LEN;
- }
- if (algorithm) {
- memcpy(p, DIGEST_ALGORITHM, DIGEST_ALGORITHM_LEN);
- p += DIGEST_ALGORITHM_LEN;
- memcpy(p, algorithm->s, algorithm->len);
- p += algorithm->len;
- }
- else {
- #ifdef _PRINT_MD5
- memcpy(p, DIGEST_MD5, DIGEST_MD5_LEN ); p += DIGEST_MD5_LEN;
- #endif
- }
- memcpy(p, CRLF, CRLF_LEN); p += CRLF_LEN;
- hf.len=(int)(p-hf.s); /* fix len, it might be smaller due to a smaller
- nonce */
-
- DBG("auth: '%.*s'\n", hf.len, ZSW(hf.s));
- *ahf = hf;
- return 0;
- }
- /**
- * Create {WWW,Proxy}-Authenticate header field
- * @param nonce nonce value
- * @param algorithm algorithm value
- * @return -1 on error, 0 on success
- *
- * The result is stored in an attribute.
- * If nonce is not null that it is used, instead of call calc_nonce.
- * If algorithm is not null that it is used irrespective of _PRINT_MD5
- * The value of 'qop' module parameter is used.
- *
- * Major usage of nonce and algorithm params is AKA authentication.
- */
- int build_challenge_hf(struct sip_msg* msg, int stale, str* realm,
- str* nonce, str* algorithm, int hftype)
- {
- str hf = {0, 0};
- avp_value_t val;
- int ret;
- ret = get_challenge_hf(msg, stale, realm, nonce, algorithm, &auth_qop,
- hftype, &hf);
- if(ret < 0)
- return ret;
- val.s = hf;
- if(add_avp(challenge_avpid.flags | AVP_VAL_STR, challenge_avpid.name, val)
- < 0) {
- ERR("auth: Error while creating attribute with challenge\n");
- pkg_free(hf.s);
- return -1;
- }
- pkg_free(hf.s);
- return 0;
- }
|