crypto: make getCiphers() return non-SSL ciphers
authorBen Noordhuis <info@bnoordhuis.nl>
Mon, 18 Mar 2013 23:16:55 +0000 (00:16 +0100)
committerBen Noordhuis <info@bnoordhuis.nl>
Mon, 25 Mar 2013 17:42:07 +0000 (18:42 +0100)
Commit f53441a added crypto.getCiphers() as a function that returns the
names of SSL ciphers.

Commit 14a6c4e then added crypto.getHashes(), which returns the names of
digest algorithms, but that creates a subtle inconsistency: the return
values of crypto.getHashes() are valid arguments to crypto.createHash()
but that is not true for crypto.getCiphers() - the returned values are
only valid for SSL/TLS functions.

Rectify that by adding tls.getCiphers() and making crypto.getCiphers()
return proper cipher names.

doc/api/crypto.markdown
doc/api/tls.markdown
lib/crypto.js
lib/tls.js
src/node_crypto.cc
test/simple/test-crypto.js

index 7cc4bdd..27b0362 100644 (file)
@@ -19,7 +19,7 @@ Returns an array with the names of the supported ciphers.
 Example:
 
     var ciphers = crypto.getCiphers();
-    console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...]
+    console.log(ciphers); // ['AES-128-CBC', 'AES-128-CBC-HMAC-SHA1', ...]
 
 
 ## crypto.getHashes()
index 28bc056..f89de22 100644 (file)
@@ -76,6 +76,16 @@ handshake extensions allowing you:
     certificates.
 
 
+## tls.getCiphers()
+
+Returns an array with the names of the supported SSL ciphers.
+
+Example:
+
+    var ciphers = tls.getCiphers();
+    console.log(ciphers); // ['AES128-SHA', 'AES256-SHA', ...]
+
+
 ## tls.createServer(options, [secureConnectionListener])
 
 Creates a new [tls.Server][].  The `connectionListener` argument is
index 9c7dd64..94c9569 100644 (file)
@@ -576,21 +576,23 @@ exports.prng = pseudoRandomBytes;
 
 
 exports.getCiphers = function() {
-  return getCiphers.call(null, arguments).sort();
+  return filterDuplicates(getCiphers.call(null, arguments));
 };
 
 
 exports.getHashes = function() {
-  var names = getHashes.call(null, arguments);
+  return filterDuplicates(getHashes.call(null, arguments));
 
+};
+
+
+function filterDuplicates(names) {
   // Drop all-caps names in favor of their lowercase aliases,
   // for example, 'sha1' instead of 'SHA1'.
   var ctx = {};
-  names = names.forEach(function(name) {
+  names.forEach(function(name) {
     if (/^[0-9A-Z\-]+$/.test(name)) name = name.toLowerCase();
     ctx[name] = true;
   });
-  names = Object.getOwnPropertyNames(ctx);
-
-  return names.sort();
-};
+  return Object.getOwnPropertyNames(ctx).sort();
+}
index a7908f7..df2afec 100644 (file)
@@ -40,6 +40,17 @@ exports.CLIENT_RENEG_WINDOW = 600;
 
 exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024;
 
+exports.getCiphers = function() {
+  var names = process.binding('crypto').getSSLCiphers();
+  // Drop all-caps names in favor of their lowercase aliases,
+  var ctx = {};
+  names.forEach(function(name) {
+    if (/^[0-9A-Z\-]+$/.test(name)) name = name.toLowerCase();
+    ctx[name] = true;
+  });
+  return Object.getOwnPropertyNames(ctx).sort();
+};
+
 
 var debug;
 if (process.env.NODE_DEBUG && /tls/.test(process.env.NODE_DEBUG)) {
index 2df4573..c53d2ce 100644 (file)
@@ -3948,7 +3948,7 @@ Handle<Value> RandomBytes(const Arguments& args) {
 }
 
 
-Handle<Value> GetCiphers(const Arguments& args) {
+Handle<Value> GetSSLCiphers(const Arguments& args) {
   HandleScope scope;
 
   SSL_CTX* ctx = SSL_CTX_new(TLSv1_server_method());
@@ -3977,19 +3977,28 @@ Handle<Value> GetCiphers(const Arguments& args) {
 }
 
 
-static void add_hash_to_array(const EVP_MD* md,
-                              const char* from,
-                              const char* to,
-                              void* arg) {
+template <class TypeName>
+static void array_push_back(const TypeName* md,
+                            const char* from,
+                            const char* to,
+                            void* arg) {
   Local<Array>& arr = *static_cast<Local<Array>*>(arg);
   arr->Set(arr->Length(), String::New(from));
 }
 
 
+Handle<Value> GetCiphers(const Arguments& args) {
+  HandleScope scope;
+  Local<Array> arr = Array::New();
+  EVP_CIPHER_do_all_sorted(array_push_back<EVP_CIPHER>, &arr);
+  return scope.Close(arr);
+}
+
+
 Handle<Value> GetHashes(const Arguments& args) {
   HandleScope scope;
   Local<Array> arr = Array::New();
-  EVP_MD_do_all_sorted(add_hash_to_array, &arr);
+  EVP_MD_do_all_sorted(array_push_back<EVP_MD>, &arr);
   return scope.Close(arr);
 }
 
@@ -4033,6 +4042,7 @@ void InitCrypto(Handle<Object> target) {
   NODE_SET_METHOD(target, "PBKDF2", PBKDF2);
   NODE_SET_METHOD(target, "randomBytes", RandomBytes<false>);
   NODE_SET_METHOD(target, "pseudoRandomBytes", RandomBytes<true>);
+  NODE_SET_METHOD(target, "getSSLCiphers", GetSSLCiphers);
   NODE_SET_METHOD(target, "getCiphers", GetCiphers);
   NODE_SET_METHOD(target, "getHashes", GetHashes);
 
index 4a7c456..e17f2d5 100644 (file)
@@ -834,20 +834,24 @@ testPBKDF2('pass\0word', 'sa\0lt', 4096, 16,
            '\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);
-  }
+  assert.deepEqual(list, list.sort());
 }
 
-// Assume that we have at least AES256-SHA.
-assert.notEqual(0, crypto.getCiphers());
-assert.notEqual(-1, crypto.getCiphers().indexOf('AES256-SHA'));
+// Assume that we have at least AES-128-CBC.
+assert.notEqual(0, crypto.getCiphers().length);
+assert.notEqual(-1, crypto.getCiphers().indexOf('aes-128-cbc'));
+assert.equal(-1, crypto.getCiphers().indexOf('AES-128-CBC'));
 assertSorted(crypto.getCiphers());
 
+// Assume that we have at least AES256-SHA.
+var tls = require('tls');
+assert.notEqual(0, tls.getCiphers().length);
+assert.notEqual(-1, tls.getCiphers().indexOf('aes256-sha'));
+assert.equal(-1, tls.getCiphers().indexOf('AES256-SHA'));
+assertSorted(tls.getCiphers());
+
 // Assert that we have sha and sha1 but not SHA and SHA1.
-assert.notEqual(0, crypto.getHashes());
+assert.notEqual(0, crypto.getHashes().length);
 assert.notEqual(-1, crypto.getHashes().indexOf('sha1'));
 assert.notEqual(-1, crypto.getHashes().indexOf('sha'));
 assert.equal(-1, crypto.getHashes().indexOf('SHA1'));