Attachment #8848140: patch for digest for bug #41489

View | Details | Raw Unified | Return to bug 41489
Collapse All | Expand All

(-)a/netwerk/protocol/http/nsHttpDigestAuth.cpp (-43 / +151 lines)
Line     Link Here 
 Lines 40-80   nsHttpDigestAuth::~nsHttpDigestAuth() Link Here 
40
40
41
NS_IMPL_ISUPPORTS(nsHttpDigestAuth, nsIHttpAuthenticator)
41
NS_IMPL_ISUPPORTS(nsHttpDigestAuth, nsIHttpAuthenticator)
42
42
43
//-----------------------------------------------------------------------------
43
//-----------------------------------------------------------------------------
44
// nsHttpDigestAuth <protected>
44
// nsHttpDigestAuth <protected>
45
//-----------------------------------------------------------------------------
45
//-----------------------------------------------------------------------------
46
46
47
nsresult
47
nsresult
48
nsHttpDigestAuth::MD5Hash(const char *buf, uint32_t len)
48
nsHttpDigestAuth::DoHash(const char *buf, uint32_t len, uint16_t algorithm)
49
{
49
{
50
  nsresult rv;
50
  nsresult rv;
51
51
52
  // Cache a reference to the nsICryptoHash instance since we'll be calling
52
  // Cache a reference to the nsICryptoHash instance since we'll be calling
53
  // this function frequently.
53
  // this function frequently.
54
  if (!mVerifier) {
54
  if (!mVerifier) {
55
    mVerifier = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
55
    mVerifier = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
56
    if (NS_FAILED(rv)) {
56
    if (NS_FAILED(rv)) {
57
      LOG(("nsHttpDigestAuth: no crypto hash!\n"));
57
      LOG(("nsHttpDigestAuth: no crypto hash!\n"));
58
      return rv;
58
      return rv;
59
    }
59
    }
60
  }
60
  }
61
61
62
  rv = mVerifier->Init(nsICryptoHash::MD5);
62
  if (algorithm & (ALGO_SHA256 | ALGO_SHA256_SESS)) {
63
    rv = mVerifier->Init(nsICryptoHash::SHA256);
64
  } else if (algorithm & (ALGO_MD5 | ALGO_MD5_SESS)) {
65
    rv = mVerifier->Init(nsICryptoHash::MD5);
66
  } else {
67
    NS_ERROR("Algorithm not set");
68
    rv = NS_ERROR_UNEXPECTED;
69
  }
63
  if (NS_FAILED(rv)) return rv;
70
  if (NS_FAILED(rv)) return rv;
64
71
65
  rv = mVerifier->Update((unsigned char*)buf, len);
72
  rv = mVerifier->Update((unsigned char*)buf, len);
66
  if (NS_FAILED(rv)) return rv;
73
  if (NS_FAILED(rv)) return rv;
67
74
68
  nsAutoCString hashString;
75
  nsAutoCString hashString;
69
  rv = mVerifier->Finish(false, hashString);
76
  rv = mVerifier->Finish(false, hashString);
70
  if (NS_FAILED(rv)) return rv;
77
  if (NS_FAILED(rv)) return rv;
71
78
72
  NS_ENSURE_STATE(hashString.Length() == sizeof(mHashBuf));
79
  NS_ENSURE_STATE(hashString.Length() <= sizeof(mHashBuf));
73
  memcpy(mHashBuf, hashString.get(), hashString.Length());
80
  memcpy(mHashBuf, hashString.get(), hashString.Length());
74
81
75
  return rv;
82
  return rv;
76
}
83
}
77
84
78
nsresult
85
nsresult
79
nsHttpDigestAuth::GetMethodAndPath(nsIHttpAuthenticableChannel *authChannel,
86
nsHttpDigestAuth::GetMethodAndPath(nsIHttpAuthenticableChannel *authChannel,
80
                                   bool                         isProxyAuth,
87
                                   bool                         isProxyAuth,
 Lines 141-160   nsHttpDigestAuth::ChallengeReceived(nsIH Link Here 
141
                                    const char *challenge,
148
                                    const char *challenge,
142
                                    bool isProxyAuth,
149
                                    bool isProxyAuth,
143
                                    nsISupports **sessionState,
150
                                    nsISupports **sessionState,
144
                                    nsISupports **continuationState,
151
                                    nsISupports **continuationState,
145
                                    bool *result)
152
                                    bool *result)
146
{
153
{
147
  nsAutoCString realm, domain, nonce, opaque;
154
  nsAutoCString realm, domain, nonce, opaque;
148
  bool stale;
155
  bool stale;
149
  uint16_t algorithm, qop;
156
  uint16_t algorithm, qop, charset, userhash;
150
157
151
  nsresult rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
158
  nsresult rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
152
                               &stale, &algorithm, &qop);
159
                               &stale, &algorithm, &qop, &charset, &userhash);
153
  if (NS_FAILED(rv)) return rv;
160
  if (NS_FAILED(rv)) return rv;
154
161
155
  // if the challenge has the "stale" flag set, then the user identity is not
162
  // if the challenge has the "stale" flag set, then the user identity is not
156
  // necessarily invalid.  by returning FALSE here we can suppress username
163
  // necessarily invalid.  by returning FALSE here we can suppress username
157
  // and password prompting that usually accompanies a 401/407 challenge.
164
  // and password prompting that usually accompanies a 401/407 challenge.
158
  *result = !stale;
165
  *result = !stale;
159
166
160
  // clear any existing nonce_count since we have a new challenge.
167
  // clear any existing nonce_count since we have a new challenge.
 Lines 213-232   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
213
  nsresult rv;
220
  nsresult rv;
214
  nsAutoCString httpMethod;
221
  nsAutoCString httpMethod;
215
  nsAutoCString path;
222
  nsAutoCString path;
216
  rv = GetMethodAndPath(authChannel, isProxyAuth, httpMethod, path);
223
  rv = GetMethodAndPath(authChannel, isProxyAuth, httpMethod, path);
217
  if (NS_FAILED(rv)) return rv;
224
  if (NS_FAILED(rv)) return rv;
218
225
219
  nsAutoCString realm, domain, nonce, opaque;
226
  nsAutoCString realm, domain, nonce, opaque;
220
  bool stale;
227
  bool stale;
221
  uint16_t algorithm, qop;
228
  uint16_t algorithm, qop, charset, userhash;
222
229
223
  rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
230
  rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
224
                      &stale, &algorithm, &qop);
