Attachment #8589323: to do here as draft-ietf-httpauth-digest-15 (refreshed as it should be) for bug #41489

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

(-)a/netwerk/protocol/http/nsHttpBasicAuth.cpp (-6 / +29 lines)
Line     Link Here 
 Lines 67-89   nsHttpBasicAuth::GenerateCredentials(nsI Link Here 
67
    NS_ENSURE_ARG_POINTER(creds);
67
    NS_ENSURE_ARG_POINTER(creds);
68
68
69
    *aFlags = 0;
69
    *aFlags = 0;
70
70
71
    // we only know how to deal with Basic auth for http.
71
    // we only know how to deal with Basic auth for http.
72
    bool isBasicAuth = !PL_strncasecmp(challenge, "basic", 5);
72
    bool isBasicAuth = !PL_strncasecmp(challenge, "basic", 5);
73
    NS_ENSURE_TRUE(isBasicAuth, NS_ERROR_UNEXPECTED);
73
    NS_ENSURE_TRUE(isBasicAuth, NS_ERROR_UNEXPECTED);
74
74
75
    // we work with ASCII around here
76
    nsAutoCString userpass;
75
    nsAutoCString userpass;
77
    LossyCopyUTF16toASCII(user, userpass);
76
    nsAutoCString charset;
78
    userpass.Append(':'); // always send a ':' (see bug 129565)
77
    if(strstr(challenge,"charset=")){
79
    if (password)
78
	const char *p = strstr(challenge,"charset=") + 8;
80
        LossyAppendUTF16toASCII(password, userpass);
79
	if(*p == '"'){
81
80
		p++;
81
    	}
82
	int32_t len = 0;
83
	for(;;p++){
84
		if(*p == '"' || *p == ',' || *p == 0){
85
       		break;
86
      		}
87
      		len++;
88
	}
89
	charset.Assign(p - len,len);
90
    }
91
    if(charset.EqualsLiteral("UTF-8")){
92
	//maybe it should do by default?
93
	CopyUTF16toUTF8(user, userpass);
94
	userpass.Append(':');
95
	if (password)
96
		AppendUTF16toUTF8(password, userpass);
97
    }
98
    else{
99
	//actually it is ISO-8859-1
100
	LossyCopyUTF16toASCII(user, userpass);
101
       userpass.Append(':');
102
	if (password)
103
		LossyAppendUTF16toASCII(password, userpass);
104
	}
82
    // plbase64.h provides this worst-case output buffer size calculation.
105
    // plbase64.h provides this worst-case output buffer size calculation.
83
    // use calloc, since PL_Base64Encode does not null terminate.
106
    // use calloc, since PL_Base64Encode does not null terminate.
84
    *creds = (char *) calloc(6 + ((userpass.Length() + 2)/3)*4 + 1, 1);
107
    *creds = (char *) calloc(6 + ((userpass.Length() + 2)/3)*4 + 1, 1);
85
    if (!*creds)
108
    if (!*creds)
86
        return NS_ERROR_OUT_OF_MEMORY;
109
        return NS_ERROR_OUT_OF_MEMORY;
87
110
88
    memcpy(*creds, "Basic ", 6);
111
    memcpy(*creds, "Basic ", 6);
89
    PL_Base64Encode(userpass.get(), userpass.Length(), *creds + 6);
112
    PL_Base64Encode(userpass.get(), userpass.Length(), *creds + 6);
(-)a/netwerk/protocol/http/nsHttpDigestAuth.cpp (-96 / +205 lines)
Line     Link Here 
 Lines 38-80   nsHttpDigestAuth::~nsHttpDigestAuth() Link Here 
38
38
39
NS_IMPL_ISUPPORTS(nsHttpDigestAuth, nsIHttpAuthenticator)
39
NS_IMPL_ISUPPORTS(nsHttpDigestAuth, nsIHttpAuthenticator)
40
40
41
//-----------------------------------------------------------------------------
41
//-----------------------------------------------------------------------------
42
// nsHttpDigestAuth <protected>
42
// nsHttpDigestAuth <protected>
43
//-----------------------------------------------------------------------------
43
//-----------------------------------------------------------------------------
44
44
45
nsresult
45
nsresult
46
nsHttpDigestAuth::MD5Hash(const char *buf, uint32_t len)
46
nsHttpDigestAuth::aHash(const char *buf, uint32_t len, uint16_t algorithm)
47
{
47
{
48
  nsresult rv;
48
  nsresult rv;
49
49
50
  // Cache a reference to the nsICryptoHash instance since we'll be calling
50
  // Cache a reference to the nsICryptoHash instance since we'll be calling
51
  // this function frequently.
51
  // this function frequently.
52
  if (!mVerifier) {
52
  if (!mVerifier) {
53
    mVerifier = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
53
    mVerifier = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
54
    if (NS_FAILED(rv)) {
54
    if (NS_FAILED(rv)) {
55
      LOG(("nsHttpDigestAuth: no crypto hash!\n"));
55
      LOG(("nsHttpDigestAuth: no crypto hash!\n"));
56
      return rv;
56
      return rv;
57
    }
57
    }
58
  }
58
  }
59
59
  if(algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS){
60
  rv = mVerifier->Init(nsICryptoHash::MD5);
60
	  rv = mVerifier->Init(nsICryptoHash::SHA256);
61
  }
62
  else{
63
	  rv = mVerifier->Init(nsICryptoHash::MD5);
64
  }
61
  if (NS_FAILED(rv)) return rv;
65
  if (NS_FAILED(rv)) return rv;
62
63
  rv = mVerifier->Update((unsigned char*)buf, len);
66
  rv = mVerifier->Update((unsigned char*)buf, len);
64
  if (NS_FAILED(rv)) return rv;
67
  if (NS_FAILED(rv)) return rv;
65
66
  nsAutoCString hashString;
68
  nsAutoCString hashString;
67
  rv = mVerifier->Finish(false, hashString);
69
  rv = mVerifier->Finish(false, hashString);
68
  if (NS_FAILED(rv)) return rv;
70
  if (NS_FAILED(rv)) return rv;
69
70
  NS_ENSURE_STATE(hashString.Length() == sizeof(mHashBuf));
71
  memcpy(mHashBuf, hashString.get(), hashString.Length());
71
  memcpy(mHashBuf, hashString.get(), hashString.Length());
72
73
  return rv;
72
  return rv;
74
}
73
}
75
74
76
nsresult
75
nsresult
77
nsHttpDigestAuth::GetMethodAndPath(nsIHttpAuthenticableChannel *authChannel,
76
nsHttpDigestAuth::GetMethodAndPath(nsIHttpAuthenticableChannel *authChannel,
78
                                   bool                         isProxyAuth,
77
                                   bool                         isProxyAuth,
79
                                   nsCString                   &httpMethod,
78
                                   nsCString                   &httpMethod,
80
                                   nsCString                   &path)
79
                                   nsCString                   &path)
 Lines 134-155   nsHttpDigestAuth::GetMethodAndPath(nsIHt Link Here 
134
NS_IMETHODIMP
133
NS_IMETHODIMP
135
nsHttpDigestAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel,
134
nsHttpDigestAuth::ChallengeReceived(nsIHttpAuthenticableChannel *authChannel,
136
                                    const char *challenge,
135
                                    const char *challenge,
137
                                    bool isProxyAuth,
136
                                    bool isProxyAuth,
138
                                    nsISupports **sessionState,
137
                                    nsISupports **sessionState,
139
                                    nsISupports **continuationState,
138
                                    nsISupports **continuationState,
140
                                    bool *result)
139
                                    bool *result)
141
{
140
{
142
  nsAutoCString realm, domain, nonce, opaque;
141
  nsAutoCString realm, domain, nonce, opaque, charset;
143
  bool stale;
142
  bool stale;
144
  uint16_t algorithm, qop;
143
  uint16_t algorithm, qop, userhash;
145
144
146
  nsresult rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
145
  nsresult rv = ParseChallenge(challenge, realm, domain, nonce, opaque, charset,
147
                               &stale, &algorithm, &qop);
146
                               &stale, &algorithm, &qop, &userhash);
148
  if (NS_FAILED(rv)) return rv;
147
  if (NS_FAILED(rv)) return rv;
149
148
150
  // if the challenge has the "stale" flag set, then the user identity is not
149
  // 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
150
  // necessarily invalid.  by returning FALSE here we can suppress username
152
  // and password prompting that usually accompanies a 401/407 challenge.
151
  // and password prompting that usually accompanies a 401/407 challenge.
153
  *result = !stale;
152
  *result = !stale;
154
153
155
  // clear any existing nonce_count since we have a new challenge.
154
  // clear any existing nonce_count since we have a new challenge.
 Lines 190-220   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
190
  }
189
  }
