Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion libsofia-sip-ua/iptsec/auth_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,8 @@ static int auc_digest_challenge(auth_client_t *ca, msg_auth_t const *ch)

stale = ac->ac_stale || cda->cda_ac->ac_nonce == NULL;

if (ac->ac_qop && (cda->cda_cnonce == NULL || ac->ac_stale || ca->ca_clear )) {
if (ac->ac_qop && (cda->cda_cnonce == NULL || ac->ac_stale || ca->ca_clear
|| su_strcmp(ac->ac_nonce, cda->cda_ac->ac_nonce) != 0)) {
su_guid_t guid[1];
char *cnonce;
size_t b64len = BASE64_MINSIZE(sizeof(guid)) + 1;
Expand Down
83 changes: 83 additions & 0 deletions libsofia-sip-ua/iptsec/test_auth_digest.c
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,89 @@ int test_digest_client(void)
TEST(as->as_status, 0);
auth_mod_destroy(am); aucs = NULL;

/* Test nc reset on new nonce without stale=true.
*
* When a server issues a fresh 401 with a new nonce but without
* stale=true, the nc counter must reset to 00000001 for the new nonce.
* See RFC 2617 section 3.2.2.
*/
{

TEST_1(am = auth_mod_create(root,
AUTHTAG_METHOD("Digest"),
AUTHTAG_REALM("ims3.so.noklab.net"),
AUTHTAG_DB(testpasswd),
AUTHTAG_QOP("auth"),
AUTHTAG_MAX_NCOUNT(5),
AUTHTAG_ALGORITHM("MD5"),
TAG_END()));

/* Get initial 401 challenge (nonce A) */
reinit_as(as);
auth_mod_check_client(am, as, NULL, ach);
TEST(as->as_status, 401);
TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
sip_authorization_class), 1);
TEST(auc_all_credentials(&aucs, "Digest", "\"ims3.so.noklab.net\"",
"user1", "secret"), 1);

/* Authorize with nonce A — nc must be 00000001 */
msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
(url_t *)"sip:surf3@ims3.so.noklab.net",
sip->sip_payload), 1);
TEST_1(sip->sip_authorization);
TEST_S(msg_header_find_param(sip->sip_authorization->au_common, "nc="),
"00000001");

/* Server accepts auth with nonce A */
reinit_as(as);
auth_mod_check_client(am, as, sip->sip_authorization, ach);
TEST(as->as_status, 0);

/* Advance time so the new auth_mod generates a different nonce.
* Nonce includes the timestamp, so a 1-second shift is enough. */
offset += 1;

/* Destroy auth_mod to get a different nonce on next challenge */
auth_mod_destroy(am);
TEST_1(am = auth_mod_create(root,
AUTHTAG_METHOD("Digest"),
AUTHTAG_REALM("ims3.so.noklab.net"),
AUTHTAG_DB(testpasswd),
AUTHTAG_QOP("auth"),
AUTHTAG_MAX_NCOUNT(5),
AUTHTAG_ALGORITHM("MD5"),
TAG_END()));

/* Get new 401 challenge (nonce B, stale=false).
* auc_challenge returns 0 here because the new nonce without
* stale=true is not recognized as an update at the auc_challenge
* level. The nc reset still happens internally in
* auc_digest_challenge via the cnonce regeneration path. */
reinit_as(as);
auth_mod_check_client(am, as, NULL, ach);
TEST(as->as_status, 401);
TEST(auc_challenge(&aucs, home, (msg_auth_t *)as->as_response,
sip_authorization_class), 0);

/* Authorize with nonce B — nc MUST reset to 00000001, not 00000002 */
msg_header_remove(m2, (void *)sip, (void *)sip->sip_authorization);
TEST(auc_authorization(&aucs, m2, (msg_pub_t*)sip, rq->rq_method_name,
(url_t *)"sip:surf3@ims3.so.noklab.net",
sip->sip_payload), 1);
TEST_1(sip->sip_authorization);
TEST_S(msg_header_find_param(sip->sip_authorization->au_common, "nc="),
"00000001");

/* Server accepts auth with nonce B */
reinit_as(as);
auth_mod_check_client(am, as, sip->sip_authorization, ach);
TEST(as->as_status, 0);

auth_mod_destroy(am); aucs = NULL;
}

/* Test empty realm */
TEST_1(am = auth_mod_create(root,
AUTHTAG_METHOD("Digest"),
Expand Down