Fossil

Check-in [48bcfbd4]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:It seems like blob_constant_time_eq() is unnecessary for sync protocol signatures; removed.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dmitry-security
Files: files | file ages | folders
SHA1:48bcfbd47bf51d4776dfd3751847270ea188ad8c
User & Date: dmitry 2011-09-30 10:51:35
Context
2011-10-04
14:28
Revert the previous change after thinking more about it.

Login cards in the sync protocol have the following format:

login userid nonce signature

Nonce is SHA-1 of the message that follows this line, signature is SHA-1 of the concatenation of the nonce and user's shared secret. The successful timing attack can reveal only signature for this particular packet due to nonce. However, as nonce is known to the attacker, it's theoretically possible for them to bruteforce the shared secret_offline_.

The whole scenario sounds highly improbable, but using constant-time comparison function for such things by default is a good practice. check-in: 13a9a124 user: dmitry tags: dmitry-security

2011-09-30
10:51
It seems like blob_constant_time_eq() is unnecessary for sync protocol signatures; removed. check-in: 48bcfbd4 user: dmitry tags: dmitry-security
09:41
Catch zero length early in blob_constant_time_eq(). check-in: e3d022df user: dmitry tags: dmitry-security
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/blob.c.

309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  szA = blob_size(pA);
  szB = blob_size(pB);
  sz = szA<szB ? szA : szB;
  rc = memcmp(blob_buffer(pA), blob_buffer(pB), sz);
  if( rc==0 ){
    rc = szA - szB;
  }
  return rc;
}

/*
** Compare two blobs in constant time and return zero if they are equal.
** Constant time comparison only applies for blobs of the same length.
** If lengths are different, immediately returns 1.
*/
int blob_constant_time_eq(Blob *pA, Blob *pB){
  int szA, szB, i;
  unsigned char *buf1, *buf2;
  unsigned char rc = 0;

  blob_is_init(pA);
  blob_is_init(pB);
  szA = blob_size(pA);
  szB = blob_size(pB);
  if( szA!=szB || szA==0 ) return 1;

  buf1 = blob_buffer(pA);
  buf2 = blob_buffer(pB);

  for( i=0; i<szA; i++ ){
    rc = rc | (buf1[i] ^ buf2[i]);
  }

  return rc;
}

/*
** Compare a blob to a string.  Return TRUE if they are equal.
*/
int blob_eq_str(Blob *pBlob, const char *z, int n){







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







309
310
311
312
313
314
315


























316
317
318
319
320
321
322
  szA = blob_size(pA);
  szB = blob_size(pB);
  sz = szA<szB ? szA : szB;
  rc = memcmp(blob_buffer(pA), blob_buffer(pB), sz);
  if( rc==0 ){
    rc = szA - szB;
  }


























  return rc;
}

/*
** Compare a blob to a string.  Return TRUE if they are equal.
*/
int blob_eq_str(Blob *pBlob, const char *z, int n){

Changes to src/xfer.c.

571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
...
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
    db_ephemeral_blob(&q, 0, &pw);
    szPw = blob_size(&pw);
    blob_zero(&combined);
    blob_copy(&combined, pNonce);
    blob_append(&combined, blob_buffer(&pw), szPw);
    sha1sum_blob(&combined, &hash);
    assert( blob_size(&hash)==40 );
    rc = blob_constant_time_eq(&hash, pSig);
    blob_reset(&hash);
    blob_reset(&combined);
    if( rc!=0 && szPw!=40 ){
      /* If this server stores cleartext passwords and the password did not
      ** match, then perhaps the client is sending SHA1 passwords.  Try
      ** again with the SHA1 password.
      */
................................................................................
      const char *zPw = db_column_text(&q, 0);
      char *zSecret = sha1_shared_secret(zPw, blob_str(pLogin), 0);
      blob_zero(&combined);
      blob_copy(&combined, pNonce);
      blob_append(&combined, zSecret, -1);
      free(zSecret);
      sha1sum_blob(&combined, &hash);
      rc = blob_constant_time_eq(&hash, pSig);
      blob_reset(&hash);
      blob_reset(&combined);
    }
    if( rc==0 ){
      const char *zCap;
      zCap = db_column_text(&q, 1);
      login_set_capabilities(zCap, 0);







|







 







|







571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
...
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
    db_ephemeral_blob(&q, 0, &pw);
    szPw = blob_size(&pw);
    blob_zero(&combined);
    blob_copy(&combined, pNonce);
    blob_append(&combined, blob_buffer(&pw), szPw);
    sha1sum_blob(&combined, &hash);
    assert( blob_size(&hash)==40 );
    rc = blob_compare(&hash, pSig);
    blob_reset(&hash);
    blob_reset(&combined);
    if( rc!=0 && szPw!=40 ){
      /* If this server stores cleartext passwords and the password did not
      ** match, then perhaps the client is sending SHA1 passwords.  Try
      ** again with the SHA1 password.
      */
................................................................................
      const char *zPw = db_column_text(&q, 0);
      char *zSecret = sha1_shared_secret(zPw, blob_str(pLogin), 0);
      blob_zero(&combined);
      blob_copy(&combined, pNonce);
      blob_append(&combined, zSecret, -1);
      free(zSecret);
      sha1sum_blob(&combined, &hash);
      rc = blob_compare(&hash, pSig);
      blob_reset(&hash);
      blob_reset(&combined);
    }
    if( rc==0 ){
      const char *zCap;
      zCap = db_column_text(&q, 1);
      login_set_capabilities(zCap, 0);