191
190
192
  nsresult rv;
191
  nsresult rv;
193
  nsAutoCString httpMethod;
192
  nsAutoCString httpMethod;
194
  nsAutoCString path;
193
  nsAutoCString path;
195
  rv = GetMethodAndPath(authChannel, isProxyAuth, httpMethod, path);
194
  rv = GetMethodAndPath(authChannel, isProxyAuth, httpMethod, path);
196
  if (NS_FAILED(rv)) return rv;
195
  if (NS_FAILED(rv)) return rv;
197
196
198
  nsAutoCString realm, domain, nonce, opaque;
197
  nsAutoCString realm, domain, nonce, opaque, charset;
199
  bool stale;
198
  bool stale;
200
  uint16_t algorithm, qop;
199
  uint16_t algorithm, qop, userhash;
201
200
202
  rv = ParseChallenge(challenge, realm, domain, nonce, opaque,
201
  rv = ParseChallenge(challenge, realm, domain, nonce, opaque, charset,
203
                      &stale, &algorithm, &qop);
202
                      &stale, &algorithm, &qop, &userhash);
204
  if (NS_FAILED(rv)) {
203
  if (NS_FAILED(rv)) {
205
    LOG(("nsHttpDigestAuth::GenerateCredentials [ParseChallenge failed rv=%x]\n", rv));
204
    LOG(("nsHttpDigestAuth::GenerateCredentials [ParseChallenge failed rv=%x]\n", rv));
206
    return rv;
205
    return rv;
207
  }
206
  }
208
207
  char ha1_digest[EXPANDED_DIGEST_SHA256_LENGTH+1];
209
  char ha1_digest[EXPANDED_DIGEST_LENGTH+1];
208
  char ha2_digest[EXPANDED_DIGEST_SHA256_LENGTH+1];
210
  char ha2_digest[EXPANDED_DIGEST_LENGTH+1];
209
  char response_digest[EXPANDED_DIGEST_SHA256_LENGTH+1];
211
  char response_digest[EXPANDED_DIGEST_LENGTH+1];
210
  char upload_data_digest[EXPANDED_DIGEST_SHA256_LENGTH+1];
212
  char upload_data_digest[EXPANDED_DIGEST_LENGTH+1];