231
                      &stale, &algorithm, &qop, &charset, &userhash);
225
  if (NS_FAILED(rv)) {
232
  if (NS_FAILED(rv)) {
226
    LOG(("nsHttpDigestAuth::GenerateCredentials [ParseChallenge failed rv=%" PRIx32 "]\n",
233
    LOG(("nsHttpDigestAuth::GenerateCredentials [ParseChallenge failed rv=%" PRIx32 "]\n",
227
         static_cast<uint32_t>(rv)));
234
         static_cast<uint32_t>(rv)));
228
    return rv;
235
    return rv;
229
  }
236
  }
230
237
231
  char ha1_digest[EXPANDED_DIGEST_LENGTH+1];
238
  char ha1_digest[EXPANDED_DIGEST_LENGTH+1];
232
  char ha2_digest[EXPANDED_DIGEST_LENGTH+1];
239
  char ha2_digest[EXPANDED_DIGEST_LENGTH+1];
 Lines 260-276   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
260
        nsNetwerkMD5Digest(upload_buffer, upload_buffer_length);
267
        nsNetwerkMD5Digest(upload_buffer, upload_buffer_length);
261
        ExpandToHex(digest, upload_data_digest);
268
        ExpandToHex(digest, upload_data_digest);
262
        NS_RELEASE(upload);
269
        NS_RELEASE(upload);
263
      }
270
      }
264
    }
271
    }
265
#endif
272
#endif
266
  }
273
  }
267
274
268
  if (!(algorithm & ALGO_MD5 || algorithm & ALGO_MD5_SESS)) {
275
  if (!(algorithm & (ALGO_MD5 | ALGO_MD5_SESS | ALGO_SHA256 |
276
                     ALGO_SHA256_SESS))) {
269
    // they asked only for algorithms that we do not support
277
    // they asked only for algorithms that we do not support
270
    NS_WARNING("unsupported algorithm requested by Digest authentication");
278
    NS_WARNING("unsupported algorithm requested by Digest authentication");
271
    return NS_ERROR_NOT_IMPLEMENTED;
279
    return NS_ERROR_NOT_IMPLEMENTED;
272
  }
280
  }
273
281
274
  //
282
  //
275
  // the following are for increasing security.  see RFC 2617 for more
283
  // the following are for increasing security.  see RFC 2617 for more
276
  // information.
284
  // information.
 Lines 308-366   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
308
    cnonce.Append(hexChar[(int)(15.0 * rand()/(RAND_MAX + 1.0))]);
316
    cnonce.Append(hexChar[(int)(15.0 * rand()/(RAND_MAX + 1.0))]);
309
  }
317
  }
310
  LOG(("   cnonce=%s\n", cnonce.get()));
318
  LOG(("   cnonce=%s\n", cnonce.get()));
311
319
312
  //
320
  //
313
  // calculate credentials
321
  // calculate credentials
314
  //
322
  //
315
323
324
  if (charset & CHARSET_SPECIFIED && !(charset & CHARSET_UTF8)) {
325
    return NS_ERROR_UNEXPECTED;
326
  }
327
  rv = CheckControls(username);
328
  NS_ENSURE_SUCCESS(rv, rv);
329
316
  NS_ConvertUTF16toUTF8 cUser(username), cPass(password);
330
  NS_ConvertUTF16toUTF8 cUser(username), cPass(password);
317
  rv = CalculateHA1(cUser, cPass, realm, algorithm, nonce, cnonce, ha1_digest);
331
  rv = CalculateHA1(cUser, cPass, realm, algorithm, nonce, cnonce, ha1_digest);
318
  if (NS_FAILED(rv)) return rv;
332
  if (NS_FAILED(rv)) return rv;
319
333
320
  rv = CalculateHA2(httpMethod, path, qop, upload_data_digest, ha2_digest);
334
  rv = CalculateHA2(httpMethod, path, qop, algorithm, upload_data_digest,
335
                    ha2_digest);
321
  if (NS_FAILED(rv)) return rv;
336
  if (NS_FAILED(rv)) return rv;
322
337
323
  rv = CalculateResponse(ha1_digest, ha2_digest, nonce, qop, nonce_count,
338
  rv = CalculateResponse(ha1_digest, ha2_digest, nonce, qop, algorithm,
324
                         cnonce, response_digest);
339
                         nonce_count, cnonce, response_digest);
325
  if (NS_FAILED(rv)) return rv;
