From 92b6417098371259730c00360979101ce38cbe12 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 14 Dec 2013 15:28:07 +0400 Subject: [PATCH] crypto: introduce .setEngine(engine, [flags]) --- deps/openssl/openssl.gyp | 19 ++++++++++++-- doc/api/crypto.markdown | 24 ++++++++++++++++++ lib/crypto.js | 16 ++++++++++++ src/node_constants.cc | 55 ++++++++++++++++++++++++++++++++++++++++ src/node_crypto.cc | 50 ++++++++++++++++++++++++++++++++++++ src/node_crypto.h | 6 +++++ 6 files changed, 168 insertions(+), 2 deletions(-) diff --git a/deps/openssl/openssl.gyp b/deps/openssl/openssl.gyp index 1775b774ccf..b3ae0041033 100644 --- a/deps/openssl/openssl.gyp +++ b/deps/openssl/openssl.gyp @@ -928,7 +928,15 @@ '-lgdi32.lib', '-luser32.lib', ] - } + }, + 'defines': [ + 'DSO_WIN32', + ], + }, { + 'defines': [ + 'DSO_DLFCN', + 'HAVE_DLFCN_H' + ], }], ['target_arch=="arm"', { 'sources': ['openssl/crypto/armcap.c'], @@ -1028,7 +1036,14 @@ '-luser32.lib', ], }, - }] + }], + [ 'OS in "linux android"', { + 'link_settings': { + 'libraries': [ + '-ldl', + ], + }, + }], ] } ], diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index 29507387d66..35d4c39f413 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -12,6 +12,30 @@ It also offers a set of wrappers for OpenSSL's hash, hmac, cipher, decipher, sign and verify methods. +## crypto.setEngine(engine, [flags]) + +Load and set engine for some/all OpenSSL functions (selected by flags). + +`engine` could be either an id or a path to the to the engine's shared library. + +`flags` is optional and has `ENGINE_METHOD_ALL` value by default. It could take +one of or mix of following flags (defined in `constants` module): + +* `ENGINE_METHOD_RSA` +* `ENGINE_METHOD_DSA` +* `ENGINE_METHOD_DH` +* `ENGINE_METHOD_RAND` +* `ENGINE_METHOD_ECDH` +* `ENGINE_METHOD_ECDSA` +* `ENGINE_METHOD_CIPHERS` +* `ENGINE_METHOD_DIGESTS` +* `ENGINE_METHOD_STORE` +* `ENGINE_METHOD_PKEY_METH` +* `ENGINE_METHOD_PKEY_ASN1_METH` +* `ENGINE_METHOD_ALL` +* `ENGINE_METHOD_NONE` + + ## crypto.getCiphers() Returns an array with the names of the supported ciphers. diff --git a/lib/crypto.js b/lib/crypto.js index add6a79d78e..33baa40467b 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -35,6 +35,7 @@ try { throw new Error('node.js not compiled with openssl crypto support.'); } +var constants = require('constants'); var stream = require('stream'); var util = require('util'); @@ -621,6 +622,21 @@ Certificate.prototype.exportChallenge = function(object, encoding) { }; +exports.setEngine = function setEngine(id, flags) { + if (!util.isString(id)) + throw new TypeError('id should be a string'); + + if (flags && !util.isNumber(flags)) + throw new TypeError('flags should be a number, if present'); + flags = flags >>> 0; + + // Use provided engine for everything by default + if (flags === 0) + flags = constants.ENGINE_METHOD_ALL; + + return binding.setEngine(id, flags); +}; + exports.randomBytes = randomBytes; exports.pseudoRandomBytes = pseudoRandomBytes; diff --git a/src/node_constants.cc b/src/node_constants.cc index 11c67ae5193..81d4124c9fc 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -34,6 +34,9 @@ #if HAVE_OPENSSL # include +# ifndef OPENSSL_NO_ENGINE +# include +# endif // !OPENSSL_NO_ENGINE #endif namespace node { @@ -875,6 +878,58 @@ void DefineOpenSSLConstants(Handle target) { NODE_DEFINE_CONSTANT(target, SSL_OP_TLS_ROLLBACK_BUG); #endif +# ifndef OPENSSL_NO_ENGINE + +# ifdef ENGINE_METHOD_DSA + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_DSA); +# endif + +# ifdef ENGINE_METHOD_DH + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_DH); +# endif + +# ifdef ENGINE_METHOD_RAND + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_RAND); +# endif + +# ifdef ENGINE_METHOD_ECDH + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_ECDH); +# endif + +# ifdef ENGINE_METHOD_ECDSA + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_ECDSA); +# endif + +# ifdef ENGINE_METHOD_CIPHERS + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_CIPHERS); +# endif + +# ifdef ENGINE_METHOD_DIGESTS + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_DIGESTS); +# endif + +# ifdef ENGINE_METHOD_STORE + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_STORE); +# endif + +# ifdef ENGINE_METHOD_PKEY_METHS + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_PKEY_METHS); +# endif + +# ifdef ENGINE_METHOD_PKEY_ASN1_METHS + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_PKEY_ASN1_METHS); +# endif + +# ifdef ENGINE_METHOD_ALL + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_ALL); +# endif + +# ifdef ENGINE_METHOD_NONE + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_NONE); +# endif + +# endif // !OPENSSL_NO_ENGINE + #ifdef OPENSSL_NPN_NEGOTIATED #define NPN_ENABLED 1 NODE_DEFINE_CONSTANT(target, NPN_ENABLED); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 753558b9019..e1eae7f2fdd 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -4069,9 +4069,56 @@ void InitCryptoOnce() { sk_SSL_COMP_zero(comp_methods); assert(sk_SSL_COMP_num(comp_methods) == 0); #endif + +#ifndef OPENSSL_NO_ENGINE + ERR_load_ENGINE_strings(); + ENGINE_load_builtin_engines(); +#endif // !OPENSSL_NO_ENGINE } +#ifndef OPENSSL_NO_ENGINE +void SetEngine(const FunctionCallbackInfo& args) { + CHECK(args.Length() >= 2 && args[0]->IsString()); + unsigned int flags = args[1]->Uint32Value(); + + ClearErrorOnReturn clear_error_on_return; + (void) &clear_error_on_return; // Silence compiler warning. + + const String::Utf8Value engine_id(args[0]); + ENGINE* engine = ENGINE_by_id(*engine_id); + + // Engine not found, try loading dynamically + if (engine == NULL) { + engine = ENGINE_by_id("dynamic"); + if (engine != NULL) { + if (!ENGINE_ctrl_cmd_string(engine, "SO_PATH", *engine_id, 0) || + !ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0)) { + ENGINE_free(engine); + engine = NULL; + } + } + } + + if (engine == NULL) { + int err = ERR_get_error(); + if (err == 0) { + char tmp[1024]; + snprintf(tmp, sizeof(tmp), "Engine \"%s\" was not found", *engine_id); + return ThrowError(tmp); + } else { + return ThrowCryptoError(err); + } + } + + int r = ENGINE_set_default(engine, flags); + ENGINE_free(engine); + if (r == 0) + return ThrowCryptoError(ERR_get_error()); +} +#endif // !OPENSSL_NO_ENGINE + + // FIXME(bnoordhuis) Handle global init correctly. void InitCrypto(Handle target, Handle unused, @@ -4090,6 +4137,9 @@ void InitCrypto(Handle target, Verify::Initialize(env, target); Certificate::Initialize(target); +#ifndef OPENSSL_NO_ENGINE + NODE_SET_METHOD(target, "setEngine", SetEngine); +#endif // !OPENSSL_NO_ENGINE NODE_SET_METHOD(target, "PBKDF2", PBKDF2); NODE_SET_METHOD(target, "randomBytes", RandomBytes); NODE_SET_METHOD(target, "pseudoRandomBytes", RandomBytes); diff --git a/src/node_crypto.h b/src/node_crypto.h index ed864297932..2357ca4a2d8 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -39,6 +39,9 @@ #include "v8.h" #include +#ifndef OPENSSL_NO_ENGINE +# include +#endif // !OPENSSL_NO_ENGINE #include #include #include @@ -574,6 +577,9 @@ class Certificate : public AsyncWrap { }; bool EntropySource(unsigned char* buffer, size_t length); +#ifndef OPENSSL_NO_ENGINE +void SetEngine(const v8::FunctionCallbackInfo& args); +#endif // !OPENSSL_NO_ENGINE void InitCrypto(v8::Handle target); } // namespace crypto