Browse code

adds support for "qop" as described in rfc2617.

Please note that MD5-sess is still not supported.

Raphael Coeffic authored on 04/05/2011 13:52:39
Showing 2 changed files
... ...
@@ -155,7 +155,7 @@ bool UACAuth::onSipReply(const AmSipReply& reply, int old_dlg_status, const stri
155 155
 				
156 156
 	  if (do_auth(reply.code, auth_hdr,  
157 157
 		      ri->second.method,
158
-		      auth_uri, result)) {
158
+		      auth_uri, ri->second.body, result)) {
159 159
 	    string hdrs = ri->second.hdrs;
160 160
 	    // TODO(?): strip headers 
161 161
 	    // ((code==401) ? stripHeader(ri->second.hdrs, "Authorization")  :
... ...
@@ -274,11 +274,14 @@ bool UACAuth::parse_header(const string& auth_hdr, UACAuthDigestChallenge& chall
274 274
   challenge.opaque = find_attribute("opaque", auth_hdr);
275 275
   challenge.algorithm = find_attribute("algorithm", auth_hdr);
276 276
   challenge.qop = find_attribute("qop", auth_hdr);
277
+  
277 278
   return (challenge.realm.length() && challenge.nonce.length());
278 279
 }
279 280
 
280 281
 bool UACAuth::do_auth(const unsigned int code, const string& auth_hdr,  
281
-		      const string& method, const string& uri, string& result) {
282
+		      const string& method, const string& uri, 
283
+		      const string& body, string& result) 
284
+{
282 285
   if (!auth_hdr.length()) {
283 286
     ERROR("empty auth header.\n");
284 287
     return false;
... ...
@@ -295,8 +298,10 @@ bool UACAuth::do_auth(const unsigned int code, const string& auth_hdr,
295 298
     return false;
296 299
   }
297 300
 
298
-  DBG("realm='%s', nonce='%s'\n", challenge.realm.c_str(), 
299
-      challenge.nonce.c_str());
301
+  DBG("realm='%s', nonce='%s', qop='%s'\n", 
302
+      challenge.realm.c_str(), 
303
+      challenge.nonce.c_str(),
304
+      challenge.qop.c_str());
300 305
 
301 306
   if (credential->realm.length() 
302 307
       && (credential->realm != challenge.realm)) {
... ...
@@ -306,23 +311,60 @@ bool UACAuth::do_auth(const unsigned int code, const string& auth_hdr,
306 311
  
307 312
   HASHHEX ha1;
308 313
   HASHHEX ha2;
314
+  HASHHEX hentity;
309 315
   HASHHEX response;
316
+  bool    qop_auth=false;
317
+  bool    qop_auth_int=false;
318
+  string  cnonce;
319
+  string  qop_value;
320
+
321
+  if(!challenge.qop.empty()){
322
+
323
+    qop_auth = key_in_list(challenge.qop,"auth");
324
+    qop_auth_int = key_in_list(challenge.qop,"auth-int");
325
+
326
+    if(qop_auth || qop_auth_int) {
327
+
328
+      cnonce = int2hex(get_random(),true);
329
+
330
+      if(challenge.nonce == nonce)
331
+	nonce_count++;
332
+      else
333
+	nonce_count = 1;
334
+
335
+      if(qop_auth_int){
336
+	uac_calc_hentity(body,hentity);
337
+	qop_value = "auth-int";
338
+      }
339
+      else
340
+	qop_value = "auth";
341
+    }
342
+  }
310 343
 
311 344
   /* do authentication */
312
-  uac_calc_HA1( challenge, ""/*cnonce*/, ha1);
313
-  uac_calc_HA2( method, uri, challenge, 0/*hentity*/, ha2);
314
-  uac_calc_response( ha1, ha2, challenge, ""/*nc*/, "" /*cnonce*/, response);
345
+  uac_calc_HA1( challenge, cnonce, ha1);
346
+  uac_calc_HA2( method, uri, challenge, qop_auth_int ? hentity : NULL, ha2);
347
+  uac_calc_response( ha1, ha2, challenge, cnonce, qop_value, response);
315 348
   DBG("calculated response = %s\n", response);
316 349
 
317 350
   // compile auth response
318
-  result = ((code==401) ? SIP_HDR_COLSP(SIP_HDR_AUTHORIZATION) "Digest username=\"" : 
319
-	    SIP_HDR_COLSP(SIP_HDR_PROXY_AUTHORIZATION) "Digest username=\"")
320
-    + credential->user + "\", realm=\"" + challenge.realm + "\", nonce=\""+challenge.nonce + 
321
-    "\", uri=\""+uri+"\", ";
351
+  result = ((code==401) ? SIP_HDR_COLSP(SIP_HDR_AUTHORIZATION) : 
352
+	    SIP_HDR_COLSP(SIP_HDR_PROXY_AUTHORIZATION));
353
+
354
+  result += "Digest username=\"" + credential->user + "\", "
355
+    "realm=\"" + challenge.realm + "\", "
356
+    "nonce=\"" + challenge.nonce + "\", "
357
+    "uri=\"" + uri + "\", ";
358
+
322 359
   if (challenge.opaque.length())
323
-    result+="opaque=\""+challenge.opaque+"\", ";
360
+    result += "opaque=\"" + challenge.opaque + "\", ";
324 361
   
325
-  result+="response=\""+string((char*)response)+"\", algorithm=MD5\n";
362
+  if (!qop_value.empty())
363
+    result += "qop=\"" + qop_value + "\", "
364
+      "cnonce=\"" + cnonce + "\", "
365
+      "nc=\"" + int2hex(nonce_count,true) + "\", ";
366
+
367
+  result += "response=\"" + string((char*)response) + "\", algorithm=MD5\n";
326 368
 
327 369
   DBG("Auth req hdr: '%s'\n", result.c_str());
328 370
   
... ...
@@ -410,7 +452,7 @@ void UACAuth::uac_calc_HA2( const string& method, const string& uri,
410 452
   MD5Update(&Md5Ctx, hc, 1);
411 453
   w_MD5Update(&Md5Ctx, uri);
412 454
 
413
-  if ( challenge.qop == "auth-int" ) 
455
+  if ( hentity != 0 ) 
414 456
     {
415 457
       MD5Update(&Md5Ctx, hc, 1);
416 458
       MD5Update(&Md5Ctx, hentity, HASHHEXLEN);
... ...
@@ -420,15 +462,27 @@ void UACAuth::uac_calc_HA2( const string& method, const string& uri,
420 462
   cvt_hex(HA2, HA2Hex);
421 463
 }
422 464
 
465
+/*
466
+ * calculate H(body)
467
+ */
423 468
 
469
+void UACAuth::uac_calc_hentity( const string& body, HASHHEX hentity )
470
+{
471
+  MD5_CTX Md5Ctx;
472
+  HASH    h;
473
+
474
+  MD5Init(&Md5Ctx);
475
+  w_MD5Update(&Md5Ctx, body);
476
+  MD5Final(h, &Md5Ctx);
477
+  cvt_hex(h,hentity);
478
+}
424 479
 
425 480
 /* 
426 481
  * calculate request-digest/response-digest as per HTTP Digest spec 
427 482
  */
428 483
 void UACAuth::uac_calc_response( HASHHEX ha1, HASHHEX ha2,
429
-				 UACAuthDigestChallenge& challenge,
430
-				 const string& nc, const string& cnonce,
431
-				 HASHHEX response)
484
+				 UACAuthDigestChallenge& challenge, const string& cnonce,
485
+				 const string& qop_value, HASHHEX response)
432 486
 {
433 487
   unsigned char hc[1]; hc[0]=':';
434 488
   MD5_CTX Md5Ctx;
... ...
@@ -440,17 +494,15 @@ void UACAuth::uac_calc_response( HASHHEX ha1, HASHHEX ha2,
440 494
   w_MD5Update(&Md5Ctx, challenge.nonce);
441 495
   MD5Update(&Md5Ctx, hc, 1);
442 496
 
443
-  if (challenge.qop.length()
444
-      && challenge.qop == "auth_int")
445
-    {
497
+  if (!qop_value.empty()) {
446 498
       
447
-      w_MD5Update(&Md5Ctx, nc);
448
-      MD5Update(&Md5Ctx, hc, 1);
449
-      w_MD5Update(&Md5Ctx, cnonce);
450
-      MD5Update(&Md5Ctx, hc, 1);
451
-      w_MD5Update(&Md5Ctx, "" /*challenge.qop*/);
452
-      MD5Update(&Md5Ctx, hc, 1);
453
-    };
499
+    w_MD5Update(&Md5Ctx, int2hex(nonce_count,true));
500
+    MD5Update(&Md5Ctx, hc, 1);
501
+    w_MD5Update(&Md5Ctx, cnonce);
502
+    MD5Update(&Md5Ctx, hc, 1);
503
+    w_MD5Update(&Md5Ctx, qop_value);
504
+    MD5Update(&Md5Ctx, hc, 1);
505
+  };
454 506
 
455 507
   MD5Update(&Md5Ctx, ha2, HASHHEXLEN);
456 508
   MD5Final(RespHash, &Md5Ctx);
... ...
@@ -105,6 +105,9 @@ class UACAuth : public AmSessionEventHandler
105 105
   UACAuthCred* credential;
106 106
   AmSipDialog* dlg;
107 107
 
108
+  string nonce; // last nonce received from server
109
+  unsigned int nonce_count;
110
+
108 111
   std::string find_attribute(const std::string& name, const std::string& header);
109 112
   bool parse_header(const std::string& auth_hdr, UACAuthDigestChallenge& challenge);
110 113
 
... ...
@@ -116,10 +119,12 @@ class UACAuth : public AmSessionEventHandler
116 119
 		     UACAuthDigestChallenge& challenge,
117 120
 		     HASHHEX hentity,
118 121
 		     HASHHEX HA2Hex );
122
+
123
+  void uac_calc_hentity( const std::string& body, HASHHEX hentity );
119 124
 	
120 125
   void uac_calc_response( HASHHEX ha1, HASHHEX ha2,
121 126
 			  UACAuthDigestChallenge& challenge,
122
-			  const std::string& nc, const std::string& cnonce,
127
+			  const std::string& cnonce, const string& qop_value, 
123 128
 			  HASHHEX response);
124 129
 	
125 130
   /** 
... ...
@@ -127,7 +132,8 @@ class UACAuth : public AmSessionEventHandler
127 132
    *  @return true if successful 
128 133
    */
129 134
   bool do_auth(const unsigned int code, const string& auth_hdr,  
130
-	       const string& method, const string& uri, string& result);
135
+	       const string& method, const string& uri, 
136
+	       const string& body, string& result);
131 137
 	
132 138
  public:
133 139