reSIProcate/stack  9694
testDigestAuthentication.cxx
Go to the documentation of this file.
00001 #include <assert.h>
00002 #include <iostream>
00003 #include <string.h>
00004 #ifdef WIN32
00005 #include <io.h>
00006 #else
00007 #include <unistd.h>
00008 #endif
00009 #include <memory>
00010 
00011 #ifdef WIN32
00012 #define usleep(x) Sleep(x/1000)
00013 #define sleep(x) Sleep(x*1000)
00014 #endif
00015 
00016 #include "resip/stack/HeaderFieldValue.hxx"
00017 #include "resip/stack/HeaderTypes.hxx"
00018 #include "resip/stack/ParserCategories.hxx"
00019 #include "resip/stack/Uri.hxx"
00020 #include "resip/stack/Helper.hxx"
00021 #include "resip/stack/test/TestSupport.hxx"
00022 #include "rutil/Timer.hxx"
00023 #include "rutil/DataStream.hxx"
00024 #include "rutil/MD5Stream.hxx"
00025 #include "digcalc.hxx"
00026 
00027 using namespace std;
00028 using namespace resip;
00029 
00030 int
00031 main(int arc, char** argv)
00032 {
00033    {
00034       Auth auth;
00035       auth.scheme() = "Digest";
00036       Data timestamp((unsigned int)(Timer::getTimeMs()/1000));
00037       auth.param(p_nonce) = "askdfjhaslkjhf498hw98hw98hfsf";      
00038       auth.param(p_algorithm) = "MD5";
00039       auth.param(p_realm) = "example.com";
00040       
00041       assert(Helper::algorithmAndQopSupported(auth));
00042       auth.param(p_algorithm) = "MD5-sess";
00043       assert(!Helper::algorithmAndQopSupported(auth));
00044       auth.param(p_algorithm) = "monkey";
00045       assert(!Helper::algorithmAndQopSupported(auth));
00046 
00047       auth.param(p_algorithm) = "MD5";
00048       auth.param(p_qop) = Symbols::auth;
00049       assert(Helper::algorithmAndQopSupported(auth));
00050 
00051       auth.param(p_qop) = Symbols::authInt;
00052       assert(Helper::algorithmAndQopSupported(auth));
00053       
00054       auth.param(p_qop) = "monkey";
00055       assert(!Helper::algorithmAndQopSupported(auth));
00056 
00057       cerr << "algorithmAndQopSupported passed" << endl;            
00058    }
00059    
00060    {
00061       assert(Data("").md5() == "d41d8cd98f00b204e9800998ecf8427e");
00062       assert(Data("a").md5() == "0cc175b9c0f1b6a831c399e269772661");
00063       assert(Data("abc").md5() == "900150983cd24fb0d6963f7d28e17f72");
00064       assert(Data("message digest").md5() == "f96b697d7cb7938d525a2f31aaf161d0");
00065       assert(Data("abcdefghijklmnopqrstuvwxyz").md5() == "c3fcd3d76192e4007dfb496cca67e13b");
00066       assert(Data("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789").md5() == "d174ab98d277d9f5a5611c2c9f419d9f");
00067       assert(Data("12345678901234567890123456789012345678901234567890123456789012345678901234567890").md5() == "57edf4a22be3c955ac49da2e2107b67a");
00068    }
00069    
00070    {
00071       {
00072          MD5Stream s;
00073          assert(s.getHex() == Data("").md5());
00074       }
00075       {
00076          MD5Stream s;
00077          s << "a";
00078          assert(s.getHex() == Data("a").md5());
00079       }
00080       {
00081          MD5Stream s;
00082          s << "abc";
00083          assert(s.getHex() == Data("abc").md5());
00084       }
00085       {
00086          MD5Stream s;
00087          s << "message digest";
00088          assert(s.getHex() == Data("message digest").md5());
00089       }
00090       {
00091          MD5Stream s;
00092          s << "12345678901234567890123456789012345678901234567890123456789012345678901234567890";
00093          assert(s.getHex() == Data("12345678901234567890123456789012345678901234567890123456789012345678901234567890").md5());
00094       }
00095       {
00096          Data d;
00097          DataStream ds(d);
00098          MD5Stream s;
00099 
00100          s << "this involves" << 7.8 << "foo" << 34653453 << -6 << "hike";
00101          ds << "this involves" << 7.8 << "foo" << 34653453 << -6 << "hike";
00102          ds.flush();
00103 
00104          assert(d.md5() == s.getHex());
00105       }
00106    }
00107 
00108    {
00109       const char* alg = "MD5";
00110       const char* username = "user";
00111       const char* password = "secret";
00112       const char* realm = "localhost";
00113       const char* method = "REGISTER";
00114       const char* uri = "user@host.com";
00115       const char* nonce = "92347fea23";
00116 
00117       Data responseMD5 = Helper::makeResponseMD5(username,
00118                                                  password,
00119                                                  realm,
00120                                                  method,
00121                                                  uri,
00122                                                  nonce);
00123       
00124       HASHHEX a1Hash;
00125       HASHHEX response;
00126 
00127       DigestCalcHA1(alg,
00128                     username,
00129                     realm,
00130                     password,
00131                     nonce,
00132                     (char*)"",
00133                     a1Hash);
00134 
00135       DigestCalcResponse(a1Hash,
00136                          nonce,
00137                          (char*)"",
00138                          (char*)"",
00139                          (char*)"",
00140                          method,
00141                          uri,
00142                          (char*)"",
00143                          response);
00144 
00145       assert(responseMD5 == response);
00146    }
00147 
00148    {
00149       const char* alg = "MD5";
00150       const char* username = "user";
00151       const char* password = "secret";
00152       const char* realm = "localhost";
00153       const char* method = "REGISTER";
00154       const char* uri = "user@host.com";
00155       const char* nonce = "92347fea23";
00156       const char* cnonce = "72345hef";
00157       const char* cnonceCount = "00000001";
00158       const char* qop = "auth";
00159 
00160       Data responseMD5 = Helper::makeResponseMD5(username,
00161                                                  password,
00162                                                  realm,
00163                                                  method,
00164                                                  uri,
00165                                                  nonce,
00166                                                  qop,
00167                                                  cnonce,
00168                                                  cnonceCount);
00169       
00170       HASHHEX a1Hash;
00171       HASHHEX response;
00172 
00173       DigestCalcHA1(alg,
00174                     username,
00175                     realm,
00176                     password,
00177                     nonce,
00178                     cnonce,
00179                     a1Hash);
00180 
00181       DigestCalcResponse(a1Hash,
00182                          nonce,
00183                          cnonceCount,
00184                          cnonce,
00185                          qop,
00186                          method,
00187                          uri,
00188                          (char*)"",
00189                          response);
00190 
00191       assert(responseMD5 == response);
00192    }
00193 
00194    {
00195       const char* alg = "MD5";
00196       const char* username = "user";
00197       const char* password = "secret";
00198       const char* realm = "localhost";
00199       const char* method = "REGISTER";
00200       const char* uri = "user@host.com";
00201       const char* nonce = "92347fea23";
00202 
00203       Data responseMD5 = Helper::makeResponseMD5(username,
00204                                                  password,
00205                                                  realm,
00206                                                  method,
00207                                                  uri,
00208                                                  nonce);
00209       
00210       HASHHEX a1Hash;
00211       HASHHEX response;
00212 
00213       DigestCalcHA1(alg,
00214                     username,
00215                     realm,
00216                     password,
00217                     nonce,
00218                     (char*)"",
00219                     a1Hash);
00220 
00221       DigestCalcResponse(a1Hash,
00222                          nonce,
00223                          (char*)"",
00224                          (char*)"",
00225                          (char*)"",
00226                          method,
00227                          uri,
00228                          (char*)"",
00229                          response);
00230 
00231       assert(responseMD5 == response);
00232    }
00233 
00234 /*
00235 REGISTER sip:kelowna.gloo.net SIP/2.0
00236 To: sip:100@kelowna.gloo.net
00237 From: <sip:100@kelowna.gloo.net>
00238 Call-ID: 000532ff-828108c2-79016ad7-69ac4815@192.168.2.233
00239 CSeq: 102 REGISTER
00240 Contact: sip:100@192.168.2.233:5060
00241 Via: SIP/2.0/UDP 192.168.2.233:5060;received=192.168.2.233;rport=5060
00242 Expires: 3600
00243 Date: Sat, 07 Dec 2002 02:21:59 GMT
00244 Proxy-Authorization: Digest username="sip:100@kelowna.gloo.net:5060",realm="kelowna.gloo.net",uri="sip:kelowna.gloo.net",response="8485db84088e6be6c55717d2eb891eca",nonce="1039227719:9e17fc5e10c30f162e7a21c9f6a4d2a7",algorithm=MD5
00245 User-Agent: CSCO/4
00246 Content-Length: 0
00247 */
00248 
00249 /*
00250 Proxy-Authorization: Digest username="sip:100@kelowna.gloo.net:5060",realm="kelowna.gloo.net",uri="sip:kelowna.gloo.net",response="8485db84088e6be6c55717d2eb891eca",nonce="1039227719:9e17fc5e10c30f162e7a21c9f6a4d2a7",algorithm=MD5
00251 */
00252    {
00253       const char* alg = "MD5";
00254       const char* username = "sip:100@kelowna.gloo.net:5060";
00255       const char* password = "secret";
00256       const char* realm = "kelowna.gloo.net";
00257       const char* method = "REGISTER";
00258       const char* uri = "sip:kelowna.gloo.net";
00259       const char* nonce = "1039227719:9e17fc5e10c30f162e7a21c9f6a4d2a7";
00260       const char* cnonce = "";
00261       const char* cnonceCount = "";
00262       const char* qop = "";
00263 
00264       Data responseMD5 = Helper::makeResponseMD5(username,
00265                                                  password,
00266                                                  realm,
00267                                                  method,
00268                                                  uri,
00269                                                  nonce,
00270                                                  qop,
00271                                                  cnonce,
00272                                                  cnonceCount);
00273       
00274       HASHHEX a1Hash;
00275       HASHHEX response;
00276 
00277       DigestCalcHA1(alg,
00278                     username,
00279                     realm,
00280                     password,
00281                     nonce,
00282                     cnonce,
00283                     a1Hash);
00284 
00285       DigestCalcResponse(a1Hash,
00286                          nonce,
00287                          cnonceCount,
00288                          cnonce,
00289                          qop,
00290                          method,
00291                          uri,
00292                          (char*)"",
00293                          response);
00294 
00295       assert(responseMD5 == response);
00296    }
00297 
00298 
00299 /*
00300 Calling form_SIPdigest with:
00301   nonce    = 1039063045
00302   user     = sip:100@kelowna.gloo.net:5060
00303   pswd     = secret
00304   method   = REGISTER
00305   uri      = sip:kelowna.gloo.net
00306   realm    = kelowna.gloo.net
00307   algorithm= MD5
00308 Message digest    == 575a9ecd3a6f1989a978748217b24a25
00309 Calculated digest == 575a9ecd3a6f1989a978748217b24a25
00310 */
00311    {
00312       const char* alg = "MD5";
00313       const char* username = "sip:100@kelowna.gloo.net:5060";
00314       const char* password = "secret";
00315       const char* realm = "kelowna.gloo.net";
00316       const char* method = "REGISTER";
00317       const char* uri = "sip:kelowna.gloo.net";
00318       const char* nonce = "1039063045";
00319 
00320       Data responseMD5 = Helper::makeResponseMD5(username,
00321                                                  password,
00322                                                  realm,
00323                                                  method,
00324                                                  uri,
00325                                                  nonce);
00326       
00327       HASHHEX a1Hash;
00328       HASHHEX response;
00329 
00330       DigestCalcHA1(alg,
00331                     username,
00332                     realm,
00333                     password,
00334                     nonce,
00335                     (char*)"",
00336                     a1Hash);
00337 
00338       DigestCalcResponse(a1Hash,
00339                          nonce,
00340                          (char*)"",
00341                          (char*)"",
00342                          (char*)"",
00343                          method,
00344                          uri,
00345                          (char*)"",
00346                          response);
00347 
00348       assert(responseMD5 == response);
00349       assert(responseMD5 == "575a9ecd3a6f1989a978748217b24a25");
00350    }
00351 
00352    {
00353       Data txt("INVITE sip:bob@biloxi.com SIP/2.0\r\n"
00354                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\r\n"
00355                "To: Bob <sip:bob@biloxi.com>\r\n"
00356                "From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n"
00357                "Call-ID: a84b4c76e66710\r\n"
00358                "CSeq: 314159 INVITE\r\n"
00359                "Max-Forwards: 70\r\n"
00360                "Contact: <sip:alice@pc33.atlanta.com>\r\n"
00361                "Content-Type: application/sdp\r\n"
00362                "Content-Length: 150\r\n"
00363                "\r\n"
00364                "v=0\r\n"
00365                "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n"
00366                "s=-\r\n"
00367                "c=IN IP4 pc33.atlanta.com\r\n"
00368                "t=0 0\r\n"
00369                "m=audio 3456 RTP/AVP 0 1 3 99\r\n"
00370                "a=rtpmap:0 PCMU/8000\r\n");
00371 
00372       auto_ptr<SipMessage> request(TestSupport::makeMessage(txt.c_str()));      
00373 
00374       Data realm = "localhost";
00375       auto_ptr<SipMessage> challenge(Helper::makeProxyChallenge(*request, realm, false));
00376 
00377       assert(challenge->exists(h_ProxyAuthenticates));
00378       assert(challenge->header(h_ProxyAuthenticates).size() == 1);
00379 
00380       Data username = "bob";
00381       Data password = "secret";
00382       Data cnonce = "366fead6";
00383       unsigned int nc = 0;
00384       
00385       Data encodedPassword = password.md5();
00386 
00387       Helper::addAuthorization(*request,
00388                                *challenge,
00389                                username,
00390                                encodedPassword,
00391                                cnonce,
00392                                nc);
00393 
00394       assert(request->exists(h_ProxyAuthorizations));
00395       assert(request->header(h_ProxyAuthorizations).size() == 1);
00396       assert(!request->header(h_ProxyAuthorizations).front().exists(p_qop));
00397 
00398       const Auth& auth = request->header(h_ProxyAuthorizations).front();
00399       
00400       assert(auth.param(p_username) == "bob");
00401       assert(auth.param(p_uri) == "sip:bob@biloxi.com");
00402       assert(auth.param(p_algorithm) == "MD5");
00403 
00404       Helper::AuthResult res = Helper::authenticateRequest(*request, 
00405                                                            realm,
00406                                                            encodedPassword);
00407       assert(res == Helper::Authenticated);
00408 
00409       res = Helper::authenticateRequest(*request, 
00410                                         realm,
00411                                         encodedPassword,
00412                                         5);
00413 
00414       assert(res == Helper::Authenticated);
00415 
00416       sleep(2);
00417       res = Helper::authenticateRequest(*request, 
00418                                         realm,
00419                                         encodedPassword,
00420                                         1);
00421  
00422       assert(res == Helper::Expired);
00423       
00424    }
00425 
00426    {
00427       Data txt("INVITE sip:bob@biloxi.com SIP/2.0\r\n"
00428                "Via: SIP/2.0/UDP pc33.atlanta.com;branch=z9hG4bKnashds8\r\n"
00429                "To: Bob <sip:bob@biloxi.com>\r\n"
00430                "From: Alice <sip:alice@atlanta.com>;tag=1928301774\r\n"
00431                "Call-ID: a84b4c76e66710\r\n"
00432                "CSeq: 314159 INVITE\r\n"
00433                "Max-Forwards: 70\r\n"
00434                "Contact: <sip:alice@pc33.atlanta.com>\r\n"
00435                "Content-Type: application/sdp\r\n"
00436                "Content-Length: 150\r\n"
00437                "\r\n"
00438                "v=0\r\n"
00439                "o=alice 53655765 2353687637 IN IP4 pc33.atlanta.com\r\n"
00440                "s=-\r\n"
00441                "c=IN IP4 pc33.atlanta.com\r\n"
00442                "t=0 0\r\n"
00443                "m=audio 3456 RTP/AVP 0 1 3 99\r\n"
00444                "a=rtpmap:0 PCMU/8000\r\n");
00445 
00446       auto_ptr<SipMessage> request(TestSupport::makeMessage(txt.c_str()));      
00447 
00448       Data realm = "localhost";
00449       auto_ptr<SipMessage> challenge(Helper::makeProxyChallenge(*request, realm, true));
00450 
00451       cerr << *challenge << endl;
00452 
00453       assert(challenge->exists(h_ProxyAuthenticates));
00454       assert(challenge->header(h_ProxyAuthenticates).size() == 1);
00455       assert(challenge->header(h_ProxyAuthenticates).front().exists(p_qopOptions));
00456       assert(challenge->header(h_ProxyAuthenticates).front().param(p_algorithm) == "MD5");
00457       assert(challenge->header(h_ProxyAuthenticates).front().scheme() == "Digest");
00458 
00459       Data username = "bob";
00460       Data password = "secret";
00461       Data cnonce = "366fead6";
00462       unsigned int nc = 9;
00463       
00464       Data encodedPassword = password.md5();
00465 
00466       Helper::addAuthorization(*request,
00467                                *challenge,
00468                                username,
00469                                encodedPassword,
00470                                cnonce,
00471                                nc);
00472 
00473       assert(nc == 10);
00474 
00475       cerr << *request << endl;
00476 
00477       assert(request->exists(h_ProxyAuthorizations));
00478       assert(request->header(h_ProxyAuthorizations).size() == 1);
00479       assert(request->header(h_ProxyAuthorizations).front().exists(p_qop));
00480       assert(request->header(h_ProxyAuthorizations).front().param(p_nc) == "0000000a");
00481 
00482       const Auth& auth = request->header(h_ProxyAuthorizations).front();
00483       
00484       assert(auth.param(p_username) == "bob");
00485       assert(auth.param(p_uri) == "sip:bob@biloxi.com");
00486       assert(auth.param(p_algorithm) == "MD5");
00487 
00488       Helper::AuthResult res = Helper::authenticateRequest(*request, 
00489                                                            realm,
00490                                                            encodedPassword);
00491       assert(res == Helper::Authenticated);
00492 
00493       res = Helper::authenticateRequest(*request, 
00494                                         realm,
00495                                         encodedPassword,
00496                                         5);
00497 
00498       assert(res == Helper::Authenticated);
00499 
00500       sleep(2);
00501       res = Helper::authenticateRequest(*request, 
00502                                         realm,
00503                                         encodedPassword,
00504                                         1);
00505  
00506       assert(res == Helper::Expired);
00507       
00508    }
00509    cerr << "ALL OK" << endl;
00510    return 0;
00511 }
00512 /* ====================================================================
00513  * The Vovida Software License, Version 1.0 
00514  * 
00515  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00516  * 
00517  * Redistribution and use in source and binary forms, with or without
00518  * modification, are permitted provided that the following conditions
00519  * are met:
00520  * 
00521  * 1. Redistributions of source code must retain the above copyright
00522  *    notice, this list of conditions and the following disclaimer.
00523  * 
00524  * 2. Redistributions in binary form must reproduce the above copyright
00525  *    notice, this list of conditions and the following disclaimer in
00526  *    the documentation and/or other materials provided with the
00527  *    distribution.
00528  * 
00529  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00530  *    and "Vovida Open Communication Application Library (VOCAL)" must
00531  *    not be used to endorse or promote products derived from this
00532  *    software without prior written permission. For written
00533  *    permission, please contact vocal@vovida.org.
00534  *
00535  * 4. Products derived from this software may not be called "VOCAL", nor
00536  *    may "VOCAL" appear in their name, without prior written
00537  *    permission of Vovida Networks, Inc.
00538  * 
00539  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00540  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00541  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00542  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00543  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00544  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00545  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00546  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00547  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00548  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00549  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00550  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00551  * DAMAGE.
00552  * 
00553  * ====================================================================
00554  * 
00555  * This software consists of voluntary contributions made by Vovida
00556  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00557  * Inc.  For more information on Vovida Networks, Inc., please see
00558  * <http://www.vovida.org/>.
00559  *
00560  */