Merge remote-tracking branch 'origin/v0.8'
authorBen Noordhuis <info@bnoordhuis.nl>
Sat, 2 Mar 2013 22:13:35 +0000 (23:13 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Sat, 2 Mar 2013 22:13:35 +0000 (23:13 +0100)
Conflicts:
doc/api/http.markdown
test/simple/test-crypto.js

1  2 
doc/api/http.markdown
lib/http.js
src/node_crypto.cc
test/simple/test-crypto.js
test/simple/test-dgram-pingpong.js

@@@ -762,14 -879,15 +762,12 @@@ Just like `'end'`, this event occurs on
  `'data'` events will fire afterwards. See [http.ServerResponse][]'s `'close'`
  event for more information.
  
- Note: `'close'` can fire after `'end'`, but not vice versa.
 +### message.httpVersion
  
 -### response.statusCode
 +In case of server request, the HTTP version sent by the client. In the case of
 +client response, the HTTP version of the connected-to server.
 +Probably either `'1.1'` or `'1.0'`.
  
 -The 3-digit HTTP response status code. E.G. `404`.
 -
 -### response.httpVersion
 -
 -The HTTP version of the connected-to server. Probably either
 -`'1.1'` or `'1.0'`.
  Also `response.httpVersionMajor` is the first integer and
  `response.httpVersionMinor` is the second.
  
diff --cc lib/http.js
Simple merge
@@@ -2279,17 -2301,46 +2279,13 @@@ class Cipher : public ObjectWrap 
  
      int r = cipher->CipherFinal(&out_value, &out_len);
  
-     assert(out_value != NULL);
-     assert(out_len != -1 || r == 0);
-     if (out_len == 0 || r == 0) {
-       // out_value always get allocated.
+     if (out_len <= 0 || r == 0) {
        delete[] out_value;
 -      if (r == 0) {
 -        Local<Value> exception = Exception::TypeError(
 -          String::New("CipherFinal fail"));
 -        return ThrowException(exception);
 -      } else {
 -        return scope.Close(String::New(""));
 -      }
 +      out_value = NULL;
 +      if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
      }
  
 -    enum encoding enc = ParseEncoding(args[0], BINARY);
 -    if (enc == HEX) {
 -      // Hex encoding
 -      HexEncode(out_value, out_len, &out_hexdigest, &out_hex_len);
 -      outString = Encode(out_hexdigest, out_hex_len, BINARY);
 -      delete [] out_hexdigest;
 -    } else if (enc == BASE64) {
 -      // Check to see if we need to add in previous base64 overhang
 -      if (cipher->incomplete_base64!=NULL){
 -        unsigned char* complete_base64 = new unsigned char[out_len+cipher->incomplete_base64_len+1];
 -        memcpy(complete_base64, cipher->incomplete_base64, cipher->incomplete_base64_len);
 -        memcpy(&complete_base64[cipher->incomplete_base64_len], out_value, out_len);
 -        delete [] out_value;
 -
 -        delete [] cipher->incomplete_base64;
 -        cipher->incomplete_base64=NULL;
 -
 -        out_value=complete_base64;
 -        out_len += cipher->incomplete_base64_len;
 -      }
 -      base64(out_value, out_len, &out_hexdigest, &out_hex_len);
 -      outString = Encode(out_hexdigest, out_hex_len, BINARY);
 -      delete [] out_hexdigest;
 -    } else if (enc == BINARY) {
 -      outString = Encode(out_value, out_len, BINARY);
 -    } else {
 -      fprintf(stderr, "node-crypto : Cipher .final encoding "
 -                      "can be binary, hex or base64\n");
 -    }
 +    outString = Encode(out_value, out_len, BUFFER);
  
      delete [] out_value;
      return scope.Close(outString);
@@@ -2591,18 -2750,42 +2587,15 @@@ class Decipher : public ObjectWrap 
      int out_len = -1;
      Local<Value> outString;
  
 -    int r = cipher->DecipherFinal<TOLERATE_PADDING>(&out_value, &out_len);
 +    int r = cipher->DecipherFinal(&out_value, &out_len);
  
-     assert(out_value != NULL);
-     assert(out_len != -1);
-     if (out_len == 0 || r == 0) {
+     if (out_len <= 0 || r == 0) {
        delete [] out_value; // allocated even if out_len == 0
 -      if (r == 0) {
 -        Local<Value> exception = Exception::TypeError(
 -          String::New("DecipherFinal fail"));
 -        return ThrowException(exception);
 -      } else {
 -        return scope.Close(String::New(""));
 -      }
 +      out_value = NULL;
 +      if (r == 0) return ThrowCryptoTypeError(ERR_get_error());
      }
  
 -    if (args.Length() == 0 || !args[0]->IsString()) {
 -      outString = Encode(out_value, out_len, BINARY);
 -    } else {
 -      enum encoding enc = ParseEncoding(args[0]);
 -      if (enc == UTF8) {
 -        // See if we have any overhang from last utf8 partial ending
 -        if (cipher->incomplete_utf8!=NULL) {
 -          char* complete_out = new char[cipher->incomplete_utf8_len + out_len];
 -          memcpy(complete_out, cipher->incomplete_utf8, cipher->incomplete_utf8_len);
 -          memcpy((char *)complete_out+cipher->incomplete_utf8_len, out_value, out_len);
 -
 -          delete [] cipher->incomplete_utf8;
 -          cipher->incomplete_utf8=NULL;
 -
 -          outString = Encode(complete_out, cipher->incomplete_utf8_len+out_len, enc);
 -          delete [] complete_out;
 -        } else {
 -          outString = Encode(out_value, out_len, enc);
 -        }
 -      } else {
 -        outString = Encode(out_value, out_len, enc);
 -      }
 -    }
 +    outString = Encode(out_value, out_len, BUFFER);
      delete [] out_value;
      return scope.Close(outString);
    }
@@@ -800,68 -622,59 +800,86 @@@ assert.strictEqual(rsaVerify.verify(rsa
  //
  // Test PBKDF2 with RFC 6070 test vectors (except #4)
  //
 -crypto.pbkdf2('password', 'salt', 1, 20, function(err, result) {
 -  assert.equal(result,
 -               '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' +
 -               '\xaf\x60\x12\x06\x2f\xe0\x37\xa6',
 -               'pbkdf1 test vector 1');
 -});
 +function testPBKDF2(password, salt, iterations, keylen, expected) {
 +  var actual = crypto.pbkdf2Sync(password, salt, iterations, keylen);
 +  assert.equal(actual.toString('binary'), expected);
  
 -crypto.pbkdf2('password', 'salt', 2, 20, function(err, result) {
 -  assert.equal(result,
 -               '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' +
 -               '\xce\x1d\x41\xf0\xd8\xde\x89\x57',
 -               'pbkdf1 test vector 2');
 -});
 +  crypto.pbkdf2(password, salt, iterations, keylen, function(err, actual) {
 +    assert.equal(actual.toString('binary'), expected);
 +  });
 +}
  
 -crypto.pbkdf2('password', 'salt', 4096, 20, function(err, result) {
 -  assert.equal(result,
 -               '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' +
 -               '\xf7\x21\xd0\x65\xa4\x29\xc1',
 -               'pbkdf1 test vector 3');
 -});
  
 -crypto.pbkdf2(
 -    'passwordPASSWORDpassword',
 -    'saltSALTsaltSALTsaltSALTsaltSALTsalt',
 -    4096,
 -    25, function(err, result) {
 -      assert.equal(result,
 -                   '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' +
 -                   '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38',
 -                   'pbkdf1 test vector 5');
 -    });
 -
 -crypto.pbkdf2('pass\0word', 'sa\0lt', 4096, 16, function(err, result) {
 -  assert.equal(result,
 -               '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' +
 -               '\x25\xe0\xc3',
 -               'pbkdf1 test vector 6');
 -});
 +testPBKDF2('password', 'salt', 1, 20,
 +           '\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24' +
 +           '\xaf\x60\x12\x06\x2f\xe0\x37\xa6');
 +
 +testPBKDF2('password', 'salt', 2, 20,
 +           '\xea\x6c\x01\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a' +
 +           '\xce\x1d\x41\xf0\xd8\xde\x89\x57');
 +
 +testPBKDF2('password', 'salt', 4096, 20,
 +           '\x4b\x00\x79\x01\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26' +
 +           '\xf7\x21\xd0\x65\xa4\x29\xc1');
 +
 +testPBKDF2('passwordPASSWORDpassword',
 +           'saltSALTsaltSALTsaltSALTsaltSALTsalt',
 +           4096,
 +           25,
 +           '\x3d\x2e\xec\x4f\xe4\x1c\x84\x9b\x80\xc8\xd8\x36\x62' +
 +           '\xc0\xe4\x4a\x8b\x29\x1a\x96\x4c\xf2\xf0\x70\x38');
 +
 +testPBKDF2('pass\0word', 'sa\0lt', 4096, 16,
 +           '\x56\xfa\x6a\xa7\x55\x48\x09\x9d\xcc\x37\xd7\xf0\x34' +
 +           '\x25\xe0\xc3');
 +
 +function assertSorted(list) {
 +  for (var i = 0, k = list.length - 1; i < k; ++i) {
 +    var a = list[i + 0];
 +    var b = list[i + 1];
 +    assert(a <= b);
 +  }
 +}
 +
 +// Assume that we have at least AES256-SHA.
 +assert.notEqual(0, crypto.getCiphers());
 +assert.notEqual(-1, crypto.getCiphers().indexOf('AES256-SHA'));
 +assertSorted(crypto.getCiphers());
 +
 +// Assert that we have sha and sha1 but not SHA and SHA1.
 +assert.notEqual(0, crypto.getHashes());
 +assert.notEqual(-1, crypto.getHashes().indexOf('sha1'));
 +assert.notEqual(-1, crypto.getHashes().indexOf('sha'));
 +assert.equal(-1, crypto.getHashes().indexOf('SHA1'));
 +assert.equal(-1, crypto.getHashes().indexOf('SHA'));
 +assertSorted(crypto.getHashes());
 +
 +(function() {
 +  var c = crypto.createDecipher('aes-128-ecb', '');
 +  assert.throws(function() { c.final('utf8') }, /invalid public key/);
 +})();
 +
 +// Base64 padding regression test, see #4837.
 +(function() {
 +  var c = crypto.createCipher('aes-256-cbc', 'secret');
 +  var s = c.update('test', 'utf8', 'base64') + c.final('base64');
 +  assert.equal(s, '375oxUQCIocvxmC5At+rvA==');
 +})();
+ // Error path should not leak memory (check with valgrind).
+ assert.throws(function() {
+   crypto.pbkdf2('password', 'salt', 1, 20, null);
+ });
+ // Calling Cipher.final() or Decipher.final() twice should error but
+ // not assert. See #4886.
+ (function() {
+   var c = crypto.createCipher('aes-256-cbc', 'secret');
+   try { c.final('xxx') } catch (e) { /* Ignore. */ }
+   try { c.final('xxx') } catch (e) { /* Ignore. */ }
+   try { c.final('xxx') } catch (e) { /* Ignore. */ }
+   var d = crypto.createDecipher('aes-256-cbc', 'secret');
+   try { d.final('xxx') } catch (e) { /* Ignore. */ }
+   try { d.final('xxx') } catch (e) { /* Ignore. */ }
+   try { d.final('xxx') } catch (e) { /* Ignore. */ }
+ })();
Simple merge