From: Ben Noordhuis Date: Tue, 30 Jul 2013 13:19:48 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/v0.10' X-Git-Tag: v0.11.5~54 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b8c04b921b626edd4201f805d0feb384c8e91ea7;p=platform%2Fupstream%2Fnodejs.git Merge remote-tracking branch 'origin/v0.10' Conflicts: AUTHORS ChangeLog deps/uv/ChangeLog deps/uv/src/version.c deps/uv/src/win/fs.c src/node.cc src/node_crypto.cc src/node_os.cc src/node_version.h --- b8c04b921b626edd4201f805d0feb384c8e91ea7 diff --cc AUTHORS index 7bf4393,a063d87..4b7f00c --- a/AUTHORS +++ b/AUTHORS @@@ -431,12 -431,8 +431,13 @@@ JeongHoon Byun Alexey Kupershtokh Benjamin Ruston +Manav Rathi +Marcin Kostrzewa +Suwon Chae +David Braun Mitar Milutinovic Michael Hart ++Jeff Barczewski Andrew Hart Rafael Garcia Tobias Müllerleile @@@ -461,7 -455,5 +462,7 @@@ Daniel G. Taylor Veres Lajos Yuan Chuan +Krzysztof Chrapka +Linus Mårtensson Peter Rust - Jeff Barczewski + Shuan Wang diff --cc ChangeLog index b3d8b49,db902bc..3d6570f --- a/ChangeLog +++ b/ChangeLog @@@ -1,184 -1,27 +1,208 @@@ + 2013.07.25, Version 0.10.15 (Stable) + + * src: fix process.getuid() return value (Ben Noordhuis) + + + 2013.07.25, Version 0.10.14 (Stable), fdf57f811f9683a4ec49a74dc7226517e32e6c9d + + * uv: Upgrade to v0.10.13 + + * npm: Upgrade to v1.3.5 + + * os: Don't report negative times in cpu info (Ben Noordhuis) + + * fs: Handle large UID and GID (Ben Noordhuis) + + * url: Fix edge-case when protocol is non-lowercase (Shuan Wang) + + * doc: Streams API Doc Rewrite (isaacs) + + * node: call MakeDomainCallback in all domain cases (Trevor Norris) + + * crypto: fix memory leak in LoadPKCS12 (Fedor Indutny) + + +2013.07.12, Version 0.11.4 (Unstable) + +* npm: Upgrade to 1.3.4 + +* v8: Upgrade to v3.20.2 + +* c-ares: Upgrade to piscisaureus/cares@805d153 + +* timers: setImmediate process full queue each turn (Ben Noordhuis) + +* http: Add agent.get/request methods (isaacs) + +* http: Proper KeepAlive behavior (isaacs) + +* configure: fix the --without-ssl option (Nathan Rajlich) + +* buffer: propagate originating parent (Trevor Norris) + +* tls_wrap: return Error not throw for missing cert (Timothy J Fontaine) + +* src: enable native v8 typed arrays (Ben Noordhuis) + +* stream: objectMode transform should allow falsey values (Jeff Barczewski) + +* slab_allocator: remove SlabAllocator (Trevor Norris) + +* crypto: fix memory leak in LoadPKCS12 (Fedor Indutny) + +* tls: export TLSSocket (Fedor Indutny) + +* zlib: allow changing of level and strategy (Brian White) + +* zlib: allow custom flush type for flush() (Brian White) + + +2013.06.26, Version 0.11.3 (Unstable), 38c0c47bbe280ddc42054418091571e532d82a1e + +* uv: Upgrade to v0.11.5 + +* c-ares: upgrade to 1.10.0 + +* v8: upgrade to v3.19.13 + +* punycode: update to v1.2.3 (Mathias Bynens) + +* debugger: break on uncaught exception (Miroslav Bajtos) + +* child_process: emit 'disconnect' asynchronously (Ben Noordhuis) + +* dtrace: enable uv's probes if enabled (Timothy J Fontaine) + +* dtrace: unify dtrace and systemtap interfaces (Timothy J Fontaine) + +* buffer: New API for backing data store (Trevor Norris) + +* buffer: return `this` in fill() for chainability (Brian White) + +* build: fix include order for building on windows (Timothy J Fontaine) + +* build: add android support (Linus Mårtensson) + +* readline: strip ctrl chars for prompt width calc (Krzysztof Chrapka) + +* tls: introduce TLSSocket based on tls_wrap binding (Fedor Indutny) + +* tls: add localAddress and localPort properties (Ben Noordhuis) + +* crypto: free excessive memory in NodeBIO (Fedor Indutny) + +* process: remove maxTickDepth (Trevor Norris) + +* timers: use uv_now instead of Date.now (Timothy J Fontaine) + +* util: Add debuglog, deprecate console lookalikes (isaacs) + +* module: use path.sep instead of a custom solution (Robert Kowalski) + +* http: don't escape request path, reject bad chars (Ben Noordhuis) + +* net: emit dns 'lookup' event before connect (Ben Noordhuis) + +* dns: add getServers and setServers (Timothy J Fontaine) + + +2013.05.13, Version 0.11.2 (Unstable), 5d3dc0e4c3369dfb00b7b13e08936c2e652fa696 + +* uv: Upgrade to 0.11.2 + +* V8: Upgrade to 3.19.0 + +* npm: Upgrade to 1.2.21 + +* build: Makefile should respect configure --prefix (Timothy J Fontaine) + +* cluster: use round-robin load balancing (Ben Noordhuis) + +* debugger, cluster: each worker has new debug port (Miroslav Bajtoš) + +* debugger: `restart` with custom debug port (Miroslav Bajtoš) + +* debugger: breakpoints in scripts not loaded yet (Miroslav Bajtoš) + +* event: EventEmitter#setMaxListeners() returns this (Sam Roberts) + +* events: add EventEmitter.defaultMaxListeners (Ben Noordhuis) + +* install: Support $(PREFIX) install target directory prefix (Olof Johansson) + +* os: Include netmask in os.networkInterfaces() (Ben Kelly) + +* path: add path.isAbsolute(path) (Ryan Doenges) + +* stream: Guarantee ordering of 'finish' event (isaacs) + +* streams: introduce .cork/.uncork/._writev (Fedor Indutny) + +* vm: add support for timeout argument (Andrew Paprocki) + + +2013.04.19, Version 0.11.1 (Unstable), 4babd2b46ebf9fbea2c9946af5cfae25a33b2b22 + +* V8: upgrade to 3.18.0 + +* uv: Upgrade to v0.11.1 + +* http: split into multiple separate modules (Timothy J Fontaine) + +* http: escape unsafe characters in request path (Ben Noordhuis) + +* url: Escape all unwise characters (isaacs) + +* build: depend on v8 postmortem-metadata if enabled (Paddy Byers) + +* etw: update prototypes to match dtrace provider (Timothy J Fontaine) + +* buffer: change output of Buffer.prototype.toJSON() (David Braun) + +* dtrace: actually use the _handle.fd value (Timothy J Fontaine) + +* dtrace: pass more arguments to probes (Dave Pacheco) + +* build: allow building with dtrace on osx (Dave Pacheco) + +* zlib: allow passing options to convenience methods (Kyle Robinson Young) + + +2013.03.28, Version 0.11.0 (Unstable), bce38b3d74e64fcb7d04a2dd551151da6168cdc5 + +* V8: update to 3.17.13 + +* os: use %SystemRoot% or %windir% in os.tmpdir() (Suwon Chae) + +* util: fix util.inspect() line width calculation (Marcin Kostrzewa) + +* buffer: remove _charsWritten (Trevor Norris) + +* fs: uv_[fl]stat now reports subsecond resolution (Timothy J Fontaine) + +* fs: Throw if error raised and missing callback (bnoordhuis) + +* tls: expose SSL_CTX_set_timeout via tls.createServer (Manav Rathi) + +* tls: remove harmful unnecessary bounds checking (Marcel Laverdet) + +* buffer: write ascii strings using WriteOneByte (Trevor Norris) + +* dtrace: fix generation of v8 constants on freebsd (Fedor Indutny) + +* dtrace: x64 ustack helper (Fedor Indutny) + +* readline: handle wide characters properly (Nao Iizuka) + +* repl: Use a domain to catch async errors safely (isaacs) + +* repl: emit 'reset' event when context is reset (Sami Samhuri) + +* util: custom `inspect()` method may return an Object (Nathan Rajlich) + +* console: `console.dir()` bypasses inspect() methods (Nathan Rajlich) + + 2013.07.09, Version 0.10.13 (Stable), e32660a984427d46af6a144983cf7b8045b7299c * uv: Upgrade to v0.10.12 diff --cc src/node_crypto.cc index 608601a,02b0660..b978784 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@@ -2065,1175 -2058,1736 +2065,1190 @@@ void Connection::SetSNICallback(const F #endif -class Cipher : public ObjectWrap { - public: - static void Initialize (v8::Handle target) { - HandleScope scope; +void CipherBase::Initialize(Handle target) { + HandleScope scope(node_isolate); - Local t = FunctionTemplate::New(New); + Local t = FunctionTemplate::New(New); - t->InstanceTemplate()->SetInternalFieldCount(1); + t->InstanceTemplate()->SetInternalFieldCount(1); - NODE_SET_PROTOTYPE_METHOD(t, "init", CipherInit); - NODE_SET_PROTOTYPE_METHOD(t, "initiv", CipherInitIv); - NODE_SET_PROTOTYPE_METHOD(t, "update", CipherUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding); - NODE_SET_PROTOTYPE_METHOD(t, "final", CipherFinal); + NODE_SET_PROTOTYPE_METHOD(t, "init", Init); + NODE_SET_PROTOTYPE_METHOD(t, "initiv", InitIv); + NODE_SET_PROTOTYPE_METHOD(t, "update", Update); + NODE_SET_PROTOTYPE_METHOD(t, "final", Final); + NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding); - target->Set(String::NewSymbol("Cipher"), t->GetFunction()); - } + target->Set(String::NewSymbol("CipherBase"), t->GetFunction()); +} - bool CipherInit(char* cipherType, char* key_buf, int key_buf_len) { - cipher = EVP_get_cipherbyname(cipherType); - if(!cipher) { - fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType); - return false; - } +void CipherBase::New(const FunctionCallbackInfo& args) { + assert(args.IsConstructCall() == true); + HandleScope scope(node_isolate); + CipherBase* cipher = new CipherBase(args[0]->IsTrue() ? kCipher : kDecipher); + cipher->Wrap(args.This()); +} - unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH]; - int key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL, - (unsigned char*) key_buf, key_buf_len, 1, key, iv); - EVP_CIPHER_CTX_init(&ctx); - EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true); - if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) { - fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len); - EVP_CIPHER_CTX_cleanup(&ctx); - return false; - } - EVP_CipherInit_ex(&ctx, NULL, NULL, - (unsigned char*)key, - (unsigned char*)iv, true); - initialised_ = true; - return true; - } - - - bool CipherInitIv(char* cipherType, - char* key, - int key_len, - char* iv, - int iv_len) { - cipher = EVP_get_cipherbyname(cipherType); - if(!cipher) { - fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType); - return false; - } - /* OpenSSL versions up to 0.9.8l failed to return the correct - iv_length (0) for ECB ciphers */ - if (EVP_CIPHER_iv_length(cipher) != iv_len && - !(EVP_CIPHER_mode(cipher) == EVP_CIPH_ECB_MODE && iv_len == 0)) { - fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len); - return false; - } - EVP_CIPHER_CTX_init(&ctx); - EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, NULL, true); - if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) { - fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len); - EVP_CIPHER_CTX_cleanup(&ctx); - return false; - } - EVP_CipherInit_ex(&ctx, NULL, NULL, - (unsigned char*)key, - (unsigned char*)iv, true); - initialised_ = true; - return true; - } +void CipherBase::Init(char* cipher_type, char* key_buf, int key_buf_len) { + HandleScope scope(node_isolate); - int CipherUpdate(char* data, int len, unsigned char** out, int* out_len) { - if (!initialised_) return 0; - *out_len = len+EVP_CIPHER_CTX_block_size(&ctx); - *out = new unsigned char[*out_len]; - return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len); + assert(cipher_ == NULL); + cipher_ = EVP_get_cipherbyname(cipher_type); + if (cipher_ == NULL) { + return ThrowError("Unknown cipher"); } - int SetAutoPadding(bool auto_padding) { - if (!initialised_) return 0; - return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0); - } + unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; - int CipherFinal(unsigned char** out, int *out_len) { - if (!initialised_) return 0; - *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)]; - int r = EVP_CipherFinal_ex(&ctx,*out, out_len); - EVP_CIPHER_CTX_cleanup(&ctx); - initialised_ = false; - return r; + int key_len = EVP_BytesToKey(cipher_, + EVP_md5(), + NULL, + reinterpret_cast(key_buf), + key_buf_len, + 1, + key, + iv); + + EVP_CIPHER_CTX_init(&ctx_); + EVP_CipherInit_ex(&ctx_, cipher_, NULL, NULL, NULL, kind_ == kCipher); + if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) { + EVP_CIPHER_CTX_cleanup(&ctx_); + return ThrowError("Invalid key length"); } + EVP_CipherInit_ex(&ctx_, + NULL, + NULL, + reinterpret_cast(key), + reinterpret_cast(iv), + kind_ == kCipher); + initialised_ = true; +} + - protected: +void CipherBase::Init(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - static Handle New(const Arguments& args) { - HandleScope scope; + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); - Cipher *cipher = new Cipher(); - cipher->Wrap(args.This()); - return args.This(); + if (args.Length() < 2 || + !(args[0]->IsString() && Buffer::HasInstance(args[1]))) { + return ThrowError("Must give cipher-type, key"); } - static Handle CipherInit(const Arguments& args) { - HandleScope scope; - - Cipher *cipher = ObjectWrap::Unwrap(args.This()); + String::Utf8Value cipher_type(args[0]); + char* key_buf = Buffer::Data(args[1]); + ssize_t key_buf_len = Buffer::Length(args[1]); + cipher->Init(*cipher_type, key_buf, key_buf_len); +} - if (args.Length() <= 1 - || !args[0]->IsString() - || !(args[1]->IsString() || Buffer::HasInstance(args[1]))) - { - return ThrowException(Exception::Error(String::New( - "Must give cipher-type, key"))); - } - ASSERT_IS_BUFFER(args[1]); - ssize_t key_buf_len = Buffer::Length(args[1]); +void CipherBase::InitIv(char* cipher_type, + char* key, + int key_len, + char* iv, + int iv_len) { + HandleScope scope(node_isolate); - if (key_buf_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } + cipher_ = EVP_get_cipherbyname(cipher_type); + if (cipher_ == NULL) { + return ThrowError("Unknown cipher"); + } - char* key_buf = new char[key_buf_len]; - ssize_t key_written = DecodeWrite(key_buf, key_buf_len, args[1], BINARY); - assert(key_written == key_buf_len); + /* OpenSSL versions up to 0.9.8l failed to return the correct + iv_length (0) for ECB ciphers */ + if (EVP_CIPHER_iv_length(cipher_) != iv_len && + !(EVP_CIPHER_mode(cipher_) == EVP_CIPH_ECB_MODE && iv_len == 0)) { + return ThrowError("Invalid IV length"); + } + EVP_CIPHER_CTX_init(&ctx_); + EVP_CipherInit_ex(&ctx_, cipher_, NULL, NULL, NULL, kind_ == kCipher); + if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) { + EVP_CIPHER_CTX_cleanup(&ctx_); + return ThrowError("Invalid key length"); + } - String::Utf8Value cipherType(args[0]); + EVP_CipherInit_ex(&ctx_, + NULL, + NULL, + reinterpret_cast(key), + reinterpret_cast(iv), + kind_ == kCipher); + initialised_ = true; +} - bool r = cipher->CipherInit(*cipherType, key_buf, key_buf_len); - delete [] key_buf; +void CipherBase::InitIv(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (!r) return ThrowCryptoError(ERR_get_error()); + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); - return args.This(); + if (args.Length() < 3 || !args[0]->IsString()) { + return ThrowError("Must give cipher-type, key, and iv as argument"); } + ASSERT_IS_BUFFER(args[1]); + ASSERT_IS_BUFFER(args[2]); + + String::Utf8Value cipher_type(args[0]); + ssize_t key_len = Buffer::Length(args[1]); + char* key_buf = Buffer::Data(args[1]); + ssize_t iv_len = Buffer::Length(args[2]); + char* iv_buf = Buffer::Data(args[2]); + cipher->InitIv(*cipher_type, key_buf, key_len, iv_buf, iv_len); +} + + +bool CipherBase::Update(char* data, + int len, + unsigned char** out, + int* out_len) { + if (!initialised_) return 0; + *out_len = len + EVP_CIPHER_CTX_block_size(&ctx_); + *out = new unsigned char[*out_len]; + return EVP_CipherUpdate(&ctx_, + *out, + out_len, + reinterpret_cast(data), + len); +} + + +void CipherBase::Update(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); + + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); + + ASSERT_IS_STRING_OR_BUFFER(args[0]); + + unsigned char* out = NULL; + bool r; + int out_len = 0; + + // Only copy the data if we have to, because it's a string + if (args[0]->IsString()) { ++ Local string = args[0].As(); + enum encoding encoding = ParseEncoding(args[1], BINARY); - size_t buflen = StringBytes::StorageSize(args[0], encoding); ++ if (!StringBytes::IsValidString(string, encoding)) ++ return ThrowTypeError("Bad input string"); ++ size_t buflen = StringBytes::StorageSize(string, encoding); + char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, args[0], encoding); ++ size_t written = StringBytes::Write(buf, buflen, string, encoding); + r = cipher->Update(buf, written, &out, &out_len); + delete[] buf; + } else { + char* buf = Buffer::Data(args[0]); + size_t buflen = Buffer::Length(args[0]); + r = cipher->Update(buf, buflen, &out, &out_len); + } - static Handle CipherInitIv(const Arguments& args) { - Cipher *cipher = ObjectWrap::Unwrap(args.This()); + if (!r) { + delete[] out; + return ThrowCryptoTypeError(ERR_get_error()); + } - HandleScope scope; + Local buf = Buffer::New(reinterpret_cast(out), out_len); + if (out) delete[] out; + args.GetReturnValue().Set(buf); +} - if (args.Length() <= 2 - || !args[0]->IsString() - || !(args[1]->IsString() || Buffer::HasInstance(args[1])) - || !(args[2]->IsString() || Buffer::HasInstance(args[2]))) - { - return ThrowException(Exception::Error(String::New( - "Must give cipher-type, key, and iv as argument"))); - } - ASSERT_IS_BUFFER(args[1]); - ssize_t key_len = Buffer::Length(args[1]); +bool CipherBase::SetAutoPadding(bool auto_padding) { + if (!initialised_) return false; + return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding); +} - if (key_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - ASSERT_IS_BUFFER(args[2]); - ssize_t iv_len = Buffer::Length(args[2]); +void CipherBase::SetAutoPadding(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); + cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue()); +} - if (iv_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - char* key_buf = new char[key_len]; - ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY); - assert(key_written == key_len); +bool CipherBase::Final(unsigned char** out, int *out_len) { + if (!initialised_) return false; - char* iv_buf = new char[iv_len]; - ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY); - assert(iv_written == iv_len); + *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx_)]; + bool r = EVP_CipherFinal_ex(&ctx_, *out, out_len); + EVP_CIPHER_CTX_cleanup(&ctx_); + initialised_ = false; - String::Utf8Value cipherType(args[0]); + return r; +} - bool r = cipher->CipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len); - delete [] key_buf; - delete [] iv_buf; +void CipherBase::Final(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (!r) return ThrowCryptoError(ERR_get_error()); + CipherBase* cipher = ObjectWrap::Unwrap(args.This()); - return args.This(); - } + unsigned char* out_value = NULL; + int out_len = -1; + Local outString; - static Handle CipherUpdate(const Arguments& args) { - Cipher *cipher = ObjectWrap::Unwrap(args.This()); + bool r = cipher->Final(&out_value, &out_len); - HandleScope scope; + if (out_len <= 0 || !r) { + delete[] out_value; + out_value = NULL; + out_len = 0; + if (!r) return ThrowCryptoTypeError(ERR_get_error()); + } - ASSERT_IS_STRING_OR_BUFFER(args[0]); + args.GetReturnValue().Set( + Buffer::New(reinterpret_cast(out_value), out_len)); +} - // Only copy the data if we have to, because it's a string - unsigned char* out = 0; - int out_len = 0, r; - if (args[0]->IsString()) { - Local string = args[0].As(); - enum encoding encoding = ParseEncoding(args[1], BINARY); - if (!StringBytes::IsValidString(string, encoding)) - return ThrowTypeError("Bad input string"); - size_t buflen = StringBytes::StorageSize(string, encoding); - char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, string, encoding); - r = cipher->CipherUpdate(buf, written, &out, &out_len); - delete[] buf; - } else { - char* buf = Buffer::Data(args[0]); - size_t buflen = Buffer::Length(args[0]); - r = cipher->CipherUpdate(buf, buflen, &out, &out_len); - } - if (r == 0) { - delete[] out; - return ThrowCryptoTypeError(ERR_get_error()); - } +void Hmac::Initialize(v8::Handle target) { + HandleScope scope(node_isolate); - Local outString; - outString = Encode(out, out_len, BUFFER); + Local t = FunctionTemplate::New(New); - if (out) delete[] out; + t->InstanceTemplate()->SetInternalFieldCount(1); - return scope.Close(outString); - } + NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit); + NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate); + NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest); - static Handle SetAutoPadding(const Arguments& args) { - HandleScope scope; - Cipher *cipher = ObjectWrap::Unwrap(args.This()); + target->Set(String::NewSymbol("Hmac"), t->GetFunction()); +} - cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue()); - return Undefined(); - } +void Hmac::New(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); + Hmac* hmac = new Hmac(); + hmac->Wrap(args.This()); +} - static Handle CipherFinal(const Arguments& args) { - Cipher *cipher = ObjectWrap::Unwrap(args.This()); - HandleScope scope; +void Hmac::HmacInit(char* hashType, char* key, int key_len) { + HandleScope scope(node_isolate); - unsigned char* out_value = NULL; - int out_len = -1; - Local outString ; + assert(md_ == NULL); + md_ = EVP_get_digestbyname(hashType); + if (md_ == NULL) { + return ThrowError("Unknown message digest"); + } + HMAC_CTX_init(&ctx_); + if (key_len == 0) { + HMAC_Init(&ctx_, "", 0, md_); + } else { + HMAC_Init(&ctx_, key, key_len, md_); + } + initialised_ = true; +} - int r = cipher->CipherFinal(&out_value, &out_len); - if (out_len <= 0 || r == 0) { - delete[] out_value; - out_value = NULL; - if (r == 0) return ThrowCryptoTypeError(ERR_get_error()); - } +void Hmac::HmacInit(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - outString = Encode(out_value, out_len, BUFFER); + Hmac* hmac = ObjectWrap::Unwrap(args.This()); - delete [] out_value; - return scope.Close(outString); + if (args.Length() < 2 || !args[0]->IsString()) { + return ThrowError("Must give hashtype string, key as arguments"); } - Cipher () : ObjectWrap () - { - initialised_ = false; - } + ASSERT_IS_BUFFER(args[1]); - ~Cipher () { - if (initialised_) { - EVP_CIPHER_CTX_cleanup(&ctx); - } - } + String::Utf8Value hashType(args[0]); - private: + char* buffer_data = Buffer::Data(args[1]); + size_t buffer_length = Buffer::Length(args[1]); + hmac->HmacInit(*hashType, buffer_data, buffer_length); +} - EVP_CIPHER_CTX ctx; /* coverity[member_decl] */ - const EVP_CIPHER *cipher; /* coverity[member_decl] */ - bool initialised_; -}; +bool Hmac::HmacUpdate(char* data, int len) { + if (!initialised_) return false; + HMAC_Update(&ctx_, reinterpret_cast(data), len); + return true; +} -class Decipher : public ObjectWrap { - public: - static void - Initialize (v8::Handle target) - { - HandleScope scope; +void Hmac::HmacUpdate(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - Local t = FunctionTemplate::New(New); + Hmac* hmac = ObjectWrap::Unwrap(args.This()); - t->InstanceTemplate()->SetInternalFieldCount(1); + ASSERT_IS_STRING_OR_BUFFER(args[0]); - NODE_SET_PROTOTYPE_METHOD(t, "init", DecipherInit); - NODE_SET_PROTOTYPE_METHOD(t, "initiv", DecipherInitIv); - NODE_SET_PROTOTYPE_METHOD(t, "update", DecipherUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "final", DecipherFinal); - NODE_SET_PROTOTYPE_METHOD(t, "finaltol", DecipherFinal); // remove someday - NODE_SET_PROTOTYPE_METHOD(t, "setAutoPadding", SetAutoPadding); + // Only copy the data if we have to, because it's a string + bool r; + if (args[0]->IsString()) { ++ Local string = args[0].As(); + enum encoding encoding = ParseEncoding(args[1], BINARY); - size_t buflen = StringBytes::StorageSize(args[0], encoding); ++ if (!StringBytes::IsValidString(string, encoding)) ++ return ThrowTypeError("Bad input string"); ++ size_t buflen = StringBytes::StorageSize(string, encoding); + char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, args[0], encoding); ++ size_t written = StringBytes::Write(buf, buflen, string, encoding); + r = hmac->HmacUpdate(buf, written); + delete[] buf; + } else { + char* buf = Buffer::Data(args[0]); + size_t buflen = Buffer::Length(args[0]); + r = hmac->HmacUpdate(buf, buflen); + } - target->Set(String::NewSymbol("Decipher"), t->GetFunction()); + if (!r) { + return ThrowTypeError("HmacUpdate fail"); } +} - bool DecipherInit(char* cipherType, char* key_buf, int key_buf_len) { - cipher_ = EVP_get_cipherbyname(cipherType); - if(!cipher_) { - fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType); - return false; - } +bool Hmac::HmacDigest(unsigned char** md_value, unsigned int* md_len) { + if (!initialised_) return false; + *md_value = new unsigned char[EVP_MAX_MD_SIZE]; + HMAC_Final(&ctx_, *md_value, md_len); + HMAC_CTX_cleanup(&ctx_); + initialised_ = false; + return true; +} - unsigned char key[EVP_MAX_KEY_LENGTH],iv[EVP_MAX_IV_LENGTH]; - int key_len = EVP_BytesToKey(cipher_, - EVP_md5(), - NULL, - (unsigned char*)(key_buf), - key_buf_len, - 1, - key, - iv); - - EVP_CIPHER_CTX_init(&ctx); - EVP_CipherInit_ex(&ctx, cipher_, NULL, NULL, NULL, false); - if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) { - fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len); - EVP_CIPHER_CTX_cleanup(&ctx); - return false; - } - EVP_CipherInit_ex(&ctx, NULL, NULL, - (unsigned char*)key, - (unsigned char*)iv, false); - initialised_ = true; - return true; - } - - - bool DecipherInitIv(char* cipherType, - char* key, - int key_len, - char* iv, - int iv_len) { - cipher_ = EVP_get_cipherbyname(cipherType); - if(!cipher_) { - fprintf(stderr, "node-crypto : Unknown cipher %s\n", cipherType); - return false; - } - /* OpenSSL versions up to 0.9.8l failed to return the correct - iv_length (0) for ECB ciphers */ - if (EVP_CIPHER_iv_length(cipher_) != iv_len && - !(EVP_CIPHER_mode(cipher_) == EVP_CIPH_ECB_MODE && iv_len == 0)) { - fprintf(stderr, "node-crypto : Invalid IV length %d\n", iv_len); - return false; - } - EVP_CIPHER_CTX_init(&ctx); - EVP_CipherInit_ex(&ctx, cipher_, NULL, NULL, NULL, false); - if (!EVP_CIPHER_CTX_set_key_length(&ctx, key_len)) { - fprintf(stderr, "node-crypto : Invalid key length %d\n", key_len); - EVP_CIPHER_CTX_cleanup(&ctx); - return false; - } - EVP_CipherInit_ex(&ctx, NULL, NULL, - (unsigned char*)key, - (unsigned char*)iv, false); - initialised_ = true; - return true; - } - - int DecipherUpdate(char* data, int len, unsigned char** out, int* out_len) { - if (!initialised_) { - *out_len = 0; - *out = NULL; - return 0; - } - *out_len = len+EVP_CIPHER_CTX_block_size(&ctx); - *out = new unsigned char[*out_len]; +void Hmac::HmacDigest(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); + + Hmac* hmac = ObjectWrap::Unwrap(args.This()); - return EVP_CipherUpdate(&ctx, *out, out_len, (unsigned char*)data, len); + enum encoding encoding = BUFFER; + if (args.Length() >= 1) { + encoding = ParseEncoding(args[0]->ToString(), BUFFER); } - int SetAutoPadding(bool auto_padding) { - if (!initialised_) return 0; - return EVP_CIPHER_CTX_set_padding(&ctx, auto_padding ? 1 : 0); + unsigned char* md_value = NULL; + unsigned int md_len = 0; + + bool r = hmac->HmacDigest(&md_value, &md_len); + if (!r) { + md_value = NULL; + md_len = 0; } - // coverity[alloc_arg] - int DecipherFinal(unsigned char** out, int *out_len) { - int r; + Local rc = StringBytes::Encode( + reinterpret_cast(md_value), md_len, encoding); + delete[] md_value; + args.GetReturnValue().Set(rc); +} - if (!initialised_) { - *out_len = 0; - *out = NULL; - return 0; - } - *out = new unsigned char[EVP_CIPHER_CTX_block_size(&ctx)]; - r = EVP_CipherFinal_ex(&ctx,*out,out_len); - EVP_CIPHER_CTX_cleanup(&ctx); - initialised_ = false; - return r; - } +void Hash::Initialize(v8::Handle target) { + HandleScope scope(node_isolate); + Local t = FunctionTemplate::New(New); - protected: + t->InstanceTemplate()->SetInternalFieldCount(1); - static Handle New (const Arguments& args) { - HandleScope scope; + NODE_SET_PROTOTYPE_METHOD(t, "update", HashUpdate); + NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest); - Decipher *cipher = new Decipher(); - cipher->Wrap(args.This()); - return args.This(); - } + target->Set(String::NewSymbol("Hash"), t->GetFunction()); +} - static Handle DecipherInit(const Arguments& args) { - Decipher *cipher = ObjectWrap::Unwrap(args.This()); - HandleScope scope; +void Hash::New(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (args.Length() <= 1 - || !args[0]->IsString() - || !(args[1]->IsString() || Buffer::HasInstance(args[1]))) - { - return ThrowException(Exception::Error(String::New( - "Must give cipher-type, key as argument"))); - } + if (args.Length() == 0 || !args[0]->IsString()) { + return ThrowError("Must give hashtype string as argument"); + } - ASSERT_IS_BUFFER(args[1]); - ssize_t key_len = Buffer::Length(args[1]); + String::Utf8Value hashType(args[0]); - if (key_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } + Hash* hash = new Hash(); + if (!hash->HashInit(*hashType)) { + delete hash; + return ThrowError("Digest method not supported"); + } - char* key_buf = new char[key_len]; - ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY); - assert(key_written == key_len); + hash->Wrap(args.This()); +} - String::Utf8Value cipherType(args[0]); - bool r = cipher->DecipherInit(*cipherType, key_buf,key_len); +bool Hash::HashInit(const char* hashType) { + assert(md_ == NULL); + md_ = EVP_get_digestbyname(hashType); + if (md_ == NULL) return false; + EVP_MD_CTX_init(&mdctx_); + EVP_DigestInit_ex(&mdctx_, md_, NULL); + initialised_ = true; + return true; +} - delete [] key_buf; - if (!r) { - return ThrowException(Exception::Error(String::New("DecipherInit error"))); - } +bool Hash::HashUpdate(char* data, int len) { + if (!initialised_) return false; + EVP_DigestUpdate(&mdctx_, data, len); + return true; +} - return args.This(); - } - static Handle DecipherInitIv(const Arguments& args) { - Decipher *cipher = ObjectWrap::Unwrap(args.This()); +void Hash::HashUpdate(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - HandleScope scope; + Hash* hash = ObjectWrap::Unwrap(args.This()); - if (args.Length() <= 2 - || !args[0]->IsString() - || !(args[1]->IsString() || Buffer::HasInstance(args[1])) - || !(args[2]->IsString() || Buffer::HasInstance(args[2]))) - { - return ThrowException(Exception::Error(String::New( - "Must give cipher-type, key, and iv as argument"))); - } + ASSERT_IS_STRING_OR_BUFFER(args[0]); - ASSERT_IS_BUFFER(args[1]); - ssize_t key_len = Buffer::Length(args[1]); + // Only copy the data if we have to, because it's a string + bool r; + if (args[0]->IsString()) { ++ Local string = args[0].As(); + enum encoding encoding = ParseEncoding(args[1], BINARY); - size_t buflen = StringBytes::StorageSize(args[0], encoding); ++ if (!StringBytes::IsValidString(string, encoding)) ++ return ThrowTypeError("Bad input string"); ++ size_t buflen = StringBytes::StorageSize(string, encoding); + char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, args[0], encoding); ++ size_t written = StringBytes::Write(buf, buflen, string, encoding); + r = hash->HashUpdate(buf, written); + delete[] buf; + } else { + char* buf = Buffer::Data(args[0]); + size_t buflen = Buffer::Length(args[0]); + r = hash->HashUpdate(buf, buflen); + } - if (key_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } + if (!r) { + return ThrowTypeError("HashUpdate fail"); + } +} - ASSERT_IS_BUFFER(args[2]); - ssize_t iv_len = Buffer::Length(args[2]); - if (iv_len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } +void Hash::HashDigest(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - char* key_buf = new char[key_len]; - ssize_t key_written = DecodeWrite(key_buf, key_len, args[1], BINARY); - assert(key_written == key_len); + Hash* hash = ObjectWrap::Unwrap(args.This()); - char* iv_buf = new char[iv_len]; - ssize_t iv_written = DecodeWrite(iv_buf, iv_len, args[2], BINARY); - assert(iv_written == iv_len); + if (!hash->initialised_) { + return ThrowError("Not initialized"); + } - String::Utf8Value cipherType(args[0]); + enum encoding encoding = BUFFER; + if (args.Length() >= 1) { + encoding = ParseEncoding(args[0]->ToString(), BUFFER); + } - bool r = cipher->DecipherInitIv(*cipherType, key_buf,key_len,iv_buf,iv_len); + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; - delete [] key_buf; - delete [] iv_buf; + EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len); + EVP_MD_CTX_cleanup(&hash->mdctx_); + hash->initialised_ = false; - if (!r) { - return ThrowException(Exception::Error(String::New("DecipherInitIv error"))); - } + Local rc = StringBytes::Encode( + reinterpret_cast(md_value), md_len, encoding); + args.GetReturnValue().Set(rc); +} - return args.This(); - } - static Handle DecipherUpdate(const Arguments& args) { - HandleScope scope; +void Sign::Initialize(v8::Handle target) { + HandleScope scope(node_isolate); - Decipher *cipher = ObjectWrap::Unwrap(args.This()); + Local t = FunctionTemplate::New(New); - ASSERT_IS_STRING_OR_BUFFER(args[0]); + t->InstanceTemplate()->SetInternalFieldCount(1); - // Only copy the data if we have to, because it's a string - unsigned char* out = 0; - int out_len = 0, r; - if (args[0]->IsString()) { - Local string = args[0].As(); - enum encoding encoding = ParseEncoding(args[1], BINARY); - if (!StringBytes::IsValidString(string, encoding)) - return ThrowTypeError("Bad input string"); - size_t buflen = StringBytes::StorageSize(string, encoding); - char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, string, encoding); - r = cipher->DecipherUpdate(buf, written, &out, &out_len); - delete[] buf; - } else { - char* buf = Buffer::Data(args[0]); - size_t buflen = Buffer::Length(args[0]); - r = cipher->DecipherUpdate(buf, buflen, &out, &out_len); - } + NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit); + NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate); + NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal); - if (r == 0) { - delete[] out; - return ThrowCryptoTypeError(ERR_get_error()); - } + target->Set(String::NewSymbol("Sign"), t->GetFunction()); +} + + +void Sign::New(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); + Sign* sign = new Sign(); + sign->Wrap(args.This()); +} - Local outString; - outString = Encode(out, out_len, BUFFER); - if (out) delete [] out; +void Sign::SignInit(const char* sign_type) { + HandleScope scope(node_isolate); - return scope.Close(outString); + assert(md_ == NULL); + md_ = EVP_get_digestbyname(sign_type); + if (!md_) { + return ThrowError("Uknown message digest"); } + EVP_MD_CTX_init(&mdctx_); + EVP_SignInit_ex(&mdctx_, md_, NULL); + initialised_ = true; +} + - static Handle SetAutoPadding(const Arguments& args) { - HandleScope scope; - Decipher *cipher = ObjectWrap::Unwrap(args.This()); +void Sign::SignInit(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - cipher->SetAutoPadding(args.Length() < 1 || args[0]->BooleanValue()); + Sign* sign = ObjectWrap::Unwrap(args.This()); - return Undefined(); + if (args.Length() == 0 || !args[0]->IsString()) { + return ThrowError("Must give signtype string as argument"); } - static Handle DecipherFinal(const Arguments& args) { - HandleScope scope; + String::Utf8Value sign_type(args[0]); + sign->SignInit(*sign_type); +} + - Decipher *cipher = ObjectWrap::Unwrap(args.This()); +bool Sign::SignUpdate(char* data, int len) { + if (!initialised_) return false; + EVP_SignUpdate(&mdctx_, data, len); + return true; +} - unsigned char* out_value = NULL; - int out_len = -1; - Local outString; - int r = cipher->DecipherFinal(&out_value, &out_len); +void Sign::SignUpdate(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (out_len <= 0 || r == 0) { - delete [] out_value; // allocated even if out_len == 0 - out_value = NULL; - if (r == 0) return ThrowCryptoTypeError(ERR_get_error()); - } + Sign* sign = ObjectWrap::Unwrap(args.This()); - outString = Encode(out_value, out_len, BUFFER); - delete [] out_value; - return scope.Close(outString); - } + ASSERT_IS_STRING_OR_BUFFER(args[0]); - Decipher () : ObjectWrap () { - initialised_ = false; + // Only copy the data if we have to, because it's a string + int r; + if (args[0]->IsString()) { ++ Local string = args[0].As(); + enum encoding encoding = ParseEncoding(args[1], BINARY); - size_t buflen = StringBytes::StorageSize(args[0], encoding); ++ if (!StringBytes::IsValidString(string, encoding)) ++ return ThrowTypeError("Bad input string"); ++ size_t buflen = StringBytes::StorageSize(string, encoding); + char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, args[0], encoding); ++ size_t written = StringBytes::Write(buf, buflen, string, encoding); + r = sign->SignUpdate(buf, written); + delete[] buf; + } else { + char* buf = Buffer::Data(args[0]); + size_t buflen = Buffer::Length(args[0]); + r = sign->SignUpdate(buf, buflen); } - ~Decipher () { - if (initialised_) { - EVP_CIPHER_CTX_cleanup(&ctx); - } + if (!r) { + return ThrowTypeError("SignUpdate fail"); } +} - private: - EVP_CIPHER_CTX ctx; - const EVP_CIPHER *cipher_; - bool initialised_; -}; +bool Sign::SignFinal(unsigned char** md_value, + unsigned int *md_len, + char* key_pem, + int key_pem_len) { + if (!initialised_) return false; + BIO* bp = NULL; + EVP_PKEY* pkey = NULL; + bp = BIO_new(BIO_s_mem()); + if (!BIO_write(bp, key_pem, key_pem_len)) return false; + pkey = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL); + if (pkey == NULL) return 0; + EVP_SignFinal(&mdctx_, *md_value, md_len, pkey); + EVP_MD_CTX_cleanup(&mdctx_); + initialised_ = false; + EVP_PKEY_free(pkey); + BIO_free_all(bp); + return true; +} -class Hmac : public ObjectWrap { - public: - static void Initialize (v8::Handle target) { - HandleScope scope; - Local t = FunctionTemplate::New(New); +void Sign::SignFinal(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - t->InstanceTemplate()->SetInternalFieldCount(1); + Sign* sign = ObjectWrap::Unwrap(args.This()); - NODE_SET_PROTOTYPE_METHOD(t, "init", HmacInit); - NODE_SET_PROTOTYPE_METHOD(t, "update", HmacUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "digest", HmacDigest); + unsigned char* md_value; + unsigned int md_len; - target->Set(String::NewSymbol("Hmac"), t->GetFunction()); + enum encoding encoding = BUFFER; + if (args.Length() >= 2) { + encoding = ParseEncoding(args[1]->ToString(), BUFFER); } - bool HmacInit(char* hashType, char* key, int key_len) { - md = EVP_get_digestbyname(hashType); - if(!md) { - fprintf(stderr, "node-crypto : Unknown message digest %s\n", hashType); - return false; - } - HMAC_CTX_init(&ctx); - if (key_len == 0) { - HMAC_Init(&ctx, "", 0, md); - } else { - HMAC_Init(&ctx, key, key_len, md); - } - initialised_ = true; - return true; + ASSERT_IS_BUFFER(args[0]); + ssize_t len = Buffer::Length(args[0]); + char* buf = Buffer::Data(args[0]); - } + md_len = 8192; // Maximum key size is 8192 bits + md_value = new unsigned char[md_len]; - int HmacUpdate(char* data, int len) { - if (!initialised_) return 0; - HMAC_Update(&ctx, (unsigned char*)data, len); - return 1; + bool r = sign->SignFinal(&md_value, &md_len, buf, len); + if (!r) { + delete[] md_value; + md_value = NULL; + md_len = 0; } - int HmacDigest(unsigned char** md_value, unsigned int *md_len) { - if (!initialised_) return 0; - *md_value = new unsigned char[EVP_MAX_MD_SIZE]; - HMAC_Final(&ctx, *md_value, md_len); - HMAC_CTX_cleanup(&ctx); - initialised_ = false; - return 1; - } + Local rc = StringBytes::Encode( + reinterpret_cast(md_value), md_len, encoding); + delete[] md_value; + args.GetReturnValue().Set(rc); +} - protected: +void Verify::Initialize(v8::Handle target) { + HandleScope scope(node_isolate); - static Handle New (const Arguments& args) { - HandleScope scope; + Local t = FunctionTemplate::New(New); - Hmac *hmac = new Hmac(); - hmac->Wrap(args.This()); - return args.This(); - } + t->InstanceTemplate()->SetInternalFieldCount(1); - static Handle HmacInit(const Arguments& args) { - Hmac *hmac = ObjectWrap::Unwrap(args.This()); + NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit); + NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate); + NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal); - HandleScope scope; + target->Set(String::NewSymbol("Verify"), t->GetFunction()); +} - if (args.Length() == 0 || !args[0]->IsString()) { - return ThrowException(Exception::Error(String::New( - "Must give hashtype string as argument"))); - } - ASSERT_IS_BUFFER(args[1]); - ssize_t len = Buffer::Length(args[1]); +void Verify::New(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); + Verify* verify = new Verify(); + verify->Wrap(args.This()); +} - if (len < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - String::Utf8Value hashType(args[0]); +void Verify::VerifyInit(const char* verify_type) { + HandleScope scope(node_isolate); - bool r; - - if( Buffer::HasInstance(args[1])) { - char* buffer_data = Buffer::Data(args[1]); - size_t buffer_length = Buffer::Length(args[1]); - - r = hmac->HmacInit(*hashType, buffer_data, buffer_length); - } else { - char* buf = new char[len]; - ssize_t written = DecodeWrite(buf, len, args[1], BINARY); - assert(written == len); - - r = hmac->HmacInit(*hashType, buf, len); - - delete [] buf; - } - - if (!r) { - return ThrowException(Exception::Error(String::New("hmac error"))); - } - - return args.This(); + assert(md_ == NULL); + md_ = EVP_get_digestbyname(verify_type); + if (md_ == NULL) { + return ThrowError("Unknown message digest"); } - static Handle HmacUpdate(const Arguments& args) { - Hmac *hmac = ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - ASSERT_IS_STRING_OR_BUFFER(args[0]); - - // Only copy the data if we have to, because it's a string - int r; - if (args[0]->IsString()) { - Local string = args[0].As(); - enum encoding encoding = ParseEncoding(args[1], BINARY); - if (!StringBytes::IsValidString(string, encoding)) - return ThrowTypeError("Bad input string"); - size_t buflen = StringBytes::StorageSize(string, encoding); - char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, string, encoding); - r = hmac->HmacUpdate(buf, written); - delete[] buf; - } else { - char* buf = Buffer::Data(args[0]); - size_t buflen = Buffer::Length(args[0]); - r = hmac->HmacUpdate(buf, buflen); - } - - if (!r) { - Local exception = Exception::TypeError(String::New("HmacUpdate fail")); - return ThrowException(exception); - } - - return args.This(); - } - - static Handle HmacDigest(const Arguments& args) { - Hmac *hmac = ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - enum encoding encoding = BUFFER; - if (args.Length() >= 1) { - encoding = ParseEncoding(args[0]->ToString(), BUFFER); - } - - unsigned char* md_value = NULL; - unsigned int md_len = 0; - Local outString; - - int r = hmac->HmacDigest(&md_value, &md_len); - if (r == 0) { - md_value = NULL; - md_len = 0; - } + EVP_MD_CTX_init(&mdctx_); + EVP_VerifyInit_ex(&mdctx_, md_, NULL); + initialised_ = true; +} - outString = StringBytes::Encode( - reinterpret_cast(md_value), md_len, encoding); - delete[] md_value; - return scope.Close(outString); - } +void Verify::VerifyInit(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - Hmac () : ObjectWrap () { - initialised_ = false; - } + Verify* verify = ObjectWrap::Unwrap(args.This()); - ~Hmac () { - if (initialised_) { - HMAC_CTX_cleanup(&ctx); - } + if (args.Length() == 0 || !args[0]->IsString()) { + return ThrowError("Must give verifytype string as argument"); } - private: - - HMAC_CTX ctx; /* coverity[member_decl] */ - const EVP_MD *md; /* coverity[member_decl] */ - bool initialised_; -}; + String::Utf8Value verify_type(args[0]); + verify->VerifyInit(*verify_type); +} -class Hash : public ObjectWrap { - public: - static void Initialize (v8::Handle target) { - HandleScope scope; +bool Verify::VerifyUpdate(char* data, int len) { + if (!initialised_) return false; + EVP_VerifyUpdate(&mdctx_, data, len); + return true; +} - Local t = FunctionTemplate::New(New); - t->InstanceTemplate()->SetInternalFieldCount(1); +void Verify::VerifyUpdate(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - NODE_SET_PROTOTYPE_METHOD(t, "update", HashUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "digest", HashDigest); + Verify* verify = ObjectWrap::Unwrap(args.This()); - target->Set(String::NewSymbol("Hash"), t->GetFunction()); - } + ASSERT_IS_STRING_OR_BUFFER(args[0]); - bool HashInit (const char* hashType) { - md = EVP_get_digestbyname(hashType); - if(!md) return false; - EVP_MD_CTX_init(&mdctx); - EVP_DigestInit_ex(&mdctx, md, NULL); - initialised_ = true; - return true; + // Only copy the data if we have to, because it's a string + bool r; + if (args[0]->IsString()) { ++ Local string = args[0].As(); + enum encoding encoding = ParseEncoding(args[1], BINARY); - size_t buflen = StringBytes::StorageSize(args[0], encoding); ++ if (!StringBytes::IsValidString(string, encoding)) ++ return ThrowTypeError("Bad input string"); ++ size_t buflen = StringBytes::StorageSize(string, encoding); + char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, args[0], encoding); ++ size_t written = StringBytes::Write(buf, buflen, string, encoding); + r = verify->VerifyUpdate(buf, written); + delete[] buf; + } else { + char* buf = Buffer::Data(args[0]); + size_t buflen = Buffer::Length(args[0]); + r = verify->VerifyUpdate(buf, buflen); } - int HashUpdate(char* data, int len) { - if (!initialised_) return 0; - EVP_DigestUpdate(&mdctx, data, len); - return 1; + if (!r) { + return ThrowTypeError("VerifyUpdate fail"); } +} - protected: - - static Handle New (const Arguments& args) { - HandleScope scope; - - if (args.Length() == 0 || !args[0]->IsString()) { - return ThrowException(Exception::Error(String::New( - "Must give hashtype string as argument"))); - } - - String::Utf8Value hashType(args[0]); +bool Verify::VerifyFinal(char* key_pem, + int key_pem_len, + unsigned char* sig, + int siglen) { + HandleScope scope(node_isolate); - Hash *hash = new Hash(); - if (!hash->HashInit(*hashType)) { - delete hash; - return ThrowException(Exception::Error(String::New( - "Digest method not supported"))); - } - - hash->Wrap(args.This()); - return args.This(); + if (!initialised_) { + ThrowError("Verify not initalised"); + return false; } - static Handle HashUpdate(const Arguments& args) { - HandleScope scope; - - Hash *hash = ObjectWrap::Unwrap(args.This()); - - ASSERT_IS_STRING_OR_BUFFER(args[0]); - - // Only copy the data if we have to, because it's a string - int r; - if (args[0]->IsString()) { - Local string = args[0].As(); - enum encoding encoding = ParseEncoding(args[1], BINARY); - if (!StringBytes::IsValidString(string, encoding)) - return ThrowTypeError("Bad input string"); - size_t buflen = StringBytes::StorageSize(string, encoding); - char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, string, encoding); - r = hash->HashUpdate(buf, written); - delete[] buf; - } else { - char* buf = Buffer::Data(args[0]); - size_t buflen = Buffer::Length(args[0]); - r = hash->HashUpdate(buf, buflen); - } - - if (!r) { - Local exception = Exception::TypeError(String::New("HashUpdate fail")); - return ThrowException(exception); + EVP_PKEY* pkey = NULL; + BIO* bp = NULL; + X509* x509 = NULL; + bool fatal = true; + int r = 0; + + bp = BIO_new(BIO_s_mem()); + if (bp == NULL) + goto exit; + + if (!BIO_write(bp, key_pem, key_pem_len)) + goto exit; + + // Check if this is a PKCS#8 or RSA public key before trying as X.509. + // Split this out into a separate function once we have more than one + // consumer of public keys. + if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) { + pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL); + if (pkey == NULL) + goto exit; + } else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) { + RSA* rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL); + if (rsa) { + pkey = EVP_PKEY_new(); + if (pkey) EVP_PKEY_set1_RSA(pkey, rsa); + RSA_free(rsa); } + if (pkey == NULL) + goto exit; + } else { + // X.509 fallback + x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL); + if (x509 == NULL) + goto exit; - return args.This(); + pkey = X509_get_pubkey(x509); + if (pkey == NULL) + goto exit; } - static Handle HashDigest(const Arguments& args) { - HandleScope scope; - - Hash *hash = ObjectWrap::Unwrap(args.This()); - - if (!hash->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); - } - - enum encoding encoding = BUFFER; - if (args.Length() >= 1) { - encoding = ParseEncoding(args[0]->ToString(), BUFFER); - } - - unsigned char md_value[EVP_MAX_MD_SIZE]; - unsigned int md_len; + fatal = false; + r = EVP_VerifyFinal(&mdctx_, sig, siglen, pkey); - EVP_DigestFinal_ex(&hash->mdctx, md_value, &md_len); - EVP_MD_CTX_cleanup(&hash->mdctx); - hash->initialised_ = false; +exit: + if (pkey != NULL) + EVP_PKEY_free(pkey); + if (bp != NULL) + BIO_free_all(bp); + if (x509 != NULL) + X509_free(x509); - return scope.Close(StringBytes::Encode( - reinterpret_cast(md_value), md_len, encoding)); - } + EVP_MD_CTX_cleanup(&mdctx_); + initialised_ = false; - Hash () : ObjectWrap () { - initialised_ = false; - } - - ~Hash () { - if (initialised_) { - EVP_MD_CTX_cleanup(&mdctx); - } + if (fatal) { + unsigned long err = ERR_get_error(); + ThrowCryptoError(err); + return false; } - private: - - EVP_MD_CTX mdctx; /* coverity[member_decl] */ - const EVP_MD *md; /* coverity[member_decl] */ - bool initialised_; -}; + return r == 1; +} -class Sign : public ObjectWrap { - public: - static void - Initialize (v8::Handle target) { - HandleScope scope; - Local t = FunctionTemplate::New(New); +void Verify::VerifyFinal(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - t->InstanceTemplate()->SetInternalFieldCount(1); + Verify* verify = ObjectWrap::Unwrap(args.This()); - NODE_SET_PROTOTYPE_METHOD(t, "init", SignInit); - NODE_SET_PROTOTYPE_METHOD(t, "update", SignUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "sign", SignFinal); + ASSERT_IS_BUFFER(args[0]); + char* kbuf = Buffer::Data(args[0]); + ssize_t klen = Buffer::Length(args[0]); - target->Set(String::NewSymbol("Sign"), t->GetFunction()); + ASSERT_IS_STRING_OR_BUFFER(args[1]); + // BINARY works for both buffers and binary strings. + enum encoding encoding = BINARY; + if (args.Length() >= 3) { + encoding = ParseEncoding(args[2]->ToString(), BINARY); } - bool SignInit (const char* signType) { - md = EVP_get_digestbyname(signType); - if(!md) { - printf("Unknown message digest %s\n", signType); - return false; - } - EVP_MD_CTX_init(&mdctx); - EVP_SignInit_ex(&mdctx, md, NULL); - initialised_ = true; - return true; + ssize_t hlen = StringBytes::Size(args[1], encoding); + // only copy if we need to, because it's a string. + unsigned char* hbuf; + if (args[1]->IsString()) { + hbuf = new unsigned char[hlen]; + ssize_t hwritten = StringBytes::Write( + reinterpret_cast(hbuf), hlen, args[1], encoding); + assert(hwritten == hlen); + } else { + hbuf = reinterpret_cast(Buffer::Data(args[1])); } - int SignUpdate(char* data, int len) { - if (!initialised_) return 0; - EVP_SignUpdate(&mdctx, data, len); - return 1; + bool rc = verify->VerifyFinal(kbuf, klen, hbuf, hlen); + if (args[1]->IsString()) { + delete[] hbuf; } + args.GetReturnValue().Set(rc); +} - int SignFinal(unsigned char** md_value, - unsigned int *md_len, - char* key_pem, - int key_pemLen) { - if (!initialised_) return 0; - - BIO *bp = NULL; - EVP_PKEY* pkey; - bp = BIO_new(BIO_s_mem()); - if(!BIO_write(bp, key_pem, key_pemLen)) return 0; - - pkey = PEM_read_bio_PrivateKey( bp, NULL, NULL, NULL ); - if (pkey == NULL) return 0; - - EVP_SignFinal(&mdctx, *md_value, md_len, pkey); - EVP_MD_CTX_cleanup(&mdctx); - initialised_ = false; - EVP_PKEY_free(pkey); - BIO_free(bp); - return 1; - } +void DiffieHellman::Initialize(v8::Handle target) { + HandleScope scope(node_isolate); - protected: + Local t = FunctionTemplate::New(New); - static Handle New (const Arguments& args) { - HandleScope scope; + t->InstanceTemplate()->SetInternalFieldCount(1); - Sign *sign = new Sign(); - sign->Wrap(args.This()); + NODE_SET_PROTOTYPE_METHOD(t, "generateKeys", GenerateKeys); + NODE_SET_PROTOTYPE_METHOD(t, "computeSecret", ComputeSecret); + NODE_SET_PROTOTYPE_METHOD(t, "getPrime", GetPrime); + NODE_SET_PROTOTYPE_METHOD(t, "getGenerator", GetGenerator); + NODE_SET_PROTOTYPE_METHOD(t, "getPublicKey", GetPublicKey); + NODE_SET_PROTOTYPE_METHOD(t, "getPrivateKey", GetPrivateKey); + NODE_SET_PROTOTYPE_METHOD(t, "setPublicKey", SetPublicKey); + NODE_SET_PROTOTYPE_METHOD(t, "setPrivateKey", SetPrivateKey); - return args.This(); - } + target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction()); - static Handle SignInit(const Arguments& args) { - HandleScope scope; + Local t2 = FunctionTemplate::New(DiffieHellmanGroup); + t2->InstanceTemplate()->SetInternalFieldCount(1); - Sign *sign = ObjectWrap::Unwrap(args.This()); + NODE_SET_PROTOTYPE_METHOD(t2, "generateKeys", GenerateKeys); + NODE_SET_PROTOTYPE_METHOD(t2, "computeSecret", ComputeSecret); + NODE_SET_PROTOTYPE_METHOD(t2, "getPrime", GetPrime); + NODE_SET_PROTOTYPE_METHOD(t2, "getGenerator", GetGenerator); + NODE_SET_PROTOTYPE_METHOD(t2, "getPublicKey", GetPublicKey); + NODE_SET_PROTOTYPE_METHOD(t2, "getPrivateKey", GetPrivateKey); - if (args.Length() == 0 || !args[0]->IsString()) { - return ThrowException(Exception::Error(String::New( - "Must give signtype string as argument"))); - } + target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction()); +} - String::Utf8Value signType(args[0]); - bool r = sign->SignInit(*signType); +bool DiffieHellman::Init(int primeLength) { + dh = DH_new(); + DH_generate_parameters_ex(dh, primeLength, DH_GENERATOR_2, 0); + bool result = VerifyContext(); + if (!result) return false; + initialised_ = true; + return true; +} - if (!r) { - return ThrowException(Exception::Error(String::New("SignInit error"))); - } - return args.This(); - } +bool DiffieHellman::Init(unsigned char* p, int p_len) { + dh = DH_new(); + dh->p = BN_bin2bn(p, p_len, 0); + dh->g = BN_new(); + if (!BN_set_word(dh->g, 2)) return false; + bool result = VerifyContext(); + if (!result) return false; + initialised_ = true; + return true; +} - static Handle SignUpdate(const Arguments& args) { - Sign *sign = ObjectWrap::Unwrap(args.This()); - HandleScope scope; +bool DiffieHellman::Init(unsigned char* p, + int p_len, + unsigned char* g, + int g_len) { + dh = DH_new(); + dh->p = BN_bin2bn(p, p_len, 0); + dh->g = BN_bin2bn(g, g_len, 0); + initialised_ = true; + return true; +} - ASSERT_IS_STRING_OR_BUFFER(args[0]); - // Only copy the data if we have to, because it's a string - int r; - if (args[0]->IsString()) { - Local string = args[0].As(); - enum encoding encoding = ParseEncoding(args[1], BINARY); - if (!StringBytes::IsValidString(string, encoding)) - return ThrowTypeError("Bad input string"); - size_t buflen = StringBytes::StorageSize(string, encoding); - char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, string, encoding); - r = sign->SignUpdate(buf, written); - delete[] buf; - } else { - char* buf = Buffer::Data(args[0]); - size_t buflen = Buffer::Length(args[0]); - r = sign->SignUpdate(buf, buflen); - } +void DiffieHellman::DiffieHellmanGroup( + const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (!r) { - Local exception = Exception::TypeError(String::New("SignUpdate fail")); - return ThrowException(exception); - } + DiffieHellman* diffieHellman = new DiffieHellman(); - return args.This(); + if (args.Length() != 1 || !args[0]->IsString()) { + return ThrowError("No group name given"); } - static Handle SignFinal(const Arguments& args) { - Sign *sign = ObjectWrap::Unwrap(args.This()); + String::Utf8Value group_name(args[0]); - HandleScope scope; - - unsigned char* md_value; - unsigned int md_len; - Local outString; - - ASSERT_IS_BUFFER(args[0]); - ssize_t len = Buffer::Length(args[0]); - - enum encoding encoding = BUFFER; - if (args.Length() >= 2) { - encoding = ParseEncoding(args[1]->ToString(), BUFFER); - } + modp_group* it = modp_groups; - char* buf = new char[len]; - ssize_t written = DecodeWrite(buf, len, args[0], BUFFER); - assert(written == len); - - md_len = 8192; // Maximum key size is 8192 bits - md_value = new unsigned char[md_len]; - - int r = sign->SignFinal(&md_value, &md_len, buf, len); - if (r == 0) { - md_value = NULL; - md_len = r; - } - - delete [] buf; - - outString = StringBytes::Encode( - reinterpret_cast(md_value), md_len, encoding); - - delete [] md_value; - return scope.Close(outString); - } - - Sign () : ObjectWrap () { - initialised_ = false; + while(it->name != NULL) { + if (!strcasecmp(*group_name, it->name)) + break; + it++; } - ~Sign () { - if (initialised_) { - EVP_MD_CTX_cleanup(&mdctx); - } + if (it->name != NULL) { + diffieHellman->Init(it->prime, + it->prime_size, + it->gen, + it->gen_size); + } else { + return ThrowError("Unknown group"); } - private: - - EVP_MD_CTX mdctx; /* coverity[member_decl] */ - const EVP_MD *md; /* coverity[member_decl] */ - bool initialised_; -}; - -class Verify : public ObjectWrap { - public: - static void Initialize (v8::Handle target) { - HandleScope scope; - - Local t = FunctionTemplate::New(New); + diffieHellman->Wrap(args.This()); +} - t->InstanceTemplate()->SetInternalFieldCount(1); - NODE_SET_PROTOTYPE_METHOD(t, "init", VerifyInit); - NODE_SET_PROTOTYPE_METHOD(t, "update", VerifyUpdate); - NODE_SET_PROTOTYPE_METHOD(t, "verify", VerifyFinal); +void DiffieHellman::New(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - target->Set(String::NewSymbol("Verify"), t->GetFunction()); - } + DiffieHellman* diffieHellman = new DiffieHellman(); + bool initialized = false; - - bool VerifyInit (const char* verifyType) { - md = EVP_get_digestbyname(verifyType); - if(!md) { - fprintf(stderr, "node-crypto : Unknown message digest %s\n", verifyType); - return false; + if (args.Length() > 0) { + if (args[0]->IsInt32()) { + initialized = diffieHellman->Init(args[0]->Int32Value()); + } else { + initialized = diffieHellman->Init( + reinterpret_cast(Buffer::Data(args[0])), + Buffer::Length(args[0])); } - EVP_MD_CTX_init(&mdctx); - EVP_VerifyInit_ex(&mdctx, md, NULL); - initialised_ = true; - return true; } - - int VerifyUpdate(char* data, int len) { - if (!initialised_) return 0; - EVP_VerifyUpdate(&mdctx, data, len); - return 1; + if (!initialized) { + return ThrowError("Initialization failed"); } + diffieHellman->Wrap(args.This()); +} - int VerifyFinal(char* key_pem, int key_pemLen, unsigned char* sig, int siglen) { - if (!initialised_) return 0; - - EVP_PKEY* pkey = NULL; - BIO *bp = NULL; - X509 *x509 = NULL; - int r = 0; - - bp = BIO_new(BIO_s_mem()); - if (bp == NULL) { - ERR_print_errors_fp(stderr); - return 0; - } - if(!BIO_write(bp, key_pem, key_pemLen)) { - ERR_print_errors_fp(stderr); - return 0; - } - - // Check if this is a PKCS#8 or RSA public key before trying as X.509. - // Split this out into a separate function once we have more than one - // consumer of public keys. - if (strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) { - pkey = PEM_read_bio_PUBKEY(bp, NULL, NULL, NULL); - if (pkey == NULL) { - ERR_print_errors_fp(stderr); - return 0; - } - } else if (strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) { - RSA* rsa = PEM_read_bio_RSAPublicKey(bp, NULL, NULL, NULL); - if (rsa) { - pkey = EVP_PKEY_new(); - if (pkey) EVP_PKEY_set1_RSA(pkey, rsa); - RSA_free(rsa); - } - if (pkey == NULL) { - ERR_print_errors_fp(stderr); - return 0; - } - } else { - // X.509 fallback - x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL); - if (x509 == NULL) { - ERR_print_errors_fp(stderr); - return 0; - } - - pkey = X509_get_pubkey(x509); - if (pkey == NULL) { - ERR_print_errors_fp(stderr); - return 0; - } - } - r = EVP_VerifyFinal(&mdctx, sig, siglen, pkey); +void DiffieHellman::GenerateKeys(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if(pkey != NULL) - EVP_PKEY_free (pkey); - if (x509 != NULL) - X509_free(x509); - if (bp != NULL) - BIO_free(bp); - EVP_MD_CTX_cleanup(&mdctx); - initialised_ = false; + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); - return r; + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } - - protected: - - static Handle New (const Arguments& args) { - HandleScope scope; - - Verify *verify = new Verify(); - verify->Wrap(args.This()); - - return args.This(); + if (!DH_generate_key(diffieHellman->dh)) { + return ThrowError("Key generation failed"); } + int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->pub_key, + reinterpret_cast(data)); - static Handle VerifyInit(const Arguments& args) { - Verify *verify = ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - if (args.Length() == 0 || !args[0]->IsString()) { - return ThrowException(Exception::Error(String::New( - "Must give verifytype string as argument"))); - } + args.GetReturnValue().Set(Encode(data, dataSize, BUFFER)); + delete[] data; +} - String::Utf8Value verifyType(args[0]); - bool r = verify->VerifyInit(*verifyType); +void DiffieHellman::GetPrime(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (!r) { - return ThrowException(Exception::Error(String::New("VerifyInit error"))); - } + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); - return args.This(); + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } + int dataSize = BN_num_bytes(diffieHellman->dh->p); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->p, reinterpret_cast(data)); - static Handle VerifyUpdate(const Arguments& args) { - HandleScope scope; - - Verify *verify = ObjectWrap::Unwrap(args.This()); + args.GetReturnValue().Set(Encode(data, dataSize, BUFFER)); + delete[] data; +} - ASSERT_IS_STRING_OR_BUFFER(args[0]); - // Only copy the data if we have to, because it's a string - int r; - if (args[0]->IsString()) { - Local string = args[0].As(); - enum encoding encoding = ParseEncoding(args[1], BINARY); - if (!StringBytes::IsValidString(string, encoding)) - return ThrowTypeError("Bad input string"); - size_t buflen = StringBytes::StorageSize(string, encoding); - char* buf = new char[buflen]; - size_t written = StringBytes::Write(buf, buflen, string, encoding); - r = verify->VerifyUpdate(buf, written); - delete[] buf; - } else { - char* buf = Buffer::Data(args[0]); - size_t buflen = Buffer::Length(args[0]); - r = verify->VerifyUpdate(buf, buflen); - } +void DiffieHellman::GetGenerator(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (!r) { - Local exception = Exception::TypeError(String::New("VerifyUpdate fail")); - return ThrowException(exception); - } + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); - return args.This(); + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } + int dataSize = BN_num_bytes(diffieHellman->dh->g); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->g, reinterpret_cast(data)); - static Handle VerifyFinal(const Arguments& args) { - HandleScope scope; - - Verify *verify = ObjectWrap::Unwrap(args.This()); - - ASSERT_IS_BUFFER(args[0]); - ssize_t klen = Buffer::Length(args[0]); - - if (klen < 0) { - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - - char* kbuf = new char[klen]; - ssize_t kwritten = DecodeWrite(kbuf, klen, args[0], BINARY); - assert(kwritten == klen); - - ASSERT_IS_STRING_OR_BUFFER(args[1]); - - // BINARY works for both buffers and binary strings. - enum encoding encoding = BINARY; - if (args.Length() >= 3) { - encoding = ParseEncoding(args[2]->ToString(), BINARY); - } - - ssize_t hlen = StringBytes::Size(args[1], encoding); - - if (hlen < 0) { - delete[] kbuf; - Local exception = Exception::TypeError(String::New("Bad argument")); - return ThrowException(exception); - } - - unsigned char* hbuf = new unsigned char[hlen]; - ssize_t hwritten = StringBytes::Write( - reinterpret_cast(hbuf), hlen, args[1], encoding); - assert(hwritten == hlen); + args.GetReturnValue().Set(Encode(data, dataSize, BUFFER)); + delete[] data; +} - int r; - r = verify->VerifyFinal(kbuf, klen, hbuf, hlen); - delete[] kbuf; - delete[] hbuf; +void DiffieHellman::GetPublicKey(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - return Boolean::New(r && r != -1); - } + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); - Verify () : ObjectWrap () { - initialised_ = false; + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } - ~Verify () { - if (initialised_) { - EVP_MD_CTX_cleanup(&mdctx); - } + if (diffieHellman->dh->pub_key == NULL) { + return ThrowError("No public key - did you forget to generate one?"); } - private: - - EVP_MD_CTX mdctx; /* coverity[member_decl] */ - const EVP_MD *md; /* coverity[member_decl] */ - bool initialised_; + int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->pub_key, + reinterpret_cast(data)); -}; - -class DiffieHellman : public ObjectWrap { - public: - static void Initialize(v8::Handle target) { - HandleScope scope; - - Local t = FunctionTemplate::New(New); - - t->InstanceTemplate()->SetInternalFieldCount(1); - - NODE_SET_PROTOTYPE_METHOD(t, "generateKeys", GenerateKeys); - NODE_SET_PROTOTYPE_METHOD(t, "computeSecret", ComputeSecret); - NODE_SET_PROTOTYPE_METHOD(t, "getPrime", GetPrime); - NODE_SET_PROTOTYPE_METHOD(t, "getGenerator", GetGenerator); - NODE_SET_PROTOTYPE_METHOD(t, "getPublicKey", GetPublicKey); - NODE_SET_PROTOTYPE_METHOD(t, "getPrivateKey", GetPrivateKey); - NODE_SET_PROTOTYPE_METHOD(t, "setPublicKey", SetPublicKey); - NODE_SET_PROTOTYPE_METHOD(t, "setPrivateKey", SetPrivateKey); - - target->Set(String::NewSymbol("DiffieHellman"), t->GetFunction()); - - Local t2 = FunctionTemplate::New(DiffieHellmanGroup); - t2->InstanceTemplate()->SetInternalFieldCount(1); + args.GetReturnValue().Set(Encode(data, dataSize, BUFFER)); + delete[] data; +} - NODE_SET_PROTOTYPE_METHOD(t2, "generateKeys", GenerateKeys); - NODE_SET_PROTOTYPE_METHOD(t2, "computeSecret", ComputeSecret); - NODE_SET_PROTOTYPE_METHOD(t2, "getPrime", GetPrime); - NODE_SET_PROTOTYPE_METHOD(t2, "getGenerator", GetGenerator); - NODE_SET_PROTOTYPE_METHOD(t2, "getPublicKey", GetPublicKey); - NODE_SET_PROTOTYPE_METHOD(t2, "getPrivateKey", GetPrivateKey); - target->Set(String::NewSymbol("DiffieHellmanGroup"), t2->GetFunction()); - } +void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - bool Init(int primeLength) { - dh = DH_new(); - DH_generate_parameters_ex(dh, primeLength, DH_GENERATOR_2, 0); - bool result = VerifyContext(); - if (!result) return false; - initialised_ = true; - return true; - } + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); - bool Init(unsigned char* p, int p_len) { - dh = DH_new(); - dh->p = BN_bin2bn(p, p_len, 0); - dh->g = BN_new(); - if (!BN_set_word(dh->g, 2)) return false; - bool result = VerifyContext(); - if (!result) return false; - initialised_ = true; - return true; + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } - bool Init(unsigned char* p, int p_len, unsigned char* g, int g_len) { - dh = DH_new(); - dh->p = BN_bin2bn(p, p_len, 0); - dh->g = BN_bin2bn(g, g_len, 0); - initialised_ = true; - return true; + if (diffieHellman->dh->priv_key == NULL) { + return ThrowError("No private key - did you forget to generate one?"); } - protected: - static Handle DiffieHellmanGroup(const Arguments& args) { - HandleScope scope; - - DiffieHellman* diffieHellman = new DiffieHellman(); - - if (args.Length() != 1 || !args[0]->IsString()) { - return ThrowException(Exception::Error( - String::New("No group name given"))); - } + int dataSize = BN_num_bytes(diffieHellman->dh->priv_key); + char* data = new char[dataSize]; + BN_bn2bin(diffieHellman->dh->priv_key, + reinterpret_cast(data)); - String::Utf8Value group_name(args[0]); + args.GetReturnValue().Set(Encode(data, dataSize, BUFFER)); + delete[] data; +} - modp_group* it = modp_groups; - while(it->name != NULL) { - if (!strcasecmp(*group_name, it->name)) - break; - it++; - } +void DiffieHellman::ComputeSecret(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - if (it->name != NULL) { - diffieHellman->Init(it->prime, it->prime_size, - it->gen, it->gen_size); - } else { - return ThrowException(Exception::Error( - String::New("Unknown group"))); - } - - diffieHellman->Wrap(args.This()); + DiffieHellman* diffieHellman = + ObjectWrap::Unwrap(args.This()); - return args.This(); + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } - static Handle New(const Arguments& args) { - HandleScope scope; - - DiffieHellman* diffieHellman = new DiffieHellman(); - bool initialized = false; - - if (args.Length() > 0) { - if (args[0]->IsInt32()) { - initialized = diffieHellman->Init(args[0]->Int32Value()); - } else { - initialized = diffieHellman->Init( - reinterpret_cast(Buffer::Data(args[0])), - Buffer::Length(args[0])); - } - } - - if (!initialized) { - return ThrowException(Exception::Error( - String::New("Initialization failed"))); - } - - diffieHellman->Wrap(args.This()); + ClearErrorOnReturn clear_error_on_return; + (void) &clear_error_on_return; // Silence compiler warning. + BIGNUM* key = NULL; - return args.This(); + if (args.Length() == 0) { + return ThrowError("First argument must be other party's public key"); + } else { + ASSERT_IS_BUFFER(args[0]); + key = BN_bin2bn( + reinterpret_cast(Buffer::Data(args[0])), + Buffer::Length(args[0]), + 0); } - static Handle GenerateKeys(const Arguments& args) { - DiffieHellman* diffieHellman = - ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error( - String::New("Not initialized"))); - } - - if (!DH_generate_key(diffieHellman->dh)) { - return ThrowException(Exception::Error( - String::New("Key generation failed"))); - } + int dataSize = DH_size(diffieHellman->dh); + char* data = new char[dataSize]; - Local outString; + int size = DH_compute_key(reinterpret_cast(data), + key, + diffieHellman->dh); - int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); - char* data = new char[dataSize]; - BN_bn2bin(diffieHellman->dh->pub_key, - reinterpret_cast(data)); + if (size == -1) { + int checkResult; + int checked; - outString = Encode(data, dataSize, BUFFER); + checked = DH_check_pub_key(diffieHellman->dh, key, &checkResult); + BN_free(key); delete[] data; - return scope.Close(outString); - } - - static Handle GetPrime(const Arguments& args) { - DiffieHellman* diffieHellman = - ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); + if (!checked) { + return ThrowError("Invalid key"); + } else if (checkResult) { + if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) { + return ThrowError("Supplied key is too small"); + } else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) { + return ThrowError("Supplied key is too large"); + } else { + return ThrowError("Invalid key"); + } + } else { + return ThrowError("Invalid key"); } - - int dataSize = BN_num_bytes(diffieHellman->dh->p); - char* data = new char[dataSize]; - BN_bn2bin(diffieHellman->dh->p, reinterpret_cast(data)); - - Local outString; - - outString = Encode(data, dataSize, BUFFER); - - delete[] data; - - return scope.Close(outString); } - static Handle GetGenerator(const Arguments& args) { - DiffieHellman* diffieHellman = - ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); - } - - int dataSize = BN_num_bytes(diffieHellman->dh->g); - char* data = new char[dataSize]; - BN_bn2bin(diffieHellman->dh->g, reinterpret_cast(data)); + BN_free(key); + assert(size >= 0); - Local outString; - - outString = Encode(data, dataSize, BUFFER); - - delete[] data; - - return scope.Close(outString); + // DH_size returns number of bytes in a prime number + // DH_compute_key returns number of bytes in a remainder of exponent, which + // may have less bytes than a prime number. Therefore add 0-padding to the + // allocated buffer. + if (size != dataSize) { + assert(dataSize > size); + memmove(data + dataSize - size, data, size); + memset(data, 0, dataSize - size); } - static Handle GetPublicKey(const Arguments& args) { - DiffieHellman* diffieHellman = - ObjectWrap::Unwrap(args.This()); - - HandleScope scope; - - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); - } - - if (diffieHellman->dh->pub_key == NULL) { - return ThrowException(Exception::Error( - String::New("No public key - did you forget to generate one?"))); - } - - int dataSize = BN_num_bytes(diffieHellman->dh->pub_key); - char* data = new char[dataSize]; - BN_bn2bin(diffieHellman->dh->pub_key, - reinterpret_cast(data)); - - Local outString; - - outString = Encode(data, dataSize, BUFFER); + args.GetReturnValue().Set(Encode(data, dataSize, BUFFER)); + delete[] data; +} - delete[] data; - return scope.Close(outString); - } +void DiffieHellman::SetPublicKey(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - static Handle GetPrivateKey(const Arguments& args) { - DiffieHellman* diffieHellman = + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); - HandleScope scope; - - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); - } - - if (diffieHellman->dh->priv_key == NULL) { - return ThrowException(Exception::Error( - String::New("No private key - did you forget to generate one?"))); - } - - int dataSize = BN_num_bytes(diffieHellman->dh->priv_key); - char* data = new char[dataSize]; - BN_bn2bin(diffieHellman->dh->priv_key, - reinterpret_cast(data)); - - Local outString; - - outString = Encode(data, dataSize, BUFFER); - - delete[] data; - - return scope.Close(outString); + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } - static Handle ComputeSecret(const Arguments& args) { - HandleScope scope; - - DiffieHellman* diffieHellman = - ObjectWrap::Unwrap(args.This()); - - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); - } - - ClearErrorOnReturn clear_error_on_return; - (void) &clear_error_on_return; // Silence compiler warning. - BIGNUM* key = 0; - - if (args.Length() == 0) { - return ThrowException(Exception::Error( - String::New("First argument must be other party's public key"))); - } else { - ASSERT_IS_BUFFER(args[0]); - key = BN_bin2bn( + if (args.Length() == 0) { + return ThrowError("First argument must be public key"); + } else { + ASSERT_IS_BUFFER(args[0]); + diffieHellman->dh->pub_key = BN_bin2bn( reinterpret_cast(Buffer::Data(args[0])), Buffer::Length(args[0]), 0); - } - - int dataSize = DH_size(diffieHellman->dh); - char* data = new char[dataSize]; - - int size = DH_compute_key(reinterpret_cast(data), - key, diffieHellman->dh); - - if (size == -1) { - int checkResult; - int checked; - - checked = DH_check_pub_key(diffieHellman->dh, key, &checkResult); - BN_free(key); - delete[] data; - - if (!checked) { - return ThrowException(Exception::Error(String::New("Invalid key"))); - } else if (checkResult) { - if (checkResult & DH_CHECK_PUBKEY_TOO_SMALL) { - return ThrowException(Exception::Error( - String::New("Supplied key is too small"))); - } else if (checkResult & DH_CHECK_PUBKEY_TOO_LARGE) { - return ThrowException(Exception::Error( - String::New("Supplied key is too large"))); - } else { - return ThrowException(Exception::Error(String::New("Invalid key"))); - } - } else { - return ThrowException(Exception::Error(String::New("Invalid key"))); - } - } - - BN_free(key); - assert(size >= 0); - - // DH_size returns number of bytes in a prime number - // DH_compute_key returns number of bytes in a remainder of exponent, which - // may have less bytes than a prime number. Therefore add 0-padding to the - // allocated buffer. - if (size != dataSize) { - assert(dataSize > size); - memmove(data + dataSize - size, data, size); - memset(data, 0, dataSize - size); - } - - Local outString; - - outString = Encode(data, dataSize, BUFFER); - - delete[] data; - return scope.Close(outString); } +} - static Handle SetPublicKey(const Arguments& args) { - HandleScope scope; - - DiffieHellman* diffieHellman = - ObjectWrap::Unwrap(args.This()); - - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error(String::New("Not initialized"))); - } - - if (args.Length() == 0) { - return ThrowException(Exception::Error( - String::New("First argument must be public key"))); - } else { - ASSERT_IS_BUFFER(args[0]); - diffieHellman->dh->pub_key = - BN_bin2bn( - reinterpret_cast(Buffer::Data(args[0])), - Buffer::Length(args[0]), 0); - } - - return args.This(); - } - static Handle SetPrivateKey(const Arguments& args) { - HandleScope scope; +void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo& args) { + HandleScope scope(node_isolate); - DiffieHellman* diffieHellman = + DiffieHellman* diffieHellman = ObjectWrap::Unwrap(args.This()); - if (!diffieHellman->initialised_) { - return ThrowException(Exception::Error( - String::New("Not initialized"))); - } - - if (args.Length() == 0) { - return ThrowException(Exception::Error( - String::New("First argument must be private key"))); - } else { - ASSERT_IS_BUFFER(args[0]); - diffieHellman->dh->priv_key = - BN_bin2bn( - reinterpret_cast(Buffer::Data(args[0])), - Buffer::Length(args[0]), 0); - } - - return args.This(); - } - - DiffieHellman() : ObjectWrap() { - initialised_ = false; - dh = NULL; + if (!diffieHellman->initialised_) { + return ThrowError("Not initialized"); } - ~DiffieHellman() { - if (dh != NULL) { - DH_free(dh); - } + if (args.Length() == 0) { + return ThrowError("First argument must be private key"); + } else { + ASSERT_IS_BUFFER(args[0]); + diffieHellman->dh->priv_key = BN_bin2bn( + reinterpret_cast(Buffer::Data(args[0])), + Buffer::Length(args[0]), + 0); } +} - private: - bool VerifyContext() { - int codes; - if (!DH_check(dh, &codes)) return false; - if (codes & DH_CHECK_P_NOT_SAFE_PRIME) return false; - if (codes & DH_CHECK_P_NOT_PRIME) return false; - if (codes & DH_UNABLE_TO_CHECK_GENERATOR) return false; - if (codes & DH_NOT_SUITABLE_GENERATOR) return false; - return true; - } - bool initialised_; - DH* dh; -}; +bool DiffieHellman::VerifyContext() { + int codes; + if (!DH_check(dh, &codes)) return false; + if (codes & DH_CHECK_P_NOT_SAFE_PRIME) return false; + if (codes & DH_CHECK_P_NOT_PRIME) return false; + if (codes & DH_UNABLE_TO_CHECK_GENERATOR) return false; + if (codes & DH_NOT_SUITABLE_GENERATOR) return false; + return true; +} struct pbkdf2_req { diff --cc src/node_os.cc index 5b6e30b,4b325d8..143dd60 --- a/src/node_os.cc +++ b/src/node_os.cc @@@ -131,29 -116,30 +131,31 @@@ static void GetCPUInfo(const FunctionCa uv_cpu_info_t* cpu_infos; int count, i; - uv_err_t err = uv_cpu_info(&cpu_infos, &count); - - if (err.code != UV_OK) { - return Undefined(); - } + int err = uv_cpu_info(&cpu_infos, &count); + if (err) return; Local cpus = Array::New(); - for (i = 0; i < count; i++) { + uv_cpu_info_t* ci = cpu_infos + i; + Local times_info = Object::New(); - times_info->Set(String::New("user"), Number::New(ci->cpu_times.user)); - times_info->Set(String::New("nice"), Number::New(ci->cpu_times.nice)); - times_info->Set(String::New("sys"), Number::New(ci->cpu_times.sys)); - times_info->Set(String::New("idle"), Number::New(ci->cpu_times.idle)); - times_info->Set(String::New("irq"), Number::New(ci->cpu_times.irq)); + times_info->Set(String::New("user"), - Integer::New(cpu_infos[i].cpu_times.user, node_isolate)); ++ Number::New(node_isolate, ci->cpu_times.user)); + times_info->Set(String::New("nice"), - Integer::New(cpu_infos[i].cpu_times.nice, node_isolate)); ++ Number::New(node_isolate, ci->cpu_times.nice)); + times_info->Set(String::New("sys"), - Integer::New(cpu_infos[i].cpu_times.sys, node_isolate)); ++ Number::New(node_isolate, ci->cpu_times.sys)); + times_info->Set(String::New("idle"), - Integer::New(cpu_infos[i].cpu_times.idle, node_isolate)); ++ Number::New(node_isolate, ci->cpu_times.idle)); + times_info->Set(String::New("irq"), - Integer::New(cpu_infos[i].cpu_times.irq, node_isolate)); ++ Number::New(node_isolate, ci->cpu_times.irq)); Local cpu_info = Object::New(); - cpu_info->Set(String::New("model"), String::New(cpu_infos[i].model)); - cpu_info->Set(String::New("speed"), - Integer::New(cpu_infos[i].speed, node_isolate)); + cpu_info->Set(String::New("model"), String::New(ci->model)); - cpu_info->Set(String::New("speed"), Number::New(ci->speed)); ++ cpu_info->Set(String::New("speed"), Number::New(node_isolate, ci->speed)); cpu_info->Set(String::New("times"), times_info); - (*cpus)->Set(i,cpu_info); + + (*cpus)->Set(i, cpu_info); } uv_free_cpu_info(cpu_infos, count);