netwerk/protocol/http/nsHttpDigestAuth.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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

mercurial