|
---|
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 |