340
  if (NS_FAILED(rv)) return rv;
326
341
327
  //
342
  //
328
  // Values that need to match the quoted-string production from RFC 2616:
343
  // Values that need to match the quoted-string production from RFC 2616:
329
  //
344
  //
330
  //    username
345
  //    username
331
  //    realm
346
  //    realm
332
  //    nonce
347
  //    nonce
333
  //    opaque
348
  //    opaque
334
  //    cnonce
349
  //    cnonce
335
  //
350
  //
336
351
337
  nsAutoCString authString;
352
  nsAutoCString authString;
338
353
339
  authString.AssignLiteral("Digest username=");
354
  if (userhash == USERHASH_TRUE) {
340
  rv = AppendQuotedString(cUser, authString);
355
    char hashuser[EXPANDED_DIGEST_LENGTH+1];
341
  NS_ENSURE_SUCCESS(rv, rv);
356
    cUser.Append(':');
357
    cUser.Append(realm);
358
    rv = DoHash(cUser.get(), cUser.Length(), algorithm);
359
    NS_ENSURE_SUCCESS(rv, rv);
360
    rv = ExpandToHex(mHashBuf, algorithm, hashuser);
361
    NS_ENSURE_SUCCESS(rv, rv);
362
    authString.AssignLiteral("Digest username=\"");
363
    authString += hashuser;
364
    authString += '\"';
365
  } else if (charset & CHARSET_UTF8) {
366
    authString.AssignLiteral("Digest username*=UTF-8\'\'");
367
    nsAutoCString escUser;
368
    NS_Escape(cUser, escUser, url_XAlphas);
369
    authString.Append(escUser);
370
  } else {
371
    authString.AssignLiteral("Digest username=");
372
    rv = AppendQuotedString(cUser, authString);
373
    NS_ENSURE_SUCCESS(rv, rv);
374
  }
342
375
343
  authString.AppendLiteral(", realm=");
376
  authString.AppendLiteral(", realm=");
344
  rv = AppendQuotedString(realm, authString);
377
  rv = AppendQuotedString(realm, authString);
345
  NS_ENSURE_SUCCESS(rv, rv);
378
  NS_ENSURE_SUCCESS(rv, rv);
346
379
347
  authString.AppendLiteral(", nonce=");
380
  authString.AppendLiteral(", nonce=");
348
  rv = AppendQuotedString(nonce, authString);
381
  rv = AppendQuotedString(nonce, authString);
349
  NS_ENSURE_SUCCESS(rv, rv);
382
  NS_ENSURE_SUCCESS(rv, rv);
350
383
351
  authString.AppendLiteral(", uri=\"");
384
  authString.AppendLiteral(", uri=\"");
352
  authString += path;
385
  authString += path;
353
  if (algorithm & ALGO_SPECIFIED) {
386
  if (algorithm & ALGO_SPECIFIED) {
354
    authString.AppendLiteral("\", algorithm=");
387
    authString.AppendLiteral("\", algorithm=");
355
    if (algorithm & ALGO_MD5_SESS)
388
    if (algorithm & ALGO_SHA256_SESS) {
389
      authString.AppendLiteral("SHA-256-sess");
390
    } else if (algorithm & ALGO_SHA256) {
391
      authString.AppendLiteral("SHA-256");
392
    } else if (algorithm & ALGO_MD5_SESS) {
356
      authString.AppendLiteral("MD5-sess");
393
      authString.AppendLiteral("MD5-sess");
357
    else
394
    } else {
358
      authString.AppendLiteral("MD5");
395
      authString.AppendLiteral("MD5");
396
    }
359
  } else {
397
  } else {
360
    authString += '\"';
398
    authString += '\"';
361
  }
399
  }
362
  authString.AppendLiteral(", response=\"");
400
  authString.AppendLiteral(", response=\"");
363
  authString += response_digest;
401
  authString += response_digest;
364
  authString += '\"';
402
  authString += '\"';
365
403
366
  if (!opaque.IsEmpty()) {
404
  if (!opaque.IsEmpty()) {
 Lines 381-396   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
381
    authString.AppendLiteral(", nc=");
419
    authString.AppendLiteral(", nc=");
382
    authString += nonce_count;
420
    authString += nonce_count;
383
421
384
    authString.AppendLiteral(", cnonce=");
422
    authString.AppendLiteral(", cnonce=");
385
    rv = AppendQuotedString(cnonce, authString);
423
    rv = AppendQuotedString(cnonce, authString);
386
    NS_ENSURE_SUCCESS(rv, rv);
424
    NS_ENSURE_SUCCESS(rv, rv);
387
  }
425
  }
388
426
427
  if (userhash) {
428
    authString.AppendLiteral(", userhash=");
429
    if (userhash == USERHASH_TRUE) {
430
      authString.AppendLiteral("true");
431
    } else {
432
      authString.AppendLiteral("false");
433
    }
434
  }
389
435
390
  *creds = ToNewCString(authString);
436
  *creds = ToNewCString(authString);
391
  return NS_OK;
437
  return NS_OK;