213
211
214
  if (qop & QOP_AUTH_INT) {
212
  if (qop & QOP_AUTH_INT) {
215
    // we do not support auth-int "quality of protection" currently
213
    // we do not support auth-int "quality of protection" currently
216
    qop &= ~QOP_AUTH_INT;
214
    qop &= ~QOP_AUTH_INT;
217
215
218
    NS_WARNING("no support for Digest authentication with data integrity quality of protection");
216
    NS_WARNING("no support for Digest authentication with data integrity quality of protection");
219
217
220
    /* TODO: to support auth-int, we need to get an MD5 digest of
218
    /* TODO: to support auth-int, we need to get an MD5 digest of
 Lines 231-254   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
231
      NS_ENSURE_TRUE(uc, NS_ERROR_UNEXPECTED);
229
      NS_ENSURE_TRUE(uc, NS_ERROR_UNEXPECTED);
232
      uc->GetUploadStream(&upload);
230
      uc->GetUploadStream(&upload);
233
      if (upload) {
231
      if (upload) {
234
        char * upload_buffer;
232
        char * upload_buffer;
235
        int upload_buffer_length = 0;
233
        int upload_buffer_length = 0;
236
        //TODO: read input stream into buffer
234
        //TODO: read input stream into buffer
237
        const char * digest = (const char*)
235
        const char * digest = (const char*)
238
        nsNetwerkMD5Digest(upload_buffer, upload_buffer_length);
236
        nsNetwerkMD5Digest(upload_buffer, upload_buffer_length);
239
        ExpandToHex(digest, upload_data_digest);
237
        ExpandToHex(digest, algorithm, upload_data_digest);
240
        NS_RELEASE(upload);
238
        NS_RELEASE(upload);
241
      }
239
      }
242
    }
240
    }
243
#endif
241
#endif
244
  }
242
  }
245
243
246
  if (!(algorithm & ALGO_MD5 || algorithm & ALGO_MD5_SESS)) {
244
  if (!(algorithm == ALGO_MD5 || algorithm == ALGO_MD5_SESS || algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS)) {
247
    // they asked only for algorithms that we do not support
245
    // they asked only for algorithms that we do not support
248
    NS_WARNING("unsupported algorithm requested by Digest authentication");
246
    NS_WARNING("unsupported algorithm requested by Digest authentication");
249
    return NS_ERROR_NOT_IMPLEMENTED;
247
    return NS_ERROR_NOT_IMPLEMENTED;
250
  }
248
  }
251
249
252
  //
250
  //
253
  // the following are for increasing security.  see RFC 2617 for more
251
  // the following are for increasing security.  see RFC 2617 for more
254
  // information.
252
  // information.
 Lines 285-346   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
285
  for (int i=0; i<16; ++i) {
283
  for (int i=0; i<16; ++i) {
286
    cnonce.Append(hexChar[(int)(15.0 * rand()/(RAND_MAX + 1.0))]);
284
    cnonce.Append(hexChar[(int)(15.0 * rand()/(RAND_MAX + 1.0))]);
287
  }
285
  }
288
  LOG(("   cnonce=%s\n", cnonce.get()));
286
  LOG(("   cnonce=%s\n", cnonce.get()));
289
287
290
  //
288
  //
291
  // calculate credentials
289
  // calculate credentials
292
  //
290
  //
293
291
  nsAutoCString cUser;
294
  NS_ConvertUTF16toUTF8 cUser(username), cPass(password);
292
  nsAutoCString cPass;
293
  if(charset.EqualsLiteral("ISO-8859-1")){
294
  //actually it is ISO-8859-1
295
    LossyCopyUTF16toASCII(username, cUser);
296
    LossyCopyUTF16toASCII(password, cPass);
297
  }
298
  else if(charset.EqualsLiteral("UTF-8")){
299
    CopyUTF16toUTF8(username, cUser);
300
    CopyUTF16toUTF8(password, cPass);
301
  }
302
  else{
303
	//this true lossy convert UTF16 to ASCII
304
	//ASCII is an 7-bit encoding
305
    const char16_t *p = username;
306
		cUser.Assign(*p % 128);
307
	  p++;
308
	  for(;*p != 0;p++){
309
		cUser.Append(*p % 128);
310
	  }
311
	  p = password;
312
		cPass.Assign(*p % 128);
313
	  p++;
314
	  for(;*p != 0;p++){
315
		  cPass.Append(*p % 128);
316
	  }
317
  }
295
  rv = CalculateHA1(cUser, cPass, realm, algorithm, nonce, cnonce, ha1_digest);
318
  rv = CalculateHA1(cUser, cPass, realm, algorithm, nonce, cnonce, ha1_digest);
296
  if (NS_FAILED(rv)) return rv;
319
  if (NS_FAILED(rv)) return rv;
297
320
298
  rv = CalculateHA2(httpMethod, path, qop, upload_data_digest, ha2_digest);
321
  rv = CalculateHA2(httpMethod, path, qop, algorithm, upload_data_digest, ha2_digest);
299
  if (NS_FAILED(rv)) return rv;
322
  if (NS_FAILED(rv)) return rv;
300
323
301
  rv = CalculateResponse(ha1_digest, ha2_digest, nonce, qop, nonce_count,
324
  rv = CalculateResponse(ha1_digest, ha2_digest, nonce, qop, algorithm, nonce_count,
302
                         cnonce, response_digest);
325
                         cnonce, response_digest);
303
  if (NS_FAILED(rv)) return rv;
326
  if (NS_FAILED(rv)) return rv;
304
327
305
  //
328
  //
306
  // Values that need to match the quoted-string production from RFC 2616:
329
  // Values that need to match the quoted-string production from RFC 2616:
307
  //
330
  //
308
  //    username
331
  //    username
309
  //    realm
332
  //    realm
310
  //    nonce
333
  //    nonce
311
  //    opaque
334
  //    opaque
312
  //    cnonce
335
  //    cnonce
313
  //
336
  //
314
315
  nsAutoCString authString;
337
  nsAutoCString authString;
338
  if(userhash == 2){
339
	  char hashuser[EXPANDED_DIGEST_SHA256_LENGTH+1];
340
    	  cUser.Append(":");
341
    	  cUser.Append(realm);
342
	  aHash(cUser.get(), cUser.Length(), algorithm);
343
	  ExpandToHex(mHashBuf, algorithm, hashuser);
344
	  authString.AssignLiteral("Digest username=\"");
345
	  authString += hashuser;
346
	  authString += '\"';
347
	  goto appendRealm;
348
  }
349
  if(charset.EqualsLiteral("ISO-8859-1") || charset.EqualsLiteral("UTF-8")){
350
	  if(charset.EqualsLiteral("ISO-8859-1")){
351
		authString.AssignLiteral("Digest username*=ISO-8859-1\'\'");
352
	  }
353
	  else{
354
		authString.AssignLiteral("Digest username*=UTF-8\'\'");
355
	  }
356
	  nsAutoCString escUser;
357
	  NS_Escape(cUser, escUser,  url_XAlphas);
358
	  authString.Append(escUser);
359
	  goto appendRealm;
360
  }
316
361
317
  authString.AssignLiteral("Digest username=");
362
  authString.AssignLiteral("Digest username=");
318
  rv = AppendQuotedString(cUser, authString);
363
  rv = AppendQuotedString(cUser, authString);
319
  NS_ENSURE_SUCCESS(rv, rv);
364
  NS_ENSURE_SUCCESS(rv, rv);
320
365
366
  appendRealm:
321
  authString.AppendLiteral(", realm=");
367
  authString.AppendLiteral(", realm=");
322
  rv = AppendQuotedString(realm, authString);
368
  rv = AppendQuotedString(realm, authString);
323
  NS_ENSURE_SUCCESS(rv, rv);
369
  NS_ENSURE_SUCCESS(rv, rv);
324
370
325
  authString.AppendLiteral(", nonce=");
371
  authString.AppendLiteral(", nonce=");
326
  rv = AppendQuotedString(nonce, authString);
372
  rv = AppendQuotedString(nonce, authString);
327
  NS_ENSURE_SUCCESS(rv, rv);
373
  NS_ENSURE_SUCCESS(rv, rv);
328
374
329
  authString.AppendLiteral(", uri=\"");
375
  authString.AppendLiteral(", uri=\"");
330
  authString += path;
376
  authString += path;
331
  if (algorithm & ALGO_SPECIFIED) {
377
  authString.AppendLiteral("\", algorithm=");
332
    authString.AppendLiteral("\", algorithm=");
378
 	if(algorithm == ALGO_SHA256_SESS){
333
    if (algorithm & ALGO_MD5_SESS)
379
  	authString.AppendLiteral("SHA-256-sess");
334
      authString.AppendLiteral("MD5-sess");
380
  }
335
    else
381
  else if(algorithm == ALGO_SHA256){
336
      authString.AppendLiteral("MD5");
382
	authString.AppendLiteral("SHA-256");
337
  } else {
383
  }
338
    authString += '\"';
384
  else if (algorithm == ALGO_MD5_SESS){
385
	authString.AppendLiteral("MD5-sess");
386
  }
387
  else{
388
	authString.AppendLiteral("MD5");
339
  }
389
  }
340
  authString.AppendLiteral(", response=\"");
390
  authString.AppendLiteral(", response=\"");
341
  authString += response_digest;
391
  authString += response_digest;
342
  authString += '\"';
392
  authString += '\"';
343
393
344
  if (!opaque.IsEmpty()) {
394
  if (!opaque.IsEmpty()) {
345
    authString.AppendLiteral(", opaque=");
395
    authString.AppendLiteral(", opaque=");
346
    rv = AppendQuotedString(opaque, authString);
396
    rv = AppendQuotedString(opaque, authString);
 Lines 358-374   nsHttpDigestAuth::GenerateCredentials(ns Link Here 
358
      authString += '\"';
408
      authString += '\"';
359
    authString.AppendLiteral(", nc=");
409
    authString.AppendLiteral(", nc=");
360
    authString += nonce_count;
410
    authString += nonce_count;
361
411
362
    authString.AppendLiteral(", cnonce=");
412
    authString.AppendLiteral(", cnonce=");
363
    rv = AppendQuotedString(cnonce, authString);
413
    rv = AppendQuotedString(cnonce, authString);
364
    NS_ENSURE_SUCCESS(rv, rv);
414
    NS_ENSURE_SUCCESS(rv, rv);
365
  }
415
  }
366
416
  if(userhash){
417
    authString.AppendLiteral(", userhash=");
418
    if(userhash == 2){
419
      authString.AppendLiteral("true");
420
    }
421
    else{
422
      authString.AppendLiteral("false");
423
    }
424
  }
367
425
368
  *creds = ToNewCString(authString);
426
  *creds = ToNewCString(authString);
369
  return NS_OK;
427
  return NS_OK;
370
}
428
}
371
429
372
NS_IMETHODIMP
430
NS_IMETHODIMP
373
nsHttpDigestAuth::GetAuthFlags(uint32_t *flags)
431
nsHttpDigestAuth::GetAuthFlags(uint32_t *flags)
374
{
432
{
 Lines 380-558   nsHttpDigestAuth::GetAuthFlags(uint32_t Link Here 
380
  return NS_OK;
438
  return NS_OK;
381
}
439
}
382
440
383
nsresult
441
nsresult
384
nsHttpDigestAuth::CalculateResponse(const char * ha1_digest,
442
nsHttpDigestAuth::CalculateResponse(const char * ha1_digest,
385
                                    const char * ha2_digest,
443
                                    const char * ha2_digest,
386
                                    const nsAFlatCString & nonce,
444
                                    const nsAFlatCString & nonce,
387
                                    uint16_t qop,
445
                                    uint16_t qop,
446
                  		     uint16_t algorithm,
388
                                    const char * nonce_count,
447
                                    const char * nonce_count,
389
                                    const nsAFlatCString & cnonce,
448
                                    const nsAFlatCString & cnonce,
390
                                    char * result)
449
                                    char * result)
391
{
450
{
392
  uint32_t len = 2*EXPANDED_DIGEST_LENGTH + nonce.Length() + 2;
451
  uint32_t len;
393
452
  if(algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS){
394
  if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
453
	  len = 2*EXPANDED_DIGEST_SHA256_LENGTH + nonce.Length() + 2;
454
  }
455
  else{
456
	  len = 2*EXPANDED_DIGEST_LENGTH + nonce.Length() + 2;
457
  }
458
  if (qop == QOP_AUTH || qop == QOP_AUTH_INT) {
395
    len += cnonce.Length() + NONCE_COUNT_LENGTH + 3;
459
    len += cnonce.Length() + NONCE_COUNT_LENGTH + 3;
396
    if (qop & QOP_AUTH_INT)
460
    if (qop & QOP_AUTH_INT)
397
      len += 8; // length of "auth-int"
461
      len += 8; // length of "auth-int"
398
    else
462
    else
399
      len += 4; // length of "auth"
463
      len += 4; // length of "auth"
400
  }
464
  }
401
465
402
  nsAutoCString contents;
466
  nsAutoCString contents;
403
  contents.SetCapacity(len);
467
  contents.SetCapacity(len);
404
468
405
  contents.Assign(ha1_digest, EXPANDED_DIGEST_LENGTH);
469
  if(algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS){
470
	  contents.Assign(ha1_digest, EXPANDED_DIGEST_SHA256_LENGTH);
471
  }
472
  else{
473
	  contents.Assign(ha1_digest, EXPANDED_DIGEST_LENGTH);
474
  }
406
  contents.Append(':');
475
  contents.Append(':');
407
  contents.Append(nonce);
476
  contents.Append(nonce);
408
  contents.Append(':');
477
  contents.Append(':');
409
478
410
  if (qop & QOP_AUTH || qop & QOP_AUTH_INT) {
479
  if (qop == QOP_AUTH || qop == QOP_AUTH_INT) {
411
    contents.Append(nonce_count, NONCE_COUNT_LENGTH);
480
    contents.Append(nonce_count, NONCE_COUNT_LENGTH);
412
    contents.Append(':');
481
    contents.Append(':');
413
    contents.Append(cnonce);
482
    contents.Append(cnonce);
414
    contents.Append(':');
483
    contents.Append(':');
415
    if (qop & QOP_AUTH_INT)
484
    if (qop & QOP_AUTH_INT)
416
      contents.AppendLiteral("auth-int:");
485
      contents.AppendLiteral("auth-int:");
417
    else
486
    else
418
      contents.AppendLiteral("auth:");
487
      contents.AppendLiteral("auth:");
419
  }
488
  }
420
489
  if(algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS){
421
  contents.Append(ha2_digest, EXPANDED_DIGEST_LENGTH);
490
	  contents.Append(ha2_digest, EXPANDED_DIGEST_SHA256_LENGTH);
422
491
  }
423
  nsresult rv = MD5Hash(contents.get(), contents.Length());
492
  else{
493
	  contents.Append(ha2_digest, EXPANDED_DIGEST_LENGTH);
494
  }
495
  nsresult rv = aHash(contents.get(), contents.Length(), algorithm);
424
  if (NS_SUCCEEDED(rv))
496
  if (NS_SUCCEEDED(rv))
425
    rv = ExpandToHex(mHashBuf, result);
497
    rv = ExpandToHex(mHashBuf, algorithm, result);
426
  return rv;
498
  return rv;
427
}
499
}
428
500
429
nsresult
501
nsresult
430
nsHttpDigestAuth::ExpandToHex(const char * digest, char * result)
502
nsHttpDigestAuth::ExpandToHex(const char * digest, int16_t algorithm, char * result)
431
{
503
{
432
  int16_t index, value;
504
  int16_t index, value, digestLen;
433
505
  if(algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS){
434
  for (index = 0; index < DIGEST_LENGTH; index++) {
506
	  digestLen = DIGEST_SHA256_LENGTH;
507
  }
508
  else{
509
	  digestLen = DIGEST_LENGTH;
510
  }
511
  for (index = 0; index < digestLen; index++) {
435
    value = (digest[index] >> 4) & 0xf;
512
    value = (digest[index] >> 4) & 0xf;
436
    if (value < 10)
513
    if (value < 10)
437
      result[index*2] = value + '0';
514
      result[index*2] = value + '0';
438
    else
515
    else
439
      result[index*2] = value - 10 + 'a';
516
      result[index*2] = value - 10 + 'a';
440
517
441
    value = digest[index] & 0xf;
518
    value = digest[index] & 0xf;
442
    if (value < 10)
519
    if (value < 10)
443
      result[(index*2)+1] = value + '0';
520
      result[(index*2)+1] = value + '0';
444
    else
521
    else
445
      result[(index*2)+1] = value - 10 + 'a';
522
      result[(index*2)+1] = value - 10 + 'a';
446
  }
523
  }
447
524
448
  result[EXPANDED_DIGEST_LENGTH] = 0;
525
  result[digestLen * 2] = 0;
449
  return NS_OK;
526
  return NS_OK;
450
}
527
}
451
528
452
nsresult
529
nsresult
453
nsHttpDigestAuth::CalculateHA1(const nsAFlatCString & username,
530
nsHttpDigestAuth::CalculateHA1(const nsAFlatCString & username,
454
                               const nsAFlatCString & password,
531
                               const nsAFlatCString & password,
455
                               const nsAFlatCString & realm,
532
                               const nsAFlatCString & realm,
456
                               uint16_t algorithm,
533
                               uint16_t algorithm,
457
                               const nsAFlatCString & nonce,
534
                               const nsAFlatCString & nonce,
458
                               const nsAFlatCString & cnonce,
535
                               const nsAFlatCString & cnonce,
459
                               char * result)
536
                               char * result)
460
{
537
{
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
  }
467
468
  nsAutoCString contents;
538
  nsAutoCString contents;
469
  contents.SetCapacity(len + 1);
470
539
471
  contents.Assign(username);
540
  contents.Assign(username);
472
  contents.Append(':');
541
  contents.Append(':');
473
  contents.Append(realm);
542
  contents.Append(realm);
474
  contents.Append(':');
543
  contents.Append(':');
475
  contents.Append(password);
544
  contents.Append(password);
545
  nsresult rv;
546
  rv = aHash(contents.get(), contents.Length(), algorithm);
547
  if (NS_FAILED(rv)){
548
    return rv;
549
  }
550
  if(algorithm == ALGO_MD5_SESS || algorithm == ALGO_SHA256_SESS){
551
  	if (algorithm == ALGO_SHA256_SESS){
552
	  	char part1[EXPANDED_DIGEST_SHA256_LENGTH+1];
553
	  	ExpandToHex(mHashBuf, algorithm, part1);
554
  		contents.Assign(part1, EXPANDED_DIGEST_SHA256_LENGTH);
555
  	}
556
  	else{
557
  		char part1[EXPANDED_DIGEST_LENGTH+1];
558
  		ExpandToHex(mHashBuf, algorithm, part1);
559
  		contents.Assign(part1, EXPANDED_DIGEST_LENGTH);
560
  	}
561
  	contents.Append(':');
562
	contents.Append(nonce);
563
  	contents.Append(':');
564
  	contents.Append(cnonce);
565
  	rv = aHash(contents.get(), contents.Length(), algorithm);
566
  	if (NS_FAILED(rv)){
567
  		return rv;
568
    }
569
  }
570
  return ExpandToHex(mHashBuf, algorithm, result);
476
571
477
  nsresult rv;
478
  rv = MD5Hash(contents.get(), contents.Length());
479
  if (NS_FAILED(rv))
480
    return rv;
481
482
  if (algorithm & ALGO_MD5_SESS) {
483
    char part1[EXPANDED_DIGEST_LENGTH+1];
484
    ExpandToHex(mHashBuf, part1);
485
486
    contents.Assign(part1, EXPANDED_DIGEST_LENGTH);
487
    contents.Append(':');
488
    contents.Append(nonce);
489
    contents.Append(':');
490
    contents.Append(cnonce);
491
492
    rv = MD5Hash(contents.get(), contents.Length());
493
    if (NS_FAILED(rv))
494
      return rv;
495
  }
496
497
  return ExpandToHex(mHashBuf, result);
498
}
572
}
499
573
500
nsresult
574
nsresult
501
nsHttpDigestAuth::CalculateHA2(const nsAFlatCString & method,
575
nsHttpDigestAuth::CalculateHA2(const nsAFlatCString & method,
502
                               const nsAFlatCString & path,
576
                               const nsAFlatCString & path,
503
                               uint16_t qop,
577
                               uint16_t qop,
578
              			uint16_t algorithm,
504
                               const char * bodyDigest,
579
                               const char * bodyDigest,
505
                               char * result)
580
                               char * result)
506
{
581
{
507
  uint16_t methodLen = method.Length();
582
  uint16_t methodLen = method.Length();
508
  uint32_t pathLen = path.Length();
583
  uint32_t pathLen = path.Length();
509
  uint32_t len = methodLen + pathLen + 1;
584
  uint32_t len = methodLen + pathLen + 1;
510
585
511
  if (qop & QOP_AUTH_INT) {
586
  if (qop == QOP_AUTH_INT) {
512
    len += EXPANDED_DIGEST_LENGTH + 1;
587
	  if(algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS){
588
	    len += EXPANDED_DIGEST_SHA256_LENGTH + 1;
589
	  }
590
	  else{
591
  	    len += EXPANDED_DIGEST_LENGTH + 1;
592
	  }
513
  }
593
  }
514
594
515
  nsAutoCString contents;
595
  nsAutoCString contents;
516
  contents.SetCapacity(len);
596
  contents.SetCapacity(len);
517
597
518
  contents.Assign(method);
598
  contents.Assign(method);
519
  contents.Append(':');
599
  contents.Append(':');
520
  contents.Append(path);
600
  contents.Append(path);
521
601
522
  if (qop & QOP_AUTH_INT) {
602
  if (qop == QOP_AUTH_INT) {
523
    contents.Append(':');
603
    contents.Append(':');
524
    contents.Append(bodyDigest, EXPANDED_DIGEST_LENGTH);
604
    if(algorithm == ALGO_SHA256 || algorithm == ALGO_SHA256_SESS){
605
	    contents.Append(bodyDigest, EXPANDED_DIGEST_SHA256_LENGTH);
606
    }
607
    else{
608
	    contents.Append(bodyDigest, EXPANDED_DIGEST_LENGTH);
609
    }
525
  }
610
  }
526
611
527
  nsresult rv = MD5Hash(contents.get(), contents.Length());
612
  nsresult rv = aHash(contents.get(), contents.Length(), algorithm);
528
  if (NS_SUCCEEDED(rv))
613
  if (NS_SUCCEEDED(rv))
529
    rv = ExpandToHex(mHashBuf, result);
614
    rv = ExpandToHex(mHashBuf, algorithm, result);
530
  return rv;
615
  return rv;
531
}
616
}
532
617
533
nsresult
618
nsresult
534
nsHttpDigestAuth::ParseChallenge(const char * challenge,
619
nsHttpDigestAuth::ParseChallenge(const char * challenge,
535
                                 nsACString & realm,
620
                                 nsACString & realm,
536
                                 nsACString & domain,
621
                                 nsACString & domain,
537
                                 nsACString & nonce,
622
                                 nsACString & nonce,
538
                                 nsACString & opaque,
623
                                 nsACString & opaque,
624
                		  nsACString & charset,
539
                                 bool * stale,
625
                                 bool * stale,
540
                                 uint16_t * algorithm,
626
                                 uint16_t * algorithm,
541
                                 uint16_t * qop)
627
                                 uint16_t * qop,
628
                                 uint16_t * userhash)
542
{
629
{
543
  // put an absurd, but maximum, length cap on the challenge so
630
  // put an absurd, but maximum, length cap on the challenge so
544
  // that calculations are 32 bit safe
631
  // that calculations are 32 bit safe
545
  if (strlen(challenge) > 16000000) {
632
  if (strlen(challenge) > 16000000) {
546
    return NS_ERROR_INVALID_ARG;
633
    return NS_ERROR_INVALID_ARG;
547
  }
634
  }
548
  
635
  
549
  const char *p = challenge + 7; // first 7 characters are "Digest "
636
  const char *p = challenge + 7; // first 7 characters are "Digest "
550
637
  *userhash = 0;
551
  *stale = false;
638
  *stale = false;
552
  *algorithm = ALGO_MD5; // default is MD5
639
  *algorithm = ALGO_MD5; // default is MD5
553
  *qop = 0;
640
  *qop = 0;
554
641
555
  for (;;) {
642
  for (;;) {
556
    while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p)))
643
    while (*p && (*p == ',' || nsCRT::IsAsciiSpace(*p)))
557
      ++p;
644
      ++p;
558
    if (!*p)
645
    if (!*p)
 Lines 609-643   nsHttpDigestAuth::ParseChallenge(const c Link Here 
609
    {
696
    {
610
      nonce.Assign(challenge+valueStart, valueLength);
697
      nonce.Assign(challenge+valueStart, valueLength);
611
    }
698
    }
612
    else if (nameLength == 6 &&
699
    else if (nameLength == 6 &&
613
        nsCRT::strncasecmp(challenge+nameStart, "opaque", 6) == 0)
700
        nsCRT::strncasecmp(challenge+nameStart, "opaque", 6) == 0)
614
    {
701
    {
615
      opaque.Assign(challenge+valueStart, valueLength);
702
      opaque.Assign(challenge+valueStart, valueLength);
616
    }
703
    }
704
    else if (nameLength == 7 &&
705
	      nsCRT::strncasecmp(challenge+nameStart, "charset", 7) == 0)
706
    {
707
      charset.Assign(challenge+valueStart, valueLength);
708
    }
709
    else if (nameLength == 8 &&
710
             nsCRT::strncasecmp(challenge+nameStart, "userhash", 8) == 0)
711
    {
712
      if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0){
713
        *userhash = 2;
714
      }
715
      else{
716
        *userhash = 1;
717
      }
718
    }
617
    else if (nameLength == 5 &&
719
    else if (nameLength == 5 &&
618
        nsCRT::strncasecmp(challenge+nameStart, "stale", 5) == 0)
720
        nsCRT::strncasecmp(challenge+nameStart, "stale", 5) == 0)
619
    {
721
    {
620
      if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0)
722
      if (nsCRT::strncasecmp(challenge+valueStart, "true", 4) == 0)
621
        *stale = true;
723
        *stale = true;
622
      else
724
      else
623
        *stale = false;
725
        *stale = false;
624
    }
726
    }
625
    else if (nameLength == 9 &&
727
    else if (nameLength == 9 &&
626
        nsCRT::strncasecmp(challenge+nameStart, "algorithm", 9) == 0)
728
        nsCRT::strncasecmp(challenge+nameStart, "algorithm", 9) == 0)
627
    {
729
    {
628
      // we want to clear the default, so we use = not |= here
629
      *algorithm = ALGO_SPECIFIED;
730
      *algorithm = ALGO_SPECIFIED;
630
      if (valueLength == 3 &&
731
      if (valueLength == 3 &&
631
          nsCRT::strncasecmp(challenge+valueStart, "MD5", 3) == 0)
732
          nsCRT::strncasecmp(challenge+valueStart, "MD5", 3) == 0){
632
        *algorithm |= ALGO_MD5;
733
        *algorithm = ALGO_MD5;
734
      }
633
      else if (valueLength == 8 &&
735
      else if (valueLength == 8 &&
634
          nsCRT::strncasecmp(challenge+valueStart, "MD5-sess", 8) == 0)
736
               nsCRT::strncasecmp(challenge+valueStart, "MD5-sess", 8) == 0){
635
        *algorithm |= ALGO_MD5_SESS;
737
        *algorithm = ALGO_MD5_SESS;
738
      }
739
      else if (valueLength == 7 &&
740
               nsCRT::strncasecmp(challenge+valueStart, "SHA-256", 7) == 0){
741
        *algorithm = ALGO_SHA256;
742
      }
743
      else if (valueLength == 12 &&
744
               nsCRT::strncasecmp(challenge+valueStart, "SHA-256-sess", 12) == 0){
745
        *algorithm = ALGO_SHA256_SESS;
746
      }
636
    }
747
    }
637
    else if (nameLength == 3 &&
748
    else if (nameLength == 3 &&
638
        nsCRT::strncasecmp(challenge+nameStart, "qop", 3) == 0)
749
        nsCRT::strncasecmp(challenge+nameStart, "qop", 3) == 0)
639
    {
750
    {
640
      int32_t ipos = valueStart;
751
      int32_t ipos = valueStart;
641
      while (ipos < valueStart+valueLength) {
752
      while (ipos < valueStart+valueLength) {
642
        while (ipos < valueStart+valueLength &&
753
        while (ipos < valueStart+valueLength &&
643
               (nsCRT::IsAsciiSpace(challenge[ipos]) ||
754
               (nsCRT::IsAsciiSpace(challenge[ipos]) ||
 Lines 683-700   nsHttpDigestAuth::AppendQuotedString(con Link Here 
683
794
684
    // Escape two syntactically significant characters
795
    // Escape two syntactically significant characters
685
    if (*s == '"' || *s == '\\') {
796
    if (*s == '"' || *s == '\\') {
686
      quoted.Append('\\');
797
      quoted.Append('\\');
687
    }
798
    }
688
799
689
    quoted.Append(*s);
800
    quoted.Append(*s);
690
  }
801
  }
691
  // FIXME: bug 41489
692
  // We should RFC2047-encode non-Latin-1 values according to spec
693
  quoted.Append('"');
802
  quoted.Append('"');
694
  aHeaderLine.Append(quoted);
803
  aHeaderLine.Append(quoted);
695
  return NS_OK;
804
  return NS_OK;
696
}
805
}
697
806
698
} // namespace mozilla::net
807
} // namespace mozilla::net
699
} // namespace mozilla
808
} // namespace mozilla
700
809
(-)a/netwerk/protocol/http/nsHttpDigestAuth.h (-5 / +13 lines)
Line     Link Here 
 Lines 13-34    Link Here 
13
#include "mozilla/Attributes.h"
13
#include "mozilla/Attributes.h"
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 0x03
22
#define ALGO_SHA256 0x04
23
#define ALGO_SHA256_SESS 0x05
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_LENGTH 16
28
#define DIGEST_SHA256_LENGTH 32
26
#define EXPANDED_DIGEST_LENGTH 32
29
#define EXPANDED_DIGEST_LENGTH 32
30
#define EXPANDED_DIGEST_SHA256_LENGTH 64
27
#define NONCE_COUNT_LENGTH 8
31
#define NONCE_COUNT_LENGTH 8
28
32
29
//-----------------------------------------------------------------------------
33
//-----------------------------------------------------------------------------
30
// nsHttpDigestAuth
34
// nsHttpDigestAuth
31
//-----------------------------------------------------------------------------
35
//-----------------------------------------------------------------------------
32
36
33
class nsHttpDigestAuth final : public nsIHttpAuthenticator
37
class nsHttpDigestAuth final : public nsIHttpAuthenticator
34
{
38
{
 Lines 36-94   class nsHttpDigestAuth final : public ns Link Here 
36
    NS_DECL_ISUPPORTS
40
    NS_DECL_ISUPPORTS
37
    NS_DECL_NSIHTTPAUTHENTICATOR
41
    NS_DECL_NSIHTTPAUTHENTICATOR
38
42
39
    nsHttpDigestAuth();
43
    nsHttpDigestAuth();
40
44
41
  protected:
45
  protected:
42
    ~nsHttpDigestAuth();
46
    ~nsHttpDigestAuth();
43
47
44
    nsresult ExpandToHex(const char * digest, char * result);
48
    nsresult ExpandToHex(const char * digest, int16_t algorithm, char * result);
45
49
46
    nsresult CalculateResponse(const char * ha1_digest,
50
    nsresult CalculateResponse(const char * ha1_digest,
47
                               const char * ha2_digest,
51
                               const char * ha2_digest,
48
                               const nsAFlatCString & nonce,
52
                               const nsAFlatCString & nonce,
49
                               uint16_t qop,
53
                               uint16_t qop,
54
              			uint16_t algorithm,
50
                               const char * nonce_count,
55
                               const char * nonce_count,
51
                               const nsAFlatCString & cnonce,
56
                               const nsAFlatCString & cnonce,
52
                               char * result);
57
                               char * result);
53
58
54
    nsresult CalculateHA1(const nsAFlatCString & username,
59
    nsresult CalculateHA1(const nsAFlatCString & username,
55
                          const nsAFlatCString & password,
60
                          const nsAFlatCString & password,
56
                          const nsAFlatCString & realm,
61
                          const nsAFlatCString & realm,
57
                          uint16_t algorithm,
62
                          uint16_t algorithm,
58
                          const nsAFlatCString & nonce,
63
                          const nsAFlatCString & nonce,
59
                          const nsAFlatCString & cnonce,
64
                          const nsAFlatCString & cnonce,
60
                          char * result);
65
                          char * result);
61
66
62
    nsresult CalculateHA2(const nsAFlatCString & http_method,
67
    nsresult CalculateHA2(const nsAFlatCString & http_method,
63
                          const nsAFlatCString & http_uri_path,
68
                          const nsAFlatCString & http_uri_path,
64
                          uint16_t qop,
69
                          uint16_t qop,
70
            		   uint16_t algorithm,
65
                          const char * body_digest,
71
                          const char * body_digest,
66
                          char * result);
72
                          char * result);
67
73
68
    nsresult ParseChallenge(const char * challenge,
74
    nsresult ParseChallenge(const char * challenge,
69
                            nsACString & realm,
75
                            nsACString & realm,
70
                            nsACString & domain,
76
                            nsACString & domain,
71
                            nsACString & nonce,
77
                            nsACString & nonce,
72
                            nsACString & opaque,
78
                            nsACString & opaque,
79
              		     nsACString & charset,
73
                            bool * stale,
80
                            bool * stale,
74
                            uint16_t * algorithm,
81
                            uint16_t * algorithm,
75
                            uint16_t * qop);
82
                            uint16_t * qop,
83
                            uint16_t * userhash);
76
84
77
    // result is in mHashBuf
85
    // result is in mHashBuf
78
    nsresult MD5Hash(const char *buf, uint32_t len);
86
    nsresult aHash(const char *buf, uint32_t len, uint16_t algorithm);
79
87
80
    nsresult GetMethodAndPath(nsIHttpAuthenticableChannel *,
88
    nsresult GetMethodAndPath(nsIHttpAuthenticableChannel *,
81
                              bool, nsCString &, nsCString &);
89
                              bool, nsCString &, nsCString &);
82
90
83
    // append the quoted version of value to aHeaderLine
91
    // append the quoted version of value to aHeaderLine
84
    nsresult AppendQuotedString(const nsACString & value,
92
    nsresult AppendQuotedString(const nsACString & value,
85
                                nsACString & aHeaderLine);
93
                                nsACString & aHeaderLine);
86
94
87
  protected:
95
  protected:
88
    nsCOMPtr<nsICryptoHash>        mVerifier;
96
    nsCOMPtr<nsICryptoHash>        mVerifier;
89
    char                           mHashBuf[DIGEST_LENGTH];
97
    char                           mHashBuf[DIGEST_SHA256_LENGTH];
90
};
98
};
91
99
92
}} // namespace mozilla::net
100
}} // namespace mozilla::net
93
101
94
#endif // nsHttpDigestAuth_h__
102
#endif // nsHttpDigestAuth_h__

Return to bug 41489