Forráskód Böngészése

auth: added option to use SHA-256 encryption algorithm for digest authentication

- the module paramter "algorithm" was added with the possible values "",
  "MD5" or "SHA-256".
- it allows chosing between MD5 or SHA-256 hash algorithm for digest
  authentication.
- the configured algorithm is advertised in the challenge header.
- the default values is "" which omits the algorithm field in the
  challenge header and uses MD5 for digest authentication.
- submitted via GH pull request #628
AndreasHuber-CH 9 éve
szülő
commit
e7faf1eef7

+ 2 - 0
modules/auth/Makefile

@@ -15,4 +15,6 @@ DEFS+=-DUSE_NC -DUSE_OT_NONCE
 
 DEFS+=-DSER_MOD_INTERFACE
 
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
 include ../../Makefile.modules

+ 5 - 4
modules/auth/api.c

@@ -29,6 +29,7 @@
 #include "../../ut.h"
 #include "auth_mod.h"
 #include "nonce.h"
+#include "rfc2617_sha256.h"
 
 static int auth_check_hdr_md5(struct sip_msg* msg, auth_body_t* auth_body,
 		auth_result_t* auth_res);
@@ -176,14 +177,14 @@ auth_result_t post_auth(struct sip_msg* msg, struct hdr_field* hdr)
  */
 int auth_check_response(dig_cred_t* cred, str* method, char* ha1)
 {
-	HASHHEX resp, hent;
+	HASHHEX_SHA256 resp, hent;
 
 	/*
 	 * First, we have to verify that the response received has
 	 * the same length as responses created by us
 	 */
-	if (cred->response.len != 32) {
-		DBG("check_response: Receive response len != 32\n");
+	if (cred->response.len != hash_hex_len) {
+		DBG("check_response: Receive response len != %d\n", hash_hex_len);
 		return BAD_CREDENTIALS;
 	}
 
@@ -202,7 +203,7 @@ int auth_check_response(dig_cred_t* cred, str* method, char* ha1)
 	 * And simply compare the strings, the user is
 	 * authorized if they match
 	 */
-	if (!memcmp(resp, cred->response.s, 32)) {
+	if (!memcmp(resp, cred->response.s, hash_hex_len)) {
 		DBG("check_response: Authorization is OK\n");
 		return AUTHENTICATED;
 	} else {

+ 27 - 2
modules/auth/auth_mod.c

@@ -48,6 +48,7 @@
 #include "nc.h"
 #include "ot_nonce.h"
 #include "rfc2617.h"
+#include "rfc2617_sha256.h"
 
 MODULE_VERSION
 
@@ -133,6 +134,14 @@ static struct qp auth_qauthint = {
 	QOP_AUTHINT
 };
 
+/* Hash algorithm used for digest authentication, MD5 if empty */
+str auth_algorithm = {"", 0};
+int hash_hex_len;
+
+calc_HA1_t calc_HA1;
+calc_response_t calc_response;
+
+
 /*! SL API structure */
 sl_api_t slb;
 
@@ -194,6 +203,7 @@ static param_export_t params[] = {
 	{"force_stateless_reply",  PARAM_INT,    &force_stateless_reply },
 	{"realm_prefix",           PARAM_STRING, &auth_realm_prefix.s   },
 	{"use_domain",             PARAM_INT,    &auth_use_domain       },
+	{"algorithm",              PARAM_STR,    &auth_algorithm        },
 	{0, 0, 0}
 };
 
@@ -354,6 +364,21 @@ static int mod_init(void)
 #endif /* USE_OT_NONCE */
 	}
 
+	if (auth_algorithm.len == 0 || strcmp(auth_algorithm.s, "MD5") == 0) {
+		hash_hex_len = HASHHEXLEN;
+		calc_HA1 = calc_HA1_md5;
+		calc_response = calc_response_md5;
+	}
+	else if (strcmp(auth_algorithm.s, "SHA-256") == 0) {
+		hash_hex_len = HASHHEXLEN_SHA256;
+		calc_HA1 = calc_HA1_sha256;
+		calc_response = calc_response_sha256;
+	}
+	else {
+		ERR("auth: Invalid algorithm provided. Possible values are \"\", \"MD5\" or \"SHA-256\"\n");
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -538,7 +563,7 @@ end:
 			qop = &auth_qauth;
 		}
 		if (get_challenge_hf(msg, (cred ? cred->stale : 0),
-					realm, NULL, NULL, qop, hftype, &hf) < 0) {
+					realm, NULL, (auth_algorithm.len ? &auth_algorithm : NULL), qop, hftype, &hf) < 0) {
 			ERR("Error while creating challenge\n");
 			ret = AUTH_ERROR;
 		} else {
@@ -903,7 +928,7 @@ int auth_challenge_helper(struct sip_msg *msg, str *realm, int flags, int hftype
 	} else {
 		stale = 0;
 	}
-	if (get_challenge_hf(msg, stale, realm, NULL, NULL, qop, hftype, &hf)
+	if (get_challenge_hf(msg, stale, realm, NULL, (auth_algorithm.len ? &auth_algorithm : NULL), qop, hftype, &hf)
 			< 0) {
 		ERR("Error while creating challenge\n");
 		ret = -2;

+ 6 - 0
modules/auth/auth_mod.h

@@ -29,6 +29,7 @@
 #include "../../parser/msg_parser.h"    /* struct sip_msg */
 #include "../../parser/digest/digest.h"
 #include "nonce.h" /* auth_extra_checks & AUTH_CHECK flags */
+#include "rfc2617.h"
 
 /*
  * Module parameters variables
@@ -42,5 +43,10 @@ extern avp_ident_t challenge_avpid;
 extern str proxy_challenge_header;
 extern str www_challenge_header;
 extern struct qp auth_qop;
+extern str auth_algorithm;
+
+extern int hash_hex_len;
+extern calc_HA1_t calc_HA1;
+extern calc_response_t calc_response;
 
 #endif /* AUTH_MOD_H */

+ 26 - 0
modules/auth/doc/auth_params.xml

@@ -694,4 +694,30 @@ modparam("auth", "use_domain", 1)
 	</example>
 	</section>
 
+	<section id="auth.p.algorithm">
+	<title><varname>algorithm</varname> (string)</title>
+	<para>
+	   Configure hash algorithm used for digest authentication.
+	   Possible values are "MD5" or "SHA-256". If left empty MD5 is used.
+	   If specified, the specified algorithm is used and is also but in
+	   the 'algorithm' field of the challenge header.
+   </para>
+   <para>
+	   Warning: SHA-256 hash values take twice the space of MD5 hash values.
+	   So a buffer overflow might occur if this option is used in combination
+	   with another auth_* module that does not allocate at least 65 bytes to
+	   store hash values.
+	   SHA-256 can safely be used with the module auth_db as it allocates 256 bytes
+	   to store HA1 values.
+	</para>
+	<example>
+	   <title>use SHA-256 example</title>
+	   <programlisting>
+...
+modparam("auth", "algorithm", "SHA-256")
+...
+	   </programlisting>
+	</example>
+	</section>
+
 </section>

+ 2 - 2
modules/auth/rfc2617.c

@@ -61,7 +61,7 @@ inline void cvt_hex(HASH _b, HASHHEX _h)
 /*
  * calculate H(A1) as per spec
  */
-void calc_HA1(ha_alg_t _alg, str* _username, str* _realm, str* _password,
+void calc_HA1_md5(ha_alg_t _alg, str* _username, str* _realm, str* _password,
 		str* _nonce, str* _cnonce, HASHHEX _sess_key)
 {
 	MD5_CTX Md5Ctx;
@@ -92,7 +92,7 @@ void calc_HA1(ha_alg_t _alg, str* _username, str* _realm, str* _password,
 /*
  * calculate request-digest/response-digest as per HTTP Digest spec
  */
-void calc_response(HASHHEX _ha1,      /* H(A1) */
+void calc_response_md5(HASHHEX _ha1,      /* H(A1) */
 		str* _nonce,       /* nonce from server */
 		str* _nc,          /* 8 hex digits */
 		str* _cnonce,      /* client nonce */

+ 2 - 2
modules/auth/rfc2617.h

@@ -62,7 +62,7 @@ typedef void (*calc_HA1_t)(ha_alg_t _alg,      /* Type of algorithm */
 		str* _nonce,        /* nonce string */
 		str* _cnonce,       /* cnonce */
 		HASHHEX _sess_key); /* Result will be stored here */
-void calc_HA1(ha_alg_t _alg,      /* Type of algorithm */
+void calc_HA1_md5(ha_alg_t _alg,      /* Type of algorithm */
 		str* _username,     /* username */
 		str* _realm,        /* realm */
 		str* _password,     /* password */
@@ -82,7 +82,7 @@ typedef void (*calc_response_t)(HASHHEX _ha1,       /* H(A1) */
 		str* _uri,          /* requested URL */
 		HASHHEX _hentity,   /* H(entity body) if qop="auth-int" */
 		HASHHEX _response); /* request-digest or response-digest */
-void calc_response(HASHHEX _ha1,       /* H(A1) */
+void calc_response_md5(HASHHEX _ha1,       /* H(A1) */
 		str* _nonce,        /* nonce from server */
 		str* _nc,           /* 8 hex digits */
 		str* _cnonce,       /* client nonce */

+ 148 - 0
modules/auth/rfc2617_sha256.c

@@ -0,0 +1,148 @@
+/*
+ * Digest Authentication Module
+ * Digest response calculation as per RFC2617
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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 <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rfc2617_sha256.h"
+#include "../../lib/srutils/sha256.h"
+#include "../../dprint.h"
+
+
+inline void cvt_hex_sha256(HASH_SHA256 _b, HASHHEX_SHA256 _h)
+{
+	unsigned short i;
+	unsigned char j;
+
+	for (i = 0; i < HASHLEN_SHA256; i++) {
+		j = (_b[i] >> 4) & 0xf;
+		if (j <= 9) {
+			_h[i * 2] = (j + '0');
+		} else {
+			_h[i * 2] = (j + 'a' - 10);
+		}
+
+		j = _b[i] & 0xf;
+
+		if (j <= 9) {
+			_h[i * 2 + 1] = (j + '0');
+		} else {
+			_h[i * 2 + 1] = (j + 'a' - 10);
+		}
+	};
+
+	_h[HASHHEXLEN_SHA256] = '\0';
+}
+
+/* Cast to unsigned values and forward to sr_SHA256_Update */
+static inline void SHA256_Update(SHA256_CTX* context, char *data, int len)
+{
+	sr_SHA256_Update(context, (unsigned char*)data, (unsigned int)len);
+}
+
+/*
+ * calculate H(A1) as per spec
+ */
+void calc_HA1_sha256(ha_alg_t _alg, str* _username, str* _realm, str* _password,
+		str* _nonce, str* _cnonce, HASHHEX_SHA256 _sess_key)
+{
+	SHA256_CTX Sha256Ctx;
+	HASH_SHA256 HA1;
+
+	sr_SHA256_Init(&Sha256Ctx);
+	SHA256_Update(&Sha256Ctx, _username->s, _username->len);
+	SHA256_Update(&Sha256Ctx, ":", 1);
+	SHA256_Update(&Sha256Ctx, _realm->s, _realm->len);
+	SHA256_Update(&Sha256Ctx, ":", 1);
+	SHA256_Update(&Sha256Ctx, _password->s, _password->len);
+	sr_SHA256_Final(HA1, &Sha256Ctx);
+
+	if (_alg == HA_MD5_SESS) {
+		sr_SHA256_Init(&Sha256Ctx);
+		sr_SHA256_Update(&Sha256Ctx, HA1, HASHLEN_SHA256);
+		SHA256_Update(&Sha256Ctx, ":", 1);
+		SHA256_Update(&Sha256Ctx, _nonce->s, _nonce->len);
+		SHA256_Update(&Sha256Ctx, ":", 1);
+		SHA256_Update(&Sha256Ctx, _cnonce->s, _cnonce->len);
+		sr_SHA256_Final(HA1, &Sha256Ctx);
+	};
+
+	cvt_hex_sha256(HA1, _sess_key);
+}
+
+
+/*
+ * calculate request-digest/response-digest as per HTTP Digest spec
+ */
+void calc_response_sha256(HASHHEX_SHA256 _ha1,      /* H(A1) */
+		str* _nonce,       /* nonce from server */
+		str* _nc,          /* 8 hex digits */
+		str* _cnonce,      /* client nonce */
+		str* _qop,         /* qop-value: "", "auth", "auth-int" */
+		int _auth_int,     /* 1 if auth-int is used */
+		str* _method,      /* method from the request */
+		str* _uri,         /* requested URL */
+		HASHHEX_SHA256 _hentity,  /* H(entity body) if qop="auth-int" */
+		HASHHEX_SHA256 _response) /* request-digest or response-digest */
+{
+	SHA256_CTX Sha256Ctx;
+	HASH_SHA256 HA2;
+	HASH_SHA256 RespHash;
+	HASHHEX_SHA256 HA2Hex;
+
+	/* calculate H(A2) */
+	sr_SHA256_Init(&Sha256Ctx);
+	SHA256_Update(&Sha256Ctx, _method->s, _method->len);
+	SHA256_Update(&Sha256Ctx, ":", 1);
+	SHA256_Update(&Sha256Ctx, _uri->s, _uri->len);
+
+	if (_auth_int) {
+		SHA256_Update(&Sha256Ctx, ":", 1);
+		SHA256_Update(&Sha256Ctx, _hentity, HASHHEXLEN_SHA256);
+	};
+
+	sr_SHA256_Final(HA2, &Sha256Ctx);
+	cvt_hex_sha256(HA2, HA2Hex);
+
+	/* calculate response */
+	sr_SHA256_Init(&Sha256Ctx);
+	SHA256_Update(&Sha256Ctx, _ha1, HASHHEXLEN_SHA256);
+	SHA256_Update(&Sha256Ctx, ":", 1);
+	SHA256_Update(&Sha256Ctx, _nonce->s, _nonce->len);
+	SHA256_Update(&Sha256Ctx, ":", 1);
+
+	if (_qop->len) {
+		SHA256_Update(&Sha256Ctx, _nc->s, _nc->len);
+		SHA256_Update(&Sha256Ctx, ":", 1);
+		SHA256_Update(&Sha256Ctx, _cnonce->s, _cnonce->len);
+		SHA256_Update(&Sha256Ctx, ":", 1);
+		SHA256_Update(&Sha256Ctx, _qop->s, _qop->len);
+		SHA256_Update(&Sha256Ctx, ":", 1);
+	};
+	SHA256_Update(&Sha256Ctx, HA2Hex, HASHHEXLEN_SHA256);
+	sr_SHA256_Final(RespHash, &Sha256Ctx);
+	cvt_hex_sha256(RespHash, _response);
+}

+ 71 - 0
modules/auth/rfc2617_sha256.h

@@ -0,0 +1,71 @@
+/*
+ * Digest Authentication Module
+ * Digest response calculation as per RFC2617
+ *
+ * Copyright (C) 2001-2003 FhG Fokus
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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 RFC2617_SHA256_H
+#define RFC2617_SHA256_H
+
+#include "../../str.h"
+#include "rfc2617.h"
+
+
+#define HASHLEN_SHA256 32
+typedef unsigned char HASH_SHA256[HASHLEN_SHA256];
+
+
+#define HASHHEXLEN_SHA256 64
+typedef char HASHHEX_SHA256[HASHHEXLEN_SHA256+1];
+
+
+/*
+ * Convert to hex form
+ */
+void cvt_hex_sha256(HASH_SHA256 Bin, HASHHEX_SHA256 Hex);
+
+
+/*
+ * calculate H(A1) as per HTTP Digest spec
+ */
+void calc_HA1_sha256(ha_alg_t _alg,      /* Type of algorithm */
+		str* _username,     /* username */
+		str* _realm,        /* realm */
+		str* _password,     /* password */
+		str* _nonce,        /* nonce string */
+		str* _cnonce,       /* cnonce */
+		HASHHEX_SHA256 _sess_key); /* Result will be stored here */
+
+
+/* calculate request-digest/response-digest as per HTTP Digest spec */
+void calc_response_sha256(HASHHEX_SHA256 _ha1,       /* H(A1) */
+		str* _nonce,        /* nonce from server */
+		str* _nc,           /* 8 hex digits */
+		str* _cnonce,       /* client nonce */
+		str* _qop,          /* qop-value: "", "auth", "auth-int" */
+		int _auth_int,      /* 1 if auth-int is used */
+		str* _method,       /* method from the request */
+		str* _uri,          /* requested URL */
+		HASHHEX_SHA256 _hentity,   /* H(entity body) if qop="auth-int" */
+		HASHHEX_SHA256 _response); /* request-digest or response-digest */
+
+#endif /* RFC2617_SHA256_H */