LCOV - code coverage report
Current view: top level - netwerk/protocol/http - nsHttpDigestAuth.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 332 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 17 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : // HttpLog.h should generally be included first
       8             : #include "HttpLog.h"
       9             : 
      10             : #include "mozilla/Sprintf.h"
      11             : #include "mozilla/Unused.h"
      12             : 
      13             : #include "nsHttp.h"
      14             : #include "nsHttpDigestAuth.h"
      15             : #include "nsIHttpAuthenticableChannel.h"
      16             : #include "nsISupportsPrimitives.h"
      17             : #include "nsIURI.h"
      18             : #include "nsString.h"
      19             : #include "nsEscape.h"
      20             : #include "nsNetCID.h"
      21             : #include "nsCRT.h"
      22             : #include "nsICryptoHash.h"
      23             : #include "nsComponentManagerUtils.h"
      24             : 
      25             : namespace mozilla {
      26             : namespace net {
      27             : 
      28             : //-----------------------------------------------------------------------------
      29             : // nsHttpDigestAuth <public>
      30             : //-----------------------------------------------------------------------------
      31             : 
      32           0 : nsHttpDigestAuth::nsHttpDigestAuth()
      33           0 : {}
      34             : 
      35           0 : nsHttpDigestAuth::~nsHttpDigestAuth()
      36           0 : {}
      37             : 
      38             : //-----------------------------------------------------------------------------
      39             : // nsHttpDigestAuth::nsISupports
      40             : //-----------------------------------------------------------------------------
      41             : 
      42           0 : NS_IMPL_ISUPPORTS(nsHttpDigestAuth, nsIHttpAuthenticator)
      43             : 
      44             : //-----------------------------------------------------------------------------
      45             : // nsHttpDigestAuth <protected>
      46             : //-----------------------------------------------------------------------------
      47             : 
      48             : nsresult
      49           0 : nsHttpDigestAuth::MD5Hash(const char *buf, uint32_t len)
      50             : {
      51             :   nsresult rv;
      52             : 
      53             :   // Cache a reference to the nsICryptoHash instance since we'll be calling
      54             :   // this function frequently.
      55           0 :   if (!mVerifier) {
      56           0 :     mVerifier = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
      57           0 :     if (NS_FAILED(rv)) {
      58           0 :       LOG(("nsHttpDigestAuth: no crypto hash!\n"));
      59           0 :       return rv;
      60             :     }
      61             :   }
      62             : 
      63           0 :   rv = mVerifier->Init(nsICryptoHash::MD5);
      64           0 :   if (NS_FAILED(rv)) return rv;
      65             : 
      66           0 :   rv = mVerifier->Update((unsigned char*)buf, len);
      67           0 :   if (NS_FAILED(rv)) return rv;
      68             : 
      69           0 :   nsAutoCString hashString;
      70           0 :   rv = mVerifier->Finish(false, hashString);
      71           0 :   if (NS_FAILED(rv)) return rv;
      72             : 
      73           0 :   NS_ENSURE_STATE(hashString.Length() == sizeof(mHashBuf));
      74           0 :   memcpy(mHashBuf, hashString.get(), hashString.Length());
      75             : 
      76           0 :   return rv;
      77             : }
      78             : 
      79             : nsresult
      80           0 : nsHttpDigestAuth::GetMethodAndPath(nsIHttpAuthenticableChannel *authChannel,
      81             :                                    bool                         isProxyAuth,
      82             :                                    nsCString                   &httpMethod,
      83             :                                    nsCString                   &path)
      84             : {
      85             :   nsresult rv, rv2;
      86           0 :   nsCOMPtr<nsIURI> uri;
      87           0 :   rv = authChannel->GetURI(getter_AddRefs(uri));
      88           0 :   if (NS_SUCCEEDED(rv)) {
      89             :     bool proxyMethodIsConnect;
      90           0 :     rv = authChannel->GetProxyMethodIsConnect(&proxyMethodIsConnect);
      91           0 :     if (NS_SUCCEEDED(rv)) {
      92           0 :       if (proxyMethodIsConnect && isProxyAuth) {
      93           0 :         httpMethod.AssignLiteral("CONNECT");
      94             :         //
      95             :         // generate hostname:port string. (unfortunately uri->GetHostPort
      96             :         // leaves out the port if it matches the default value, so we can't
      97             :         // just call it.)
      98             :         //
      99             :         int32_t port;
     100           0 :         rv = uri->GetAsciiHost(path);
     101           0 :         rv2 = uri->GetPort(&port);
     102           0 :         if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2)) {
     103           0 :           path.Append(':');
     104           0 :           path.AppendInt(port < 0 ? NS_HTTPS_DEFAULT_PORT : port);
     105           0 :         }
     106             :       }
     107             :       else {
     108           0 :         rv = authChannel->GetRequestMethod(httpMethod);
     109           0 :         rv2 = uri->GetPath(path);
     110           0 :         if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(rv2)) {
     111             :           //
     112             :           // strip any fragment identifier from the URL path.
     113             :           //
     114           0 :           int32_t ref = path.RFindChar('#');
     115           0 :           if (ref != kNotFound)
     116           0 :             path.Truncate(ref);
     117             :           //
     118             :           // make sure we escape any UTF-8 characters in the URI path.  the
     119             :           // digest auth uri attribute needs to match the request-URI.
     120             :           //
     121             :           // XXX we should really ask the HTTP channel for this string
     122             :           // instead of regenerating it here.
     123             :           //
     124           0 :           nsAutoCString buf;
     125           0 :           rv = NS_EscapeURL(path, esc_OnlyNonASCII, buf, mozilla::fallible);
     126           0 :           if (NS_SUCCEEDED(rv)) {
     127           0 :             path = buf;
     128             :           }
     129             :         }
     130             :       }
     131             :     }
     132             :   }
     133           0 :   return rv;
     134             : }
     135             : 
     136             : //-----------------------------------------------------------------------------
     137             : // nsHttpDigestAuth::nsIHttpAuthenticator
     138             : //-----------------------------------------------------------------------------
     139             : 
     140             : NS_IMETHODIMP
     141           0 : nsHttpDigestAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel,
     142             :                                     const char *challenge,
     143             :                                     bool isProxyAuth,
     144             :                                     nsISupports **sessionState,
     145             :                                     nsISupports **continuationState,
     146             :                                     bool *result)
     147             : {
     148           0 :   nsAutoCString realm, domain, nonce, opaque;
     149             :   bool stale;
     150             :   uint16_t algorithm, qop;
     151             : 
     152             :   nsresult rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
     153           0 :                                &stale, &algorithm, &qop);
     154           0 :   if (NS_FAILED(rv)) return rv;
     155             : 
     156             :   // if the challenge has the "stale" flag set, then the user identity is not
     157             :   // necessarily invalid.  by returning FALSE here we can suppress username
     158             :   // and password prompting that usually accompanies a 401/407 challenge.
     159           0 :   *result = !stale;
     160             : 
     161             :   // clear any existing nonce_count since we have a new challenge.
     162           0 :   NS_IF_RELEASE(*sessionState);
     163           0 :   return NS_OK;
     164             : }
     165             : 
     166             : 
     167             : NS_IMETHODIMP
     168           0 : nsHttpDigestAuth::GenerateCredentialsAsync(nsIHttpAuthenticableChannel *authChannel,
     169             :                                            nsIHttpAuthenticatorCallback* aCallback,
     170             :                                            const char *challenge,
     171             :                                            bool isProxyAuth,
     172             :                                            const char16_t *domain,
     173             :                                            const char16_t *username,
     174             :                                            const char16_t *password,
     175             :                                            nsISupports *sessionState,
     176             :                                            nsISupports *continuationState,
     177             :                                            nsICancelable **aCancellable)
     178             : {
     179           0 :   return NS_ERROR_NOT_IMPLEMENTED;
     180             : }
     181             : 
     182             : NS_IMETHODIMP
     183           0 : nsHttpDigestAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
     184             :                                       const char *challenge,
     185             :                                       bool isProxyAuth,
     186             :                                       const char16_t *userdomain,
     187             :                                       const char16_t *username,
     188             :                                       const char16_t *password,
     189             :                                       nsISupports **sessionState,
     190             :                                       nsISupports **continuationState,
     191             :                                       uint32_t *aFlags,
     192             :                                       char **creds)
     193             : 
     194             : {
     195           0 :   LOG(("nsHttpDigestAuth::GenerateCredentials [challenge=%s]\n", challenge));
     196             : 
     197           0 :   NS_ENSURE_ARG_POINTER(creds);
     198             : 
     199           0 :   *aFlags = 0;
     200             : 
     201           0 :   bool isDigestAuth = !PL_strncasecmp(challenge, "digest ", 7);
     202           0 :   NS_ENSURE_TRUE(isDigestAuth, NS_ERROR_UNEXPECTED);
     203             : 
     204             :   // IIS implementation requires extra quotes
     205           0 :   bool requireExtraQuotes = false;
     206             :   {
     207           0 :     nsAutoCString serverVal;
     208           0 :     Unused << authChannel->GetServerResponseHeader(serverVal);
     209           0 :     if (!serverVal.IsEmpty()) {
     210           0 :       requireExtraQuotes = !PL_strncasecmp(serverVal.get(), "Microsoft-IIS", 13);
     211             :     }
     212             :   }
     213             : 
     214             :   nsresult rv;
     215           0 :   nsAutoCString httpMethod;
     216           0 :   nsAutoCString path;
     217           0 :   rv = GetMethodAndPath(authChannel, isProxyAuth, httpMethod, path);
     218           0 :   if (NS_FAILED(rv)) return rv;
     219             : 
     220           0 :   nsAutoCString realm, domain, nonce, opaque;
     221             :   bool stale;
     222             :   uint16_t algorithm, qop;
     223             : 
     224             :   rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
     225           0 :                       &stale, &algorithm, &qop);
     226           0 :   if (NS_FAILED(rv)) {
     227           0 :     LOG(("nsHttpDigestAuth::GenerateCredentials [ParseChallenge failed rv=%" PRIx32 "]\n",
     228             :          static_cast<uint32_t>(rv)));
     229           0 :     return rv;
     230             :   }
     231             : 
     232             :   char ha1_digest[EXPANDED_DIGEST_LENGTH+1];
     233             :   char ha2_digest[EXPANDED_DIGEST_LENGTH+1];
     234             :   char response_digest[EXPANDED_DIGEST_LENGTH+1];
     235             :   char upload_data_digest[EXPANDED_DIGEST_LENGTH+1];
     236             : 
     237           0 :   if (qop & QOP_AUTH_INT) {
     238             :     // we do not support auth-int "quality of protection" currently
     239           0 :     qop &= ~QOP_AUTH_INT;
     240             : 
     241           0 :     NS_WARNING("no support for Digest authentication with data integrity quality of protection");
     242             : 
     243             :     /* TODO: to support auth-int, we need to get an MD5 digest of
     244             :      * TODO: the data uploaded with this request.
     245             :      * TODO: however, i am not sure how to read in the file in without
     246             :      * TODO: disturbing the channel''s use of it. do i need to copy it
     247             :      * TODO: somehow?
     248             :      */
     249             : #if 0
     250             :     if (http_channel != nullptr)
     251             :     {
     252             :       nsIInputStream * upload;
     253             :       nsCOMPtr<nsIUploadChannel> uc = do_QueryInterface(http_channel);
     254             :       NS_ENSURE_TRUE(uc, NS_ERROR_UNEXPECTED);
     255             :       uc->GetUploadStream(&upload);
     256             :       if (upload) {
     257             :         char * upload_buffer;
     258             :         int upload_buffer_length = 0;
     259             :         //TODO: read input stream into buffer
     260             :         const char * digest = (const char*)
     261             :         nsNetwerkMD5Digest(upload_buffer, upload_buffer_length);
     262             :         ExpandToHex(digest, upload_data_digest);
     263             :         NS_RELEASE(upload);
     264             :       }
     265             :     }
     266             : #endif
     267             :   }
     268             : 
     269           0 :   if (!(algorithm & ALGO_MD5 || algorithm & ALGO_MD5_SESS)) {
     270             :     // they asked only for algorithms that we do not support
     271           0 :     NS_WARNING("unsupported algorithm requested by Digest authentication");
     272           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     273             :   }
     274             : 
     275             :   //
     276             :   // the following are for increasing security.  see RFC 2617 for more
     277             :   // information.
     278             :   //
     279             :   // nonce_count allows the server to keep track of auth challenges (to help
     280             :   // prevent spoofing). we increase this count every time.
     281             :   //
     282           0 :   char nonce_count[NONCE_COUNT_LENGTH+1] = "00000001"; // in hex
     283           0 :   if (*sessionState) {
     284           0 :     nsCOMPtr<nsISupportsPRUint32> v(do_QueryInterface(*sessionState));
     285           0 :     if (v) {
     286             :       uint32_t nc;
     287           0 :       v->GetData(&nc);
     288           0 :       SprintfLiteral(nonce_count, "%08x", ++nc);
     289           0 :       v->SetData(nc);
     290             :     }
     291             :   }
     292             :   else {
     293             :     nsCOMPtr<nsISupportsPRUint32> v(
     294           0 :             do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID));
     295           0 :     if (v) {
     296           0 :       v->SetData(1);
     297           0 :       v.forget(sessionState);
     298             :     }
     299             :   }
     300           0 :   LOG(("   nonce_count=%s\n", nonce_count));
     301             : 
     302             :   //
     303             :   // this lets the client verify the server response (via a server
     304             :   // returned Authentication-Info header). also used for session info.
     305             :   //
     306           0 :   nsAutoCString cnonce;
     307             :   static const char hexChar[] = "0123456789abcdef";
     308           0 :   for (int i=0; i<16; ++i) {
     309           0 :     cnonce.Append(hexChar[(int)(15.0 * rand()/(RAND_MAX + 1.0))]);
     310             :   }
     311           0 :   LOG(("   cnonce=%s\n", cnonce.get()));
     312             : 
     313             :   //
     314             :   // calculate credentials
     315             :   //
     316             : 
     317           0 :   NS_ConvertUTF16toUTF8 cUser(username), cPass(password);
     318           0 :   rv = CalculateHA1(cUser, cPass, realm, algorithm, nonce, cnonce, ha1_digest);
     319           0 :   if (NS_FAILED(rv)) return rv;
     320             : 
     321           0 :   rv = CalculateHA2(httpMethod, path, qop, upload_data_digest, ha2_digest);
     322           0 :   if (NS_FAILED(rv)) return rv;
     323             : 
     324           0 :   rv = CalculateResponse(ha1_digest, ha2_digest, nonce, qop, nonce_count,
     325           0 :                          cnonce, response_digest);
     326           0 :   if (NS_FAILED(rv)) return rv;
     327             : 
     328             :   //
     329             :   // Values that need to match the quoted-string production from RFC 2616:
     330             :   //
     331             :   //    username
     332             :   //    realm
     333             :   //    nonce
     334             :   //    opaque
     335             :   //    cnonce
     336             :   //
     337             : 
     338           0 :   nsAutoCString authString;
     339             : 
     340           0 :   authString.AssignLiteral("Digest username=");
     341           0 :   rv = AppendQuotedString(cUser, authString);
     342           0 :   NS_ENSURE_SUCCESS(rv, rv);
     343             : 
     344           0 :   authString.AppendLiteral(", realm=");
     345           0 :   rv = AppendQuotedString(realm, authString);
     346           0 :   NS_ENSURE_SUCCESS(rv, rv);
     347             : 
     348           0 :   authString.AppendLiteral(", nonce=");
     349           0 :   rv = AppendQuotedString(nonce, authString);
     350           0 :   NS_ENSURE_SUCCESS(rv, rv);
     351             : 
     352           0 :   authString.AppendLiteral(", uri=\"");
     353           0 :   authString += path;
     354           0 :   if (algorithm & ALGO_SPECIFIED) {
     355           0 :     authString.AppendLiteral("\", algorithm=");
     356           0 :     if (algorithm & ALGO_MD5_SESS)
     357           0 :       authString.AppendLiteral("MD5-sess");
     358             :     else
     359           0 :       authString.AppendLiteral("MD5");
     360             :   } else {
     361           0 :     authString += '\"';
     362             :   }
     363           0 :   authString.AppendLiteral(", response=\"");
     364           0 :   authString += response_digest;
     365           0 :   authString += '\"';
     366             : 
     367           0 :   if (!opaque.IsEmpty()) {
     368           0 :     authString.AppendLiteral(", opaque=");
     369           0 :     rv = AppendQuotedString(opaque, authString);
     370           0 :     NS_ENSURE_SUCCESS(rv, rv);
     371             :   }
     372             : 
     373           0 :   if (qop) {
     374           0 :     authString.AppendLiteral(", qop=");
     375           0 :     if (requireExtraQuotes)
     376           0 :       authString += '\"';
     377           0 :     authString.AppendLiteral("auth");
     378           0 :     if (qop & QOP_AUTH_INT)
     379           0 :       authString.AppendLiteral("-int");
     380           0 :     if (requireExtraQuotes)
     381           0 :       authString += '\"';
     382           0 :     authString.AppendLiteral(", nc=");
     383           0 :     authString += nonce_count;
     384             : 
     385           0 :     authString.AppendLiteral(", cnonce=");
     386           0 :     rv = AppendQuotedString(cnonce, authString);
     387           0 :     NS_ENSURE_SUCCESS(rv, rv);
     388             :   }
     389             : 
     390             : 
     391           0 :   *creds = ToNewCString(authString);
     392           0 :   return NS_OK;
     393             : }
     394             : 
     395             : NS_IMETHODIMP
     396           0 : nsHttpDigestAuth::GetAuthFlags(uint32_t *flags)
     397             : {
     398           0 :   *flags = REQUEST_BASED | REUSABLE_CHALLENGE | IDENTITY_ENCRYPTED;
     399             :   //
     400             :   // NOTE: digest auth credentials must be uniquely computed for each request,
     401             :   //       so we do not set the REUSABLE_CREDENTIALS flag.
     402             :   //
     403           0 :   return NS_OK;
     404             : }
     405             : 
     406             : nsresult
     407           0 : nsHttpDigestAuth::CalculateResponse(const char * ha1_digest,
     408             :                                     const char * ha2_digest,
     409             :                                     const nsCString& nonce,
     410             :                                     uint16_t qop,
     411             :                                     const char * nonce_count,
     412             :                                     const nsCString& cnonce,
     413             :                                     char * result)
     414             : {
     415           0 :   uint32_t len = 2*EXPANDED_DIGEST_LENGTH + nonce.Length() + 2;
     416             : 
     417           0 :   if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
     418           0 :     len += cnonce.Length() + NONCE_COUNT_LENGTH + 3;
     419           0 :     if (qop & QOP_AUTH_INT)
     420           0 :       len += 8; // length of "auth-int"
     421             :     else
     422           0 :       len += 4; // length of "auth"
     423             :   }
     424             : 
     425           0 :   nsAutoCString contents;
     426           0 :   contents.SetCapacity(len);
     427             : 
     428           0 :   contents.Assign(ha1_digest, EXPANDED_DIGEST_LENGTH);
     429           0 :   contents.Append(':');
     430           0 :   contents.Append(nonce);
     431           0 :   contents.Append(':');
     432             : 
     433           0 :   if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
     434           0 :     contents.Append(nonce_count, NONCE_COUNT_LENGTH);
     435           0 :     contents.Append(':');
     436           0 :     contents.Append(cnonce);
     437           0 :     contents.Append(':');
     438           0 :     if (qop & QOP_AUTH_INT)
     439           0 :       contents.AppendLiteral("auth-int:");
     440             :     else
     441           0 :       contents.AppendLiteral("auth:");
     442             :   }
     443             : 
     444           0 :   contents.Append(ha2_digest, EXPANDED_DIGEST_LENGTH);
     445             : 
     446           0 :   nsresult rv = MD5Hash(contents.get(), contents.Length());
     447           0 :   if (NS_SUCCEEDED(rv))
     448           0 :     rv = ExpandToHex(mHashBuf, result);
     449           0 :   return rv;
     450             : }
     451             : 
     452             : nsresult
     453           0 : nsHttpDigestAuth::ExpandToHex(const char * digest, char * result)
     454             : {
     455             :   int16_t index, value;
     456             : 
     457           0 :   for (index = 0; index < DIGEST_LENGTH; index++) {
     458           0 :     value = (digest[index] >> 4) & 0xf;
     459           0 :     if (value < 10)
     460           0 :       result[index*2] = value + '0';
     461             :     else
     462           0 :       result[index*2] = value - 10 + 'a';
     463             : 
     464           0 :     value = digest[index] & 0xf;
     465           0 :     if (value < 10)
     466           0 :       result[(index*2)+1] = value + '0';
     467             :     else
     468           0 :       result[(index*2)+1] = value - 10 + 'a';
     469             :   }
     470             : 
     471           0 :   result[EXPANDED_DIGEST_LENGTH] = 0;
     472           0 :   return NS_OK;
     473             : }
     474             : 
     475             : nsresult
     476           0 : nsHttpDigestAuth::CalculateHA1(const nsCString& username,
     477             :                                const nsCString& password,
     478             :                                const nsCString& realm,
     479             :                                uint16_t algorithm,
     480             :                                const nsCString& nonce,
     481             :                                const nsCString& cnonce,
     482             :                                char * result)
     483             : {
     484           0 :   int16_t len = username.Length() + password.Length() + realm.Length() + 2;
     485           0 :   if (algorithm & ALGO_MD5_SESS) {
     486           0 :     int16_t exlen = EXPANDED_DIGEST_LENGTH + nonce.Length() + cnonce.Length() + 2;
     487           0 :     if (exlen > len)
     488           0 :         len = exlen;
     489             :   }
     490             : 
     491           0 :   nsAutoCString contents;
     492           0 :   contents.SetCapacity(len + 1);
     493             : 
     494           0 :   contents.Assign(username);
     495           0 :   contents.Append(':');
     496           0 :   contents.Append(realm);
     497           0 :   contents.Append(':');
     498           0 :   contents.Append(password);
     499             : 
     500             :   nsresult rv;
     501           0 :   rv = MD5Hash(contents.get(), contents.Length());
     502           0 :   if (NS_FAILED(rv))
     503           0 :     return rv;
     504             : 
     505           0 :   if (algorithm & ALGO_MD5_SESS) {
     506             :     char part1[EXPANDED_DIGEST_LENGTH+1];
     507           0 :     rv = ExpandToHex(mHashBuf, part1);
     508           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
     509             : 
     510           0 :     contents.Assign(part1, EXPANDED_DIGEST_LENGTH);
     511           0 :     contents.Append(':');
     512           0 :     contents.Append(nonce);
     513           0 :     contents.Append(':');
     514           0 :     contents.Append(cnonce);
     515             : 
     516           0 :     rv = MD5Hash(contents.get(), contents.Length());
     517           0 :     if (NS_FAILED(rv))
     518           0 :       return rv;
     519             :   }
     520             : 
     521           0 :   return ExpandToHex(mHashBuf, result);
     522             : }
     523             : 
     524             : nsresult
     525           0 : nsHttpDigestAuth::CalculateHA2(const nsCString& method,
     526             :                                const nsCString& path,
     527             :                                uint16_t qop,
     528             :                                const char * bodyDigest,
     529             :                                char * result)
     530             : {
     531           0 :   uint16_t methodLen = method.Length();
     532           0 :   uint32_t pathLen = path.Length();
     533           0 :   uint32_t len = methodLen + pathLen + 1;
     534             : 
     535           0 :   if (qop & QOP_AUTH_INT) {
     536           0 :     len += EXPANDED_DIGEST_LENGTH + 1;
     537             :   }
     538             : 
     539           0 :   nsAutoCString contents;
     540           0 :   contents.SetCapacity(len);
     541             : 
     542           0 :   contents.Assign(method);
     543           0 :   contents.Append(':');
     544           0 :   contents.Append(path);
     545             : 
     546           0 :   if (qop & QOP_AUTH_INT) {
     547           0 :     contents.Append(':');
     548           0 :     contents.Append(bodyDigest, EXPANDED_DIGEST_LENGTH);
     549             :   }
     550             : 
     551           0 :   nsresult rv = MD5Hash(contents.get(), contents.Length());
     552           0 :   if (NS_SUCCEEDED(rv))
     553           0 :     rv = ExpandToHex(mHashBuf, result);
     554           0 :   return rv;
     555             : }
     556             : 
     557             : nsresult
     558           0 : nsHttpDigestAuth::ParseChallenge(const char * challenge,
     559             :                                  nsACString & realm,
     560             :                                  nsACString & domain,
     561             :                                  nsACString & nonce,
     562             :                                  nsACString & opaque,
     563             :                                  bool * stale,
     564             :                                  uint16_t * algorithm,
     565             :                                  uint16_t * qop)
     566             : {
     567             :   // put an absurd, but maximum, length cap on the challenge so
     568             :   // that calculations are 32 bit safe
     569           0 :   if (strlen(challenge) > 16000000) {
     570           0 :     return NS_ERROR_INVALID_ARG;
     571             :   }
     572             : 
     573           0 :   const char *p = challenge + 6; // first 6 characters are "Digest"
     574             : 
     575           0 :   *stale = false;
     576           0 :   *algorithm = ALGO_MD5; // default is MD5
     577           0 :   *qop = 0;
     578             : 
     579             :   for (;;) {
     580           0 :     while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p)))
     581           0 :       ++p;
     582           0 :     if (!*p)
     583           0 :       break;
     584             : 
     585             :     // name
     586           0 :     int32_t nameStart = (p - challenge);
     587           0 :     while (*p && !nsCRT::IsAsciiSpace(*p) && *p != '=')
     588           0 :       ++p;
     589           0 :     if (!*p)
     590           0 :       return NS_ERROR_INVALID_ARG;
     591           0 :     int32_t nameLength = (p - challenge) - nameStart;
     592             : 
     593           0 :     while (*p && (nsCRT::IsAsciiSpace(*p) || *p == '='))
     594           0 :       ++p;
     595           0 :     if (!*p)
     596           0 :       return NS_ERROR_INVALID_ARG;
     597             : 
     598           0 :     bool quoted = false;
     599           0 :     if (*p == '"') {
     600           0 :       ++p;
     601           0 :       quoted = true;
     602             :     }
     603             : 
     604             :     // value
     605           0 :     int32_t valueStart = (p - challenge);
     606           0 :     int32_t valueLength = 0;
     607           0 :     if (quoted) {
     608           0 :       while (*p && *p != '"')
     609           0 :         ++p;
     610           0 :       if (*p != '"')
     611           0 :         return NS_ERROR_INVALID_ARG;
     612           0 :       valueLength = (p - challenge) - valueStart;
     613           0 :       ++p;
     614             :     } else {
     615           0 :       while (*p && !nsCRT::IsAsciiSpace(*p) && *p != ',')
     616           0 :         ++p;
     617           0 :       valueLength = (p - challenge) - valueStart;
     618             :     }
     619             : 
     620             :     // extract information
     621           0 :     if (nameLength == 5 &&
     622           0 :         nsCRT::strncasecmp(challenge+nameStart, "realm", 5) == 0)
     623             :     {
     624           0 :       realm.Assign(challenge+valueStart, valueLength);
     625             :     }
     626           0 :     else if (nameLength == 6 &&
     627           0 :         nsCRT::strncasecmp(challenge+nameStart, "domain", 6) == 0)
     628             :     {
     629           0 :       domain.Assign(challenge+valueStart, valueLength);
     630             :     }
     631           0 :     else if (nameLength == 5 &&
     632           0 :         nsCRT::strncasecmp(challenge+nameStart, "nonce", 5) == 0)
     633             :     {
     634           0 :       nonce.Assign(challenge+valueStart, valueLength);
     635             :     }
     636           0 :     else if (nameLength == 6 &&
     637           0 :         nsCRT::strncasecmp(challenge+nameStart, "opaque", 6) == 0)
     638             :     {
     639           0 :       opaque.Assign(challenge+valueStart, valueLength);
     640             :     }
     641           0 :     else if (nameLength == 5 &&
     642           0 :         nsCRT::strncasecmp(challenge+nameStart, "stale", 5) == 0)
     643             :     {
     644           0 :       if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0)
     645           0 :         *stale = true;
     646             :       else
     647           0 :         *stale = false;
     648             :     }
     649           0 :     else if (nameLength == 9 &&
     650           0 :         nsCRT::strncasecmp(challenge+nameStart, "algorithm", 9) == 0)
     651             :     {
     652             :       // we want to clear the default, so we use = not |= here
     653           0 :       *algorithm = ALGO_SPECIFIED;
     654           0 :       if (valueLength == 3 &&
     655           0 :           nsCRT::strncasecmp(challenge+valueStart, "MD5", 3) == 0)
     656           0 :         *algorithm |= ALGO_MD5;
     657           0 :       else if (valueLength == 8 &&
     658           0 :           nsCRT::strncasecmp(challenge+valueStart, "MD5-sess", 8) == 0)
     659           0 :         *algorithm |= ALGO_MD5_SESS;
     660             :     }
     661           0 :     else if (nameLength == 3 &&
     662           0 :         nsCRT::strncasecmp(challenge+nameStart, "qop", 3) == 0)
     663             :     {
     664           0 :       int32_t ipos = valueStart;
     665           0 :       while (ipos < valueStart+valueLength) {
     666           0 :         while (ipos < valueStart+valueLength &&
     667           0 :                (nsCRT::IsAsciiSpace(challenge[ipos]) ||
     668           0 :                 challenge[ipos] == ','))
     669           0 :           ipos++;
     670           0 :         int32_t algostart = ipos;
     671           0 :         while (ipos < valueStart+valueLength &&
     672           0 :                !nsCRT::IsAsciiSpace(challenge[ipos]) &&
     673           0 :                challenge[ipos] != ',')
     674           0 :           ipos++;
     675           0 :         if ((ipos - algostart) == 4 &&
     676           0 :             nsCRT::strncasecmp(challenge+algostart, "auth", 4) == 0)
     677           0 :           *qop |= QOP_AUTH;
     678           0 :         else if ((ipos - algostart) == 8 &&
     679           0 :             nsCRT::strncasecmp(challenge+algostart, "auth-int", 8) == 0)
     680           0 :           *qop |= QOP_AUTH_INT;
     681             :       }
     682             :     }
     683           0 :   }
     684           0 :   return NS_OK;
     685             : }
     686             : 
     687             : nsresult
     688           0 : nsHttpDigestAuth::AppendQuotedString(const nsACString & value,
     689             :                                      nsACString & aHeaderLine)
     690             : {
     691           0 :   nsAutoCString quoted;
     692           0 :   nsACString::const_iterator s, e;
     693           0 :   value.BeginReading(s);
     694           0 :   value.EndReading(e);
     695             : 
     696             :   //
     697             :   // Encode string according to RFC 2616 quoted-string production
     698             :   //
     699           0 :   quoted.Append('"');
     700           0 :   for ( ; s != e; ++s) {
     701             :     //
     702             :     // CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
     703             :     //
     704           0 :     if (*s <= 31 || *s == 127) {
     705           0 :       return NS_ERROR_FAILURE;
     706             :     }
     707             : 
     708             :     // Escape two syntactically significant characters
     709           0 :     if (*s == '"' || *s == '\\') {
     710           0 :       quoted.Append('\\');
     711             :     }
     712             : 
     713           0 :     quoted.Append(*s);
     714             :   }
     715             :   // FIXME: bug 41489
     716             :   // We should RFC2047-encode non-Latin-1 values according to spec
     717           0 :   quoted.Append('"');
     718           0 :   aHeaderLine.Append(quoted);
     719           0 :   return NS_OK;
     720             : }
     721             : 
     722             : } // namespace net
     723             : } // namespace mozilla
     724             : 
     725             : // vim: ts=2 sw=2

Generated by: LCOV version 1.13