392
}
438
}
393
439
394
NS_IMETHODIMP
440
NS_IMETHODIMP
395
nsHttpDigestAuth::GetAuthFlags(uint32_t *flags)
441
nsHttpDigestAuth::GetAuthFlags(uint32_t *flags)
396
{
442
{
 Lines 402-584   nsHttpDigestAuth::GetAuthFlags(uint32_t Link Here 
402
  return NS_OK;
448
  return NS_OK;
403
}
449
}
404
450
405
nsresult
451
nsresult
406
nsHttpDigestAuth::CalculateResponse(const char * ha1_digest,
452
nsHttpDigestAuth::CalculateResponse(const char * ha1_digest,
407
                                    const char * ha2_digest,
453
                                    const char * ha2_digest,
408
                                    const nsAFlatCString & nonce,
454
                                    const nsAFlatCString & nonce,
409
                                    uint16_t qop,
455
                                    uint16_t qop,
456
                                    uint16_t algorithm,
410
                                    const char * nonce_count,
457
                                    const char * nonce_count,
411
                                    const nsAFlatCString & cnonce,
458
                                    const nsAFlatCString & cnonce,
412
                                    char * result)
459
                                    char * result)
413
{
460
{
414
  uint32_t len = 2*EXPANDED_DIGEST_LENGTH + nonce.Length() + 2;
461
  uint32_t len = nonce.Length() + 2 + ExpandedDigestLength(algorithm) * 2;
415
462
416
  if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
463
  if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
417
    len += cnonce.Length() + NONCE_COUNT_LENGTH + 3;
464
    len += cnonce.Length() + NONCE_COUNT_LENGTH + 3;
418
    if (qop & QOP_AUTH_INT)
465
    if (qop & QOP_AUTH_INT)
419
      len += 8; // length of "auth-int"
466
      len += 8; // length of "auth-int"
420
    else
467
    else
421
      len += 4; // length of "auth"
468
      len += 4; // length of "auth"
422
  }
469
  }
423
470
424
  nsAutoCString contents;
471
  nsAutoCString contents;
425
  contents.SetCapacity(len);
472
  contents.SetCapacity(len);
426
473
427
  contents.Assign(ha1_digest, EXPANDED_DIGEST_LENGTH);
474
  contents.Assign(ha1_digest, ExpandedDigestLength(algorithm));
428
  contents.Append(':');
475
  contents.Append(':');
429
  contents.Append(nonce);
476
  contents.Append(nonce);
430
  contents.Append(':');
477
  contents.Append(':');
431
478
432
  if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
479
  if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
433
    contents.Append(nonce_count, NONCE_COUNT_LENGTH);
480
    contents.Append(nonce_count, NONCE_COUNT_LENGTH);
434
    contents.Append(':');
481
    contents.Append(':');
435
    contents.Append(cnonce);
482
    contents.Append(cnonce);
436
    contents.Append(':');
483
    contents.Append(':');
437
    if (qop & QOP_AUTH_INT)
484
    if (qop & QOP_AUTH_INT)
438
      contents.AppendLiteral("auth-int:");
485
      contents.AppendLiteral("auth-int:");
439
    else
486
    else
440
      contents.AppendLiteral("auth:");
487
      contents.AppendLiteral("auth:");
441
  }
488
  }
442
489
443
  contents.Append(ha2_digest, EXPANDED_DIGEST_LENGTH);
490
  contents.Append(ha2_digest, ExpandedDigestLength(algorithm));
444
491
445
  nsresult rv = MD5Hash(contents.get(), contents.Length());
492
  nsresult rv = DoHash(contents.get(), contents.Length(), algorithm);
446
  if (NS_SUCCEEDED(rv))
493
  if (NS_SUCCEEDED(rv))
447
    rv = ExpandToHex(mHashBuf, result);
494
    rv = ExpandToHex(mHashBuf, algorithm, result);
448
  return rv;
495
  return rv;
449
}
496
}
450
497
451
nsresult
498
nsresult
452
nsHttpDigestAuth::ExpandToHex(const char * digest, char * result)
499
nsHttpDigestAuth::ExpandToHex(const char * digest, int16_t algorithm, char * result)
453
{
500
{
454
  int16_t index, value;
501
  int16_t index, value, digestLen = DigestLength(algorithm);
455
502
456
  for (index = 0; index < DIGEST_LENGTH; index++) {
503
  for (index = 0; index < digestLen; index++) {
457
    value = (digest[index] >> 4) & 0xf;
504
    value = (digest[index] >> 4) & 0xf;
458
    if (value < 10)
505
    if (value < 10)
459
      result[index*2] = value + '0';
506
      result[index*2] = value + '0';
460
    else
507
    else
461
      result[index*2] = value - 10 + 'a';
508
      result[index*2] = value - 10 + 'a';
462
509
463
    value = digest[index] & 0xf;
510
    value = digest[index] & 0xf;
464
    if (value < 10)
511
    if (value < 10)
465
      result[(index*2)+1] = value + '0';
512
      result[(index*2)+1] = value + '0';
466
    else
513
    else
467
      result[(index*2)+1] = value - 10 + 'a';
514
      result[(index*2)+1] = value - 10 + 'a';
468
  }
515
  }
469
516
470
  result[EXPANDED_DIGEST_LENGTH] = 0;
517
  result[ExpandedDigestLength(algorithm)] = 0;
471
  return NS_OK;
518
  return NS_OK;
472
}
519
}
473
520
474
nsresult
521
nsresult
475
nsHttpDigestAuth::CalculateHA1(const nsAFlatCString & username,
522
nsHttpDigestAuth::CalculateHA1(const nsAFlatCString & username,
476
                               const nsAFlatCString & password,
523
                               const nsAFlatCString & password,
477
                               const nsAFlatCString & realm,
524
                               const nsAFlatCString & realm,
478
                               uint16_t algorithm,
525
                               uint16_t algorithm,
479
                               const nsAFlatCString & nonce,
526
                               const nsAFlatCString & nonce,
480
                               const nsAFlatCString & cnonce,
527
                               const nsAFlatCString & cnonce,
481
                               char * result)
528
                               char * result)
