[asterisk-commits] dvossel: branch 1.6.1 r205842 - in /branches/1.6.1: ./ channels/chan_sip.c
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Jul 10 11:48:10 CDT 2009
Author: dvossel
Date: Fri Jul 10 11:48:06 2009
New Revision: 205842
URL: http://svn.asterisk.org/svn-view/asterisk?view=rev&rev=205842
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.1/ (props changed)
branches/1.6.1/channels/chan_sip.c
Propchange: branches/1.6.1/
------------------------------------------------------------------------------
Binary property 'trunk-merged' - no diff available.
Modified: branches/1.6.1/channels/chan_sip.c
URL: http://svn.asterisk.org/svn-view/asterisk/branches/1.6.1/channels/chan_sip.c?view=diff&rev=205842&r1=205841&r2=205842
==============================================================================
--- branches/1.6.1/channels/chan_sip.c (original)
+++ branches/1.6.1/channels/chan_sip.c Fri Jul 10 11:48:06 2009
@@ -1359,6 +1359,7 @@
struct ast_variable *notify_headers; /*!< Custom notify type */
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) */
@@ -11246,6 +11247,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
@@ -11311,7 +11326,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);
@@ -11362,10 +11377,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))
@@ -11396,14 +11414,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"));
@@ -11536,7 +11554,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);
@@ -11581,7 +11599,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