[asterisk-commits] dvossel: branch 1.6.0 r205843 - in /branches/1.6.0: ./ channels/chan_sip.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Jul 10 11:49:00 CDT 2009


Author: dvossel
Date: Fri Jul 10 11:48:56 2009
New Revision: 205843

URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=205843
Log:
Merged revisions 205840 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/trunk

................
  r205840 | dvossel | 2009-07-10 11:42:04 -0500 (Fri, 10 Jul 2009) | 37 lines
  
  Merged revisions 205804 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.4
  
  ........
    r205804 | dvossel | 2009-07-10 11:23:59 -0500 (Fri, 10 Jul 2009) | 31 lines
    
    SIP registration auth loop caused by stale nonce
    
    If an endpoint sends two registration requests in a very short
    period of time with the same nonce, both receive 401 responses
    from Asterisk, each with a different nonce (the second 401
    containing the current nonce and the first one being stale).
    If the endpoint responds to the first 401, it does not match
    the current nonce so Asterisk sends a third 401 with a newly
    generated nonce (which updates the current nonce)... Now if
    the endpoint responds to the second 401, it does not match the
    current nonce either and Asterisk sends a fourth 401 with a
    newly generated nonce... This loop goes on and on.
    
    There appears to be a simple fix for this.  If the nonce from
    the request does not match our nonce, but is a good response
    to a previous nonce, instead of sending a 401 with a newly
    generated nonce, use the current one instead.  This breaks
    the loop as the nonce is not updated until a response is
    received. Additional logic has been added to make sure no
    nonce can be responded to twice though.
    
    (closes issue #15102)
    Reported by: Jamuel
    Patches:
          patch-bug_0015102 uploaded by Jamuel (license 809)
          nonce_sip.diff uploaded by dvossel (license 671)
    Tested by: Jamuel
    
    Review: https://reviewboard.asterisk.org/r/289/
  ........
................

Modified:
    branches/1.6.0/   (props changed)
    branches/1.6.0/channels/chan_sip.c

Propchange: branches/1.6.0/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.

Modified: branches/1.6.0/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.0/channels/chan_sip.c?view=diff&rev=205843&r1=205842&r2=205843
==============================================================================
--- branches/1.6.0/channels/chan_sip.c (original)
+++ branches/1.6.0/channels/chan_sip.c Fri Jul 10 11:48:56 2009
@@ -1273,6 +1273,7 @@
 	int route_persistant;			/*!< Is this the "real" route? */
 	struct sip_auth *peerauth;		/*!< Realm authentication */
 	int noncecount;				/*!< Nonce-count */
+	unsigned int stalenonce:1;	/*!< Marks the current nonce as responded too */
 	char lastmsg[256];			/*!< Last Message sent/received */
 	int amaflags;				/*!< AMA Flags */
 	int pendinginvite;			/*!< Any pending INVITE or state NOTIFY (in subscribe pvt's) ? (seqno of this) */
@@ -10759,6 +10760,20 @@
 		list_route(p->route);
 }
 
+/*! \brief builds the sip_pvt's randdata field which is used for the nonce
+ *  challenge.  When forceupdate is not set, the nonce is only updated if
+ *  the current one is stale.  In this case, a stalenonce is one which
+ *  has already received a response, if a nonce has not received a response
+ *  it is not always necessary or beneficial to create a new one. */
+
+static void set_nonce_randdata(struct sip_pvt *p, int forceupdate)
+{
+	if (p->stalenonce || forceupdate || ast_strlen_zero(p->randdata)) {
+		ast_string_field_build(p, randdata, "%08lx", ast_random());	/* Create nonce for challenge */
+		p->stalenonce = 0;
+	}
+}
+
 AST_THREADSTORAGE(check_auth_buf);
 #define CHECK_AUTH_BUF_INITLEN   256
 
@@ -10824,7 +10839,7 @@
 		return AUTH_CHALLENGE_SENT;
 	} else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
 		/* We have no auth, so issue challenge and request authentication */
-		ast_string_field_build(p, randdata, "%08lx", ast_random());	/* Create nonce for challenge */
+		set_nonce_randdata(p, 1); /* Create nonce for challenge */
 		transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
 		/* Schedule auto destroy in 32 seconds */
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -10875,10 +10890,13 @@
 		return AUTH_USERNAME_MISMATCH;
 	}
 
-	/* Verify nonce from request matches our nonce.  If not, send 401 with new nonce */
-	if (strcasecmp(p->randdata, keys[K_NONCE].s)) { /* XXX it was 'n'casecmp ? */
+	/* Verify nonce from request matches our nonce, and the nonce has not already been responded to.
+	 * If this check fails, send 401 with new nonce */
+	if (strcasecmp(p->randdata, keys[K_NONCE].s) || p->stalenonce) { /* XXX it was 'n'casecmp ? */
 		wrongnonce = TRUE;
 		usednonce = keys[K_NONCE].s;
+	} else {
+		p->stalenonce = 1; /* now, since the nonce has a response, mark it as stale so it can't be sent or responded to again */
 	}
 
 	if (!ast_strlen_zero(md5secret))
@@ -10909,14 +10927,14 @@
 			if (sipdebug)
 				ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", get_header(req, "To"));
 			/* We got working auth token, based on stale nonce . */
-			ast_string_field_build(p, randdata, "%08lx", ast_random());
+			set_nonce_randdata(p, 0);
 			transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, TRUE);
 		} else {
 			/* Everything was wrong, so give the device one more try with a new challenge */
 			if (!req->ignore) {
 				if (sipdebug)
 					ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", get_header(req, "To"));
-				ast_string_field_build(p, randdata, "%08lx", ast_random());
+				set_nonce_randdata(p, 1);
 			} else {
 				if (sipdebug)
 					ast_log(LOG_NOTICE, "Duplicate authentication received from '%s'\n", get_header(req, "To"));
@@ -11048,7 +11066,7 @@
 		return;
 	} else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
 		/* We have no auth, so issue challenge and request authentication */
-		ast_string_field_build(p, randdata, "%08lx", ast_random());	/* Create nonce for challenge */
+		set_nonce_randdata(p, 1);
 		transmit_response_with_auth(p, response, req, p->randdata, 0, respheader, 0);
 		/* Schedule auto destroy in 32 seconds */
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -11093,7 +11111,7 @@
 	/* Verify nonce from request matches our nonce.  If not, send 401 with new nonce */
 	if (strcasecmp(p->randdata, keys[K_NONCE].s)) {
 		if (!req->ignore) {
-			ast_string_field_build(p, randdata, "%08lx", ast_random());
+			set_nonce_randdata(p, 1);
 		}
 		transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, FALSE);
 




More information about the asterisk-commits mailing list