482
{
529
{
483
  int16_t len = username.Length() + password.Length() + realm.Length() + 2;
530
  int16_t len = username.Length() + password.Length() + realm.Length() + 2;
484
  if (algorithm & ALGO_MD5_SESS) {
531
  if (algorithm & (ALGO_MD5_SESS | ALGO_SHA256_SESS)) {
485
    int16_t exlen = EXPANDED_DIGEST_LENGTH + nonce.Length() + cnonce.Length() + 2;
532
    int16_t exlen = ExpandedDigestLength(algorithm) + nonce.Length() +
533
                    cnonce.Length() + 2;
486
    if (exlen > len)
534
    if (exlen > len)
487
        len = exlen;
535
        len = exlen;
488
  }
536
  }
489
537
490
  nsAutoCString contents;
538
  nsAutoCString contents;
491
  contents.SetCapacity(len + 1);
539
  contents.SetCapacity(len + 1);
492
540
493
  contents.Assign(username);
541
  contents.Assign(username);
494
  contents.Append(':');
542
  contents.Append(':');
495
  contents.Append(realm);
543
  contents.Append(realm);
496
  contents.Append(':');
544
  contents.Append(':');
497
  contents.Append(password);
545
  contents.Append(password);
498
546
499
  nsresult rv;
547
  nsresult rv;
500
  rv = MD5Hash(contents.get(), contents.Length());
548
  rv = DoHash(contents.get(), contents.Length(), algorithm);
501
  if (NS_FAILED(rv))
549
  if (NS_FAILED(rv))
502
    return rv;
550
    return rv;
503
551
504
  if (algorithm & ALGO_MD5_SESS) {
552
  if (algorithm & (ALGO_MD5_SESS | ALGO_SHA256_SESS)) {
505
    char part1[EXPANDED_DIGEST_LENGTH+1];
553
    char part1[EXPANDED_DIGEST_LENGTH+1];
506
    rv = ExpandToHex(mHashBuf, part1);
554
    rv = ExpandToHex(mHashBuf, algorithm, part1);
507
    MOZ_ASSERT(NS_SUCCEEDED(rv));
555
    MOZ_ASSERT(NS_SUCCEEDED(rv));
508
556
509
    contents.Assign(part1, EXPANDED_DIGEST_LENGTH);
557
    contents.Assign(part1, ExpandedDigestLength(algorithm));
510
    contents.Append(':');
558
    contents.Append(':');
511
    contents.Append(nonce);
559
    contents.Append(nonce);
512
    contents.Append(':');
560
    contents.Append(':');
513
    contents.Append(cnonce);
561
    contents.Append(cnonce);
514
562
515
    rv = MD5Hash(contents.get(), contents.Length());
563
    rv = DoHash(contents.get(), contents.Length(), algorithm);
516
    if (NS_FAILED(rv))
564
    if (NS_FAILED(rv))
517
      return rv;
565
      return rv;
518
  }
566
  }
519
567
520
  return ExpandToHex(mHashBuf, result);
568
  return ExpandToHex(mHashBuf, algorithm, result);
521
}
569
}
522
570
523
nsresult
571
nsresult
524
nsHttpDigestAuth::CalculateHA2(const nsAFlatCString & method,
572
nsHttpDigestAuth::CalculateHA2(const nsAFlatCString & method,
525
                               const nsAFlatCString & path,
573
                               const nsAFlatCString & path,
526
                               uint16_t qop,
574
                               uint16_t qop,
575
                               uint16_t algorithm,
527
                               const char * bodyDigest,
576
                               const char * bodyDigest,
528
                               char * result)
577
                               char * result)
529
{
578
{
530
  uint16_t methodLen = method.Length();
579
  uint16_t methodLen = method.Length();
531
  uint32_t pathLen = path.Length();
580
  uint32_t pathLen = path.Length();
532
  uint32_t len = methodLen + pathLen + 1;
581
  uint32_t len = methodLen + pathLen + 1;
533
582
534
  if (qop & QOP_AUTH_INT) {
583
  if (qop & QOP_AUTH_INT) {
535
    len += EXPANDED_DIGEST_LENGTH + 1;
584
    len += ExpandedDigestLength(algorithm) + 1;
536
  }
585
  }
537
586
538
  nsAutoCString contents;
587
  nsAutoCString contents;
539
  contents.SetCapacity(len);
588
  contents.SetCapacity(len);
540
589
541
  contents.Assign(method);
590
  contents.Assign(method);
542
  contents.Append(':');
591
  contents.Append(':');
543
  contents.Append(path);
592
  contents.Append(path);
544
593
545
  if (qop & QOP_AUTH_INT) {
594
  if (qop & QOP_AUTH_INT) {
546
    contents.Append(':');
595
    contents.Append(':');
547
    contents.Append(bodyDigest, EXPANDED_DIGEST_LENGTH);
596
    contents.Append(bodyDigest, ExpandedDigestLength(algorithm));
548
  }
597
  }
549
598
550
  nsresult rv = MD5Hash(contents.get(), contents.Length());
599
  nsresult rv = DoHash(contents.get(), contents.Length(), algorithm);
551
  if (NS_SUCCEEDED(rv))
600
  if (NS_SUCCEEDED(rv))
552
    rv = ExpandToHex(mHashBuf, result);
601
    rv = ExpandToHex(mHashBuf, algorithm, result);
553
  return rv;
602
  return rv;
554
}
603
}
555
604
556
nsresult
605
nsresult
557
nsHttpDigestAuth::ParseChallenge(const char * challenge,
606
nsHttpDigestAuth::ParseChallenge(const char * challenge,
558
                                 nsACString & realm,
607
                                 nsACString & realm,
559
                                 nsACString & domain,
608
                                 nsACString & domain,
560
                                 nsACString & nonce,
609
                                 nsACString & nonce,
561
                                 nsACString & opaque,
610
                                 nsACString & opaque,
562
                                 bool * stale,
611
                                 bool * stale,
563
                                 uint16_t * algorithm,
612
                                 uint16_t * algorithm,
564
                                 uint16_t * qop)
613
                                 uint16_t * qop,
614
                                 uint16_t * charset,
615
                                 uint16_t * userhash)
565
{
616
{
566
  // put an absurd, but maximum, length cap on the challenge so
617
  // put an absurd, but maximum, length cap on the challenge so
567
  // that calculations are 32 bit safe
618
  // that calculations are 32 bit safe
568
  if (strlen(challenge) > 16000000) {
619
  if (strlen(challenge) > 16000000) {
569
    return NS_ERROR_INVALID_ARG;
620
    return NS_ERROR_INVALID_ARG;
570
  }
621
  }
571
622
572
  const char *p = challenge + 6; // first 6 characters are "Digest"
623
  const char *p = challenge + 6; // first 6 characters are "Digest"
573
624
574
  *stale = false;
625
  *stale = false;
575
  *algorithm = ALGO_MD5; // default is MD5
626
  *algorithm = ALGO_MD5; // default is MD5
576
  *qop = 0;
627
  *qop = 0;
628
  *charset = CHARSET_NOT_SET;
629
  *userhash = USERHASH_NOT_SET;
577
630
578
  for (;;) {
631
  for (;;) {
579
    while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p)))
632
    while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p)))
580
      ++p;
633
      ++p;
581
    if (!*p)
634
    if (!*p)
582
      break;
635
      break;
583
636
584
    // name
637
    // name
 Lines 632-666   nsHttpDigestAuth::ParseChallenge(const c Link Here 
632
    {
685
    {
633
      nonce.Assign(challenge+valueStart, valueLength);
686
      nonce.Assign(challenge+valueStart, valueLength);
634
    }
687
    }
635
    else if (nameLength == 6 &&
688
    else if (nameLength == 6 &&
636
        nsCRT::strncasecmp(challenge+nameStart, "opaque", 6) == 0)
689
        nsCRT::strncasecmp(challenge+nameStart, "opaque", 6) == 0)
637
    {
690
    {
638
      opaque.Assign(challenge+valueStart, valueLength);
691
      opaque.Assign(challenge+valueStart, valueLength);
639
    }
692
    }
693
    else if (nameLength == 7 &&
694
              nsCRT::strncasecmp(challenge+nameStart, "charset", 7) == 0)
695
    {
696
      *charset = CHARSET_SPECIFIED;
697
      // UTF-8 or no
698
      if (nsCRT::strncasecmp(challenge+valueStart, "UTF-8", 5) == 0) {
699
        *charset |= CHARSET_UTF8;
700
      }
701
    }
702
    else if (nameLength == 8 &&
703
             nsCRT::strncasecmp(challenge+nameStart, "userhash", 8) == 0)
704
    {
705
      if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0) {
706
        *userhash = USERHASH_TRUE;
707
      } else {
708
        *userhash = USERHASH_FALSE;
709
      }
710
    }
640
    else if (nameLength == 5 &&
711
    else if (nameLength == 5 &&
641
        nsCRT::strncasecmp(challenge+nameStart, "stale", 5) == 0)
712
        nsCRT::strncasecmp(challenge+nameStart, "stale", 5) == 0)
642
    {
713
    {
643
      if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0)
714
      if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0)
644
        *stale = true;
715
        *stale = true;
645
      else
716
      else
646
        *stale = false;
717
        *stale = false;
647
    }
718
    }
648
    else if (nameLength == 9 &&
719
    else if (nameLength == 9 &&
649
        nsCRT::strncasecmp(challenge+nameStart, "algorithm", 9) == 0)
720
        nsCRT::strncasecmp(challenge+nameStart, "algorithm", 9) == 0)
650
    {
721
    {
651
      // we want to clear the default, so we use = not |= here
722
      // we want to clear the default, so we use = not |= here
652
      *algorithm = ALGO_SPECIFIED;
723
      *algorithm = ALGO_SPECIFIED;
653
      if (valueLength == 3 &&
724
      if (valueLength == 3 &&
654
          nsCRT::strncasecmp(challenge+valueStart, "MD5", 3) == 0)
725
          nsCRT::strncasecmp(challenge+valueStart, "MD5", 3) == 0) {
655
        *algorithm |= ALGO_MD5;
726
        *algorithm |= ALGO_MD5;
656
      else if (valueLength == 8 &&
727
      } else if (valueLength == 8 &&
657
          nsCRT::strncasecmp(challenge+valueStart, "MD5-sess", 8) == 0)
728
          nsCRT::strncasecmp(challenge+valueStart, "MD5-sess", 8) == 0) {
658
        *algorithm |= ALGO_MD5_SESS;
729
        *algorithm |= ALGO_MD5_SESS;
730
      } else if (valueLength == 7 &&
731
          nsCRT::strncasecmp(challenge+valueStart, "SHA-256", 7) == 0) {
732
        *algorithm |= ALGO_SHA256;
733
      } else if (valueLength == 12 &&
734
          nsCRT::strncasecmp(challenge+valueStart, "SHA-256-sess", 12) == 0) {
735
        *algorithm |= ALGO_SHA256_SESS;
736
      }
659
    }
737
    }
660
    else if (nameLength == 3 &&
738
    else if (nameLength == 3 &&
661
        nsCRT::strncasecmp(challenge+nameStart, "qop", 3) == 0)
739
        nsCRT::strncasecmp(challenge+nameStart, "qop", 3) == 0)
662
    {
740
    {
663
      int32_t ipos = valueStart;
741
      int32_t ipos = valueStart;
664
      while (ipos < valueStart+valueLength) {
742
      while (ipos < valueStart+valueLength) {
665
        while (ipos < valueStart+valueLength &&
743
        while (ipos < valueStart+valueLength &&
666
               (nsCRT::IsAsciiSpace(challenge[ipos]) ||
744
               (nsCRT::IsAsciiSpace(challenge[ipos]) ||
 Lines 706-724   nsHttpDigestAuth::AppendQuotedString(con Link Here 
706
784
707
    // Escape two syntactically significant characters
785
    // Escape two syntactically significant characters
708
    if (*s == '"' || *s == '\\') {
786
    if (*s == '"' || *s == '\\') {
709
      quoted.Append('\\');
787
      quoted.Append('\\');
710
    }
788
    }
711
789
712
    quoted.Append(*s);
790
    quoted.Append(*s);
713
  }
791
  }
714
  // FIXME: bug 41489
715
  // We should RFC2047-encode non-Latin-1 values according to spec
716
  quoted.Append('"');
792
  quoted.Append('"');
717
  aHeaderLine.Append(quoted);
793
  aHeaderLine.Append(quoted);
718
  return NS_OK;
794
  return NS_OK;
719
}
795
}
720
796
797
int16_t
798
nsHttpDigestAuth::DigestLength(int16_t algorithm)
799
{
800
  MOZ_ASSERT(algorithm >= ALGO_SPECIFIED && algorithm <= ALGO_SHA256_SESS + 1);
801
  int16_t len;
802
  if (algorithm & (ALGO_SHA256 | ALGO_SHA256_SESS)) {
803
    len = DIGEST_SHA256_LENGTH;
804
  } else {
805
    len = DIGEST_MD5_LENGTH;
806
  }
807
  return len;
808
}
809
810
int16_t
811
nsHttpDigestAuth::ExpandedDigestLength(int16_t algorithm)
812
{
813
  return DigestLength(algorithm) * 2;
814
}
815
816
nsresult
817
nsHttpDigestAuth::CheckControls(const char16_t *username)
818
{
819
  const char16_t *p = username;
820
  while(*p) {
821
    if (*p < 9 || (*p > 9 && *p <= 31) || *p == 127) {
822
      return NS_ERROR_FAILURE;
823
    }
824
    ++p;
825
  }
826
  return NS_OK;
827
}
828
721
} // namespace net
829
} // namespace net
722
} // namespace mozilla
830
} // namespace mozilla
723
831
724
// vim: ts=2 sw=2
832
// vim: ts=2 sw=2
(-)a/netwerk/protocol/http/nsHttpDigestAuth.h (-6 / +27 lines)
Line     Link Here 
 Lines 14-95    Link Here 
14
14
15
class nsICryptoHash;
15
class nsICryptoHash;
16
16
17
namespace mozilla { namespace net {
17
namespace mozilla { namespace net {
18
18
19
#define ALGO_SPECIFIED 0x01
19
#define ALGO_SPECIFIED 0x01
20
#define ALGO_MD5 0x02
20
#define ALGO_MD5 0x02
21
#define ALGO_MD5_SESS 0x04
21
#define ALGO_MD5_SESS 0x04
22
#define ALGO_SHA256 0x08
23
#define ALGO_SHA256_SESS 0x10
22
#define QOP_AUTH 0x01
24
#define QOP_AUTH 0x01
23
#define QOP_AUTH_INT 0x02
25
#define QOP_AUTH_INT 0x02
24
26
25
#define DIGEST_LENGTH 16
27
#define DIGEST_MD5_LENGTH 16
26
#define EXPANDED_DIGEST_LENGTH 32
28
#define DIGEST_SHA256_LENGTH 32
29
#define EXPANDED_DIGEST_LENGTH 64
27
#define NONCE_COUNT_LENGTH 8
30
#define NONCE_COUNT_LENGTH 8
31
#define USERHASH_NOT_SET 0x00
32
#define USERHASH_FALSE 0x01
33
#define USERHASH_TRUE 0x02
34
#define CHARSET_NOT_SET 0x00
35
#define CHARSET_SPECIFIED 0x01
36
#define CHARSET_UTF8 0x02
28
37
29
//-----------------------------------------------------------------------------
38
//-----------------------------------------------------------------------------
30
// nsHttpDigestAuth
39
// nsHttpDigestAuth
31
//-----------------------------------------------------------------------------
40
//-----------------------------------------------------------------------------
32
41
33
class nsHttpDigestAuth final : public nsIHttpAuthenticator
42
class nsHttpDigestAuth final : public nsIHttpAuthenticator
34
{
43
{
35
  public:
44
  public:
36
    NS_DECL_ISUPPORTS
45
    NS_DECL_ISUPPORTS
37
    NS_DECL_NSIHTTPAUTHENTICATOR
46
    NS_DECL_NSIHTTPAUTHENTICATOR
38
47
39
    nsHttpDigestAuth();
48
    nsHttpDigestAuth();
40
49
41
  protected:
50
  protected:
42
    ~nsHttpDigestAuth();
51
    ~nsHttpDigestAuth();
43
52
44
    MOZ_MUST_USE nsresult ExpandToHex(const char * digest, char * result);
53
    MOZ_MUST_USE nsresult ExpandToHex(const char * digest,
54
                                      int16_t algorithm,
55
                                      char * result);
45
56
46
    MOZ_MUST_USE nsresult CalculateResponse(const char * ha1_digest,
57
    MOZ_MUST_USE nsresult CalculateResponse(const char * ha1_digest,
47
                                            const char * ha2_digest,
58
                                            const char * ha2_digest,
48
                                            const nsAFlatCString & nonce,
59
                                            const nsAFlatCString & nonce,
49
                                            uint16_t qop,
60
                                            uint16_t qop,
61
                                            uint16_t algorithm,
50
                                            const char * nonce_count,
62
                                            const char * nonce_count,
51
                                            const nsAFlatCString & cnonce,
63
                                            const nsAFlatCString & cnonce,
52
                                            char * result);
64
                                            char * result);
53
65
54
    MOZ_MUST_USE nsresult CalculateHA1(const nsAFlatCString & username,
66
    MOZ_MUST_USE nsresult CalculateHA1(const nsAFlatCString & username,
55
                                       const nsAFlatCString & password,
67
                                       const nsAFlatCString & password,
56
                                       const nsAFlatCString & realm,
68
                                       const nsAFlatCString & realm,
57
                                       uint16_t algorithm,
69
                                       uint16_t algorithm,
58
                                       const nsAFlatCString & nonce,
70
                                       const nsAFlatCString & nonce,
59
                                       const nsAFlatCString & cnonce,
71
                                       const nsAFlatCString & cnonce,
60
                                       char * result);
72
                                       char * result);
61
73
62
    MOZ_MUST_USE nsresult CalculateHA2(const nsAFlatCString & http_method,
74
    MOZ_MUST_USE nsresult CalculateHA2(const nsAFlatCString & http_method,
63
                                       const nsAFlatCString & http_uri_path,
75
                                       const nsAFlatCString & http_uri_path,
64
                                       uint16_t qop,
76
                                       uint16_t qop,
77
                                       uint16_t algorithm,
65
                                       const char * body_digest,
78
                                       const char * body_digest,
66
                                       char * result);
79
                                       char * result);
67
80
68
    MOZ_MUST_USE nsresult ParseChallenge(const char * challenge,
81
    MOZ_MUST_USE nsresult ParseChallenge(const char * challenge,
69
                                         nsACString & realm,
82
                                         nsACString & realm,
70
                                         nsACString & domain,
83
                                         nsACString & domain,
71
                                         nsACString & nonce,
84
                                         nsACString & nonce,
72
                                         nsACString & opaque,
85
                                         nsACString & opaque,
73
                                         bool * stale,
86
                                         bool * stale,
74
                                         uint16_t * algorithm,
87
                                         uint16_t * algorithm,
75
                                         uint16_t * qop);
88
                                         uint16_t * qop,
89
                                         uint16_t * charset,
90
                                         uint16_t * userhash);
76
91
77
    // result is in mHashBuf
92
    // result is in mHashBuf
78
    MOZ_MUST_USE nsresult MD5Hash(const char *buf, uint32_t len);
93
    MOZ_MUST_USE nsresult DoHash(const char *buf,
94
                                 uint32_t len,
95
                                 uint16_t algorithm);
79
96
80
    MOZ_MUST_USE nsresult GetMethodAndPath(nsIHttpAuthenticableChannel *,
97
    MOZ_MUST_USE nsresult GetMethodAndPath(nsIHttpAuthenticableChannel *,
81
                                           bool, nsCString &, nsCString &);
98
                                           bool, nsCString &, nsCString &);
82
99
83
    // append the quoted version of value to aHeaderLine
100
    // append the quoted version of value to aHeaderLine
84
    MOZ_MUST_USE nsresult AppendQuotedString(const nsACString & value,
101
    MOZ_MUST_USE nsresult AppendQuotedString(const nsACString & value,
85
                                             nsACString & aHeaderLine);
102
                                             nsACString & aHeaderLine);
86
103
104
    MOZ_MUST_USE nsresult CheckControls(const char16_t *username);
105
    int16_t DigestLength(int16_t algorithm);
106
    int16_t ExpandedDigestLength(int16_t algorithm);
107
87
  protected:
108
  protected:
88
    nsCOMPtr<nsICryptoHash>        mVerifier;
109
    nsCOMPtr<nsICryptoHash>        mVerifier;
89
    char                           mHashBuf[DIGEST_LENGTH];
110
    char                           mHashBuf[DIGEST_SHA256_LENGTH];
90
};
111
};
91
112
92
} // namespace net
113
} // namespace net
93
} // namespace mozilla
114
} // namespace mozilla
94
115
95
#endif // nsHttpDigestAuth_h__
116
#endif // nsHttpDigestAuth_h__

Return to bug 41489