⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 auth_digest.c

📁 Internet Phone, Chat, Conferencing
💻 C
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE auth_digest.c * * Implementation for digest authentication. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Thu Feb 22 12:10:37 2001 ppessi */#include "config.h"#include <string.h>#include <stdarg.h>#include <assert.h>#include <sofia-sip/su_md5.h>#include "sofia-sip/auth_digest.h"#include "iptsec_debug.h"static inline int has_token(char const *qstring, char const *token);/** * Parse authentication parameters. * * The function auth_get_params() searches for the authentication parameters * in @a params. The parameter list @a params is seached for each parameter * given in in vararg section, and if it is found, its value is assigned to * the given address.  * * @note The field name should contain the equal ("=") sign. * * @return * The function auth_get_params() returns number of parameters found in * params, or -1 upon an error. */int auth_get_params(su_home_t *home,		    char const * const params[], ...		    /* char const * name, char const **return_value */){  int n, j, len, namelen, matched;  int value_match;  char const *name, *p;  char const *value, **return_value;  va_list(ap);  assert(params);  if (!params) return -1;  va_start(ap, params);  for (n = 0; (name = va_arg(ap, char const *));) {    return_value = va_arg(ap, char const **);    len = strlen(name);    if (!len)      continue;    namelen = strcspn(name, "=");    value_match = len - 1 != namelen;    for (j = 0; (p = params[j++]);) {      if (value_match) {	if (strcasecmp(p, name) == 0) {	  value = p;	}	else if (strncasecmp(p, name, namelen) == 0) {	  for (matched = namelen; strchr(" \t\r\n", p[matched]); matched++)	    ;	  if (p[matched++] != '=')	    continue;	  for (; strchr(" \t\r\n", p[matched]); matched++)	    ;	  if (p[matched] == '"' && has_token(p + matched, name + namelen + 1))	    value = p + matched;	  else if (strcasecmp(p + matched, name + namelen + 1) == 0)	    value = p + matched;	  else	    continue;	}	else {	  continue;	}      }      else if (strncasecmp(p, name, len) == 0) {	if (home && p[len] == '"') {	  int quoted = strcspn(p + len + 1, "\"");	  value = su_strndup(home, p + len + 1, quoted);	}	else {	  value = p + len;	}      }      else {	continue;      }            *return_value = value;      n++;      break;    }  }  va_end(ap);  return n;}staticint auth_struct_copy(void *dst, void const *src, int s_size){  int d_size = *(int *)dst;  if (d_size > s_size) {    memcpy(dst, src, s_size);    memset((char *)dst + s_size, 0, d_size - s_size);  }  else {    memcpy(dst, src, d_size);    *(int *)dst = d_size;  }  return 0;}#if !HAVE_STRCASESTRstatic inline char const *strcasestr(char const *haystack, char const *pin){  int i, m ,n;  m = strlen(haystack);  n = strlen(pin);  for (i = 0; i + n <= m; i++)    if (strncasecmp(haystack + i, pin, n) == 0)      break;  if (i + n <= m)    return haystack + i;  else    return NULL;}#endifstatic inline int has_token(char const *qstring, char const *token){  int n = strlen(token);  char const *q;  q = strcasestr(qstring, token);  return (q &&	  (q[n] == 0 || strchr("\", \t", q[n])) &&	  (q == qstring || strchr("\", \t", q[-1])));}/**Get digest-challenge parameters. * * The function digest_challenge_get() searches for the digest authentication * parameters in @a params.  The parameters are assigned to the appropriate * fields in @a ac structure. * * @return * * The function digest_challenge_get() returns number of parameters * found, or -1 upon an error. */int auth_digest_challenge_get(su_home_t *home,			      auth_challenge_t *ac0, 			      char const * const params[]){  int n;  auth_challenge_t ac[1] = {{ 0 }};  char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,    *qop_auth = NULL, *qop_auth_int = NULL;  ac->ac_size = sizeof(ac);  assert(ac0);   assert(ac0->ac_size >= sizeof(*ac));  if (ac0 == NULL || params == NULL)    return -1;  n = auth_get_params(home, params,		      "realm=", &ac->ac_realm,		      "domain=", &ac->ac_domain,		      "nonce=", &ac->ac_nonce,		      "opaque=", &ac->ac_opaque,		      "stale=", &ac->ac_stale,		      "algorithm=", &ac->ac_algorithm,		      "qop=", &ac->ac_qop,		      "algorithm=md5", &md5,		      "algorithm=md5-sess", &md5sess,		      "algorithm=sha1", &sha1,		      "qop=auth", &qop_auth,		      "qop=auth-int", &qop_auth_int,		      NULL);  if (n < 0)    return n;  if (ac->ac_stale && strcasecmp(ac->ac_stale, "true") != 0)    ac->ac_stale = NULL;  ac->ac_md5 = md5 != NULL || ac->ac_algorithm == NULL;  ac->ac_md5sess = md5sess != NULL;  ac->ac_sha1 = sha1 != NULL;  ac->ac_auth = qop_auth != NULL;  ac->ac_auth_int = qop_auth_int != NULL;  auth_struct_copy(ac0, ac, sizeof(ac));  SU_DEBUG_5(("%s(): got %d\n", "auth_digest_challenge_get", n));    return n;}/**Get digest-response parameters. * * The function auth_response_get() searches for the digest authentication * parameters in @a params.  The parameters are assigned to the appropriate * fields in @a ar structure. * * @return * * The function auth_response_get() returns number of parameters * found, or -1 upon an error. */int auth_digest_response_get(su_home_t *home,			     auth_response_t *ar0, 			     char const *const params[]){  int n;  auth_response_t ar[1] = {{ 0 }};  char const *md5 = NULL, *md5sess = NULL, *sha1 = NULL,    *qop_auth = NULL, *qop_auth_int = NULL;  ar->ar_size = sizeof(ar);  assert(ar0); assert(params); assert(ar0->ar_size >= sizeof(ar));  if (ar0 == NULL || params == NULL)    return -1;  n = auth_get_params(home, params,		      "username=", &ar->ar_username,		      "realm=", &ar->ar_realm,		      "nonce=", &ar->ar_nonce,		      "uri=", &ar->ar_uri,		      "response=", &ar->ar_response,		      "algorithm=", &ar->ar_algorithm,		      "opaque=", &ar->ar_opaque,		      "cnonce=", &ar->ar_cnonce,		      "qop=", &ar->ar_qop,		      "nc=", &ar->ar_nc,		      "algorithm=md5", &md5,		      "algorithm=md5-sess", &md5sess,		      "algorithm=sha1", &sha1,		      "qop=auth", &qop_auth,		      "qop=auth-int", &qop_auth_int,		      NULL);  if (n < 0)    return n;  ar->ar_md5      = md5 != NULL || ar->ar_algorithm == NULL;  ar->ar_md5sess  = md5sess != NULL;  ar->ar_sha1     = sha1 != NULL;  ar->ar_auth     = qop_auth != NULL;  ar->ar_auth_int = qop_auth_int != NULL;  auth_struct_copy(ar0, ar, sizeof(ar));  SU_DEBUG_7(("%s: %d\n", "auth_digest_response_get", n));  return n;}static void unquote_update(su_md5_t md5[1], char const *quoted){  if (!quoted)    /*xyzzy*/;  else if (quoted[0] == '"') {    char const *q;     int n;    for (q = quoted + 1; *q; q += n + 2) {      n = strcspn(q, "\"\\");      su_md5_update(md5, q, n);      if (q[n] == '"' || q[n] == '\0')	break;      su_md5_update(md5, q + n + 1, 1);    }  }  else    su_md5_strupdate(md5, quoted);}/** Generate A1 hash for digest authentication.  */int auth_digest_a1(auth_response_t *ar, 		   auth_hexmd5_t ha1,		   char const *secret){  su_md5_t md5[1];  /* Calculate A1 */  su_md5_init(md5);  su_md5_strupdate(md5, ar->ar_username);  su_md5_update(md5, ":", 1);  unquote_update(md5, ar->ar_realm);  su_md5_update(md5, ":", 1);  su_md5_strupdate(md5, secret);  su_md5_hexdigest(md5, ha1);  SU_DEBUG_5(("auth_digest_a1() has A1 = MD5(%s:%s:%s) = %s\n", 	      ar->ar_username, ar->ar_realm, secret, ha1));  return 0;}int auth_digest_a1sess(auth_response_t *ar, 		       auth_hexmd5_t ha1sess,		       char const *ha1){  su_md5_t md5[1];  su_md5_init(md5);  su_md5_strupdate(md5, ha1);  su_md5_update(md5, ":", 1);  unquote_update(md5, ar->ar_nonce);  su_md5_update(md5, ":", 1);  unquote_update(md5, ar->ar_cnonce);  su_md5_hexdigest(md5, ha1sess);  SU_DEBUG_5(("auth_sessionkey has A1' = MD5(%s:%s:%s) = %s\n", 	      ha1, ar->ar_nonce, ar->ar_cnonce, ha1sess));  return 0;}/** Generate MD5 session key for digest authentication.  */int auth_digest_sessionkey(auth_response_t *ar, 			   auth_hexmd5_t ha1,			   char const *secret){  if (ar->ar_md5sess)    ar->ar_algorithm = "MD5-sess";  else if (ar->ar_md5)    ar->ar_algorithm = "MD5";  else    return -1;  if (ar->ar_md5sess) {    auth_hexmd5_t base_ha1;     auth_digest_a1(ar, base_ha1, secret);    auth_digest_a1sess(ar, ha1, base_ha1);  } else {    auth_digest_a1(ar, ha1, secret);  }  return 0;}/** Generate response for digest authentication.  * */int auth_digest_response(auth_response_t *ar, 			 auth_hexmd5_t response,			 auth_hexmd5_t const ha1, 			 char const *method_name,			 void const *data, int dlen){  su_md5_t md5[1];  auth_hexmd5_t Hentity, HA2;  if (ar->ar_auth_int)    ar->ar_qop = "auth-int";  else if (ar->ar_auth)    ar->ar_qop = "auth";  else    ar->ar_qop = NULL;  /* Calculate Hentity */  if (ar->ar_auth_int) {    if (data && dlen) {      su_md5_init(md5);      su_md5_update(md5, data, dlen);      su_md5_hexdigest(md5, Hentity);    } else {      strcpy(Hentity, "d41d8cd98f00b204e9800998ecf8427e");    }  }  /* Calculate A2 */  su_md5_init(md5);  su_md5_strupdate(md5, method_name);  su_md5_update(md5, ":", 1);  unquote_update(md5, ar->ar_uri);  if (ar->ar_auth_int) {    su_md5_update(md5, ":", 1);    su_md5_update(md5, Hentity, sizeof(Hentity) - 1);  }  su_md5_hexdigest(md5, HA2);  SU_DEBUG_5(("A2 = MD5(%s:%s%s%s)\n", method_name, ar->ar_uri, 	      ar->ar_auth_int ? ":" : "", ar->ar_auth_int ? Hentity : ""));  /* Calculate response */  su_md5_init(md5);  su_md5_update(md5, ha1, 32);  su_md5_update(md5, ":", 1);  unquote_update(md5, ar->ar_nonce);  if (ar->ar_auth || ar->ar_auth_int) {    su_md5_update(md5, ":", 1);    su_md5_strupdate(md5, ar->ar_nc);    su_md5_update(md5, ":", 1);    unquote_update(md5, ar->ar_cnonce);    su_md5_update(md5, ":", 1);    su_md5_strupdate(md5, ar->ar_qop);  }  su_md5_update(md5, ":", 1);  su_md5_update(md5, HA2, 32);        su_md5_hexdigest(md5, response);  SU_DEBUG_5(("auth_response: %s = MD5(%s:%s%s%s%s%s%s%s:%s) (qop=%s)\n", 	      response, ha1, ar->ar_nonce, 	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_nc : "", 	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_cnonce : "", 	      ar->ar_auth ||  ar->ar_auth_int ? ":" : "", 	      ar->ar_auth ||  ar->ar_auth_int ? ar->ar_qop : "", 	      HA2,	      ar->ar_qop ? ar->ar_qop : "NONE"));  return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -