Discussion:
[Sipp-users] Patch to correctly increment 'nc' in authorization header
Matthew Briggs
2012-09-07 01:32:14 UTC
Permalink
I see a few people have found the following issue with SIPp: 'nc' counter not incremented when authorization reused.

Background:

According to SIP-Connect:

"...
2. In order to avoid unnecessary challenges, the SIP-PBX SHOULD include its authorization credentials using the current nonce in each subsequent request that allows authentication credentials to be sent to the SP-SSE..."

So an endpoint should be able to (and SHOULD) re-send it's existing authorization credentials with each INVITE, REFER,. etc it sends. It MAY be challenged for new authorization (401 / 407 Unauthorised). but the previous credentials MAY be accepted, thus reducing mwessage load on the system.

According to RFC2617, the 'nc' counter in the authorization header MUST be incremented for successive new messages which re-use an existing authorization, (but not incremented for retransmissions of old messages).

"nonce-count
This MUST be specified if a qop directive is sent (see above), and
MUST NOT be specified if the server did not send a qop directive in
the WWW-Authenticate header field. The nc-value is the hexadecimal
count of the number of requests (including the current request)
that the client has sent with the nonce value in this request. For
example, in the first request sent in response to a given nonce
value, the client sends "nc=00000001". The purpose of this
directive is to allow the server to detect request replays by
maintaining its own copy of this count - if the same nc-value is
seen twice, then the request is a replay. See the description
below of the construction of the request-digest value."


The problem: SIPP has 'nc' hard-coded to '1'


The patch below sets nc to '1' for each new authorization, then increments it each time a new message is generated which reuses the same authorization. The counter is not incremented for retransmissions. This probably counts as a hack, so apollogies for that - but it does the job.


diff -bruN of affected files: Diff is aghainst SIPP v 3.2



--- ../sipp.svn/auth.c 2011-12-17 09:28:00.062500000 +1300
+++ auth.c 2012-09-07 11:20:58.328125000 +1200
@@ -79,13 +79,14 @@

int createAuthHeaderMD5(char * user, char * password, int password_len, char * method,
char * uri, char * msgbody, char * auth,
- char * algo, char * result);
+ char * algo, char * result, unsigned int mync);
int createAuthHeaderAKAv1MD5(char * user, char * OP,
char * AMF,
char * K,
char * method,
char * uri, char * msgbody, char * auth, char *algo,
- char * result);
+ char * result,
+ unsigned int mync);


/* This function is from RFC 2617 Section 5 */
@@ -143,7 +144,8 @@
char * aka_OP,
char * aka_AMF,
char * aka_K,
- char * result) {
+ char * result,
+ unsigned int mync) {

char algo[32]="MD5";
char *start, *end;
@@ -163,12 +165,12 @@
}

if (strncasecmp(algo, "MD5", 3)==0) {
- return createAuthHeaderMD5(user,password,strlen(password),method,uri,msgbody,auth,algo,result);
+ return createAuthHeaderMD5(user,password,strlen(password),method,uri,msgbody,auth,algo,result,mync);
} else if (strncasecmp(algo, "AKAv1-MD5", 9)==0) {
return createAuthHeaderAKAv1MD5(user, aka_OP,
aka_AMF,
aka_K,
- method,uri,msgbody,auth,algo,result);
+ method,uri,msgbody,auth,algo,result,mync);
}else{
sprintf(result, "createAuthHeader: authentication must use MD5 or AKAv1-MD5");
return 0;
@@ -213,14 +215,13 @@

int createAuthHeaderMD5(char * user, char * password, int password_len, char * method,
char * uri, char * msgbody, char * auth,
- char * algo, char * result) {
+ char * algo, char * result, unsigned int mync) {

unsigned char ha1[MD5_HASH_SIZE], ha2[MD5_HASH_SIZE];
unsigned char resp[MD5_HASH_SIZE], body[MD5_HASH_SIZE];
unsigned char ha1_hex[HASH_HEX_SIZE+1], ha2_hex[HASH_HEX_SIZE+1];
unsigned char resp_hex[HASH_HEX_SIZE+1], body_hex[HASH_HEX_SIZE+1];
char tmp[MAX_HEADER_LEN], authtype[16], cnonce[32], nc[32], opaque[64];
- static unsigned int mync = 1;
int has_opaque = 0;
MD5_CTX Md5Ctx;

@@ -584,7 +585,8 @@
char * aka_K,
char * method,
char * uri, char * msgbody, char * auth, char *algo,
- char * result) {
+ char * result,
+ unsigned int mync) {

char tmp[MAX_HEADER_LEN];
char *start, *end;
@@ -657,7 +659,7 @@
sqn_he[5] = sqn[5];
has_auts = 0;
/* RES has to be used as password to compute response */
- resuf = createAuthHeaderMD5(user, (char *) res, RESLEN, method, uri, msgbody, auth, algo, result);
+ resuf = createAuthHeaderMD5(user, (char *) res, RESLEN, method, uri, msgbody, auth, algo, result, mync);
} else {
sqn_ms[5] = sqn_he[5] + 1;
f5star(k, rnd, ak, op);
@@ -667,7 +669,7 @@
has_auts = 1;
/* When re-synchronisation occurs an empty password has to be used */
/* to compute MD5 response (Cf. rfc 3310 section 3.2) */
- resuf=createAuthHeaderMD5(user,"",0,method,uri,msgbody,auth,algo,result);
+ resuf=createAuthHeaderMD5(user,"",0,method,uri,msgbody,auth,algo,result,mync);
}
if (has_auts) {
/* Format data for output in the SIP message */




--- ../sipp.svn/call.cpp 2012-01-30 11:44:23.734375000 +1300
+++ call.cpp 2012-09-07 11:46:32.421875000 +1200
@@ -409,6 +409,7 @@
#ifdef _USE_OPENSSL
dialog_authentication = NULL;
dialog_challenge_type = 0;
+ lastnc = 1;

m_ctx_ssl = NULL ;
m_bio = NULL ;
@@ -2492,7 +2493,7 @@
createSendingMessage(auth_comp->comp_param.auth_param.aka_OP, -2, my_aka_OP, sizeof(my_aka_OP));

if (createAuthHeader(my_auth_user, my_auth_pass, method, uri, auth_body, dialog_authentication,
- my_aka_OP, my_aka_AMF, my_aka_K, result + authlen) == 0) {
+ my_aka_OP, my_aka_AMF, my_aka_K, result + authlen, lastnc++) == 0) {
ERROR("%s", result + authlen);
}
authlen = strlen(result);
@@ -3302,6 +3303,7 @@
}

dialog_authentication = (char *) realloc(dialog_authentication, strlen(auth) + 2);
+ lastnc = 1;
sprintf(dialog_authentication, "%s", auth);

/* Store the code of the challenge for building the proper header */





--- ../sipp.svn/call.hpp 2011-12-17 15:02:12.593750000 +1300
+++ call.hpp 2012-09-07 11:40:15.000000000 +1200
@@ -52,9 +52,9 @@
#define RTCHECK_LOOSE 2

#ifdef __HPUX
- extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result);
+ extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result, unsigned int mync);
#else
- extern "C" { extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result); }
+ extern "C" { extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result, unsigned int mync); }
extern "C" { int verifyAuthHeader(char * user, char * password, char * method, char * auth); }
#endif

@@ -174,6 +174,8 @@
#ifdef _USE_OPENSSL
/* holds the auth header and if the challenge was 401 or 407 */
char * dialog_authentication;
+ unsigned int lastnc;
+
int dialog_challenge_type;
#endif

===================================


Matt Briggs
Test Engineer

Mobile: +64 27 ####
www.telecom.co.nz

Loading...