diff --git a/lib/tls.js b/lib/tls.js index 3613b8bb8..1fb43668d 100644 --- a/lib/tls.js +++ b/lib/tls.js @@ -192,11 +192,11 @@ CryptoStream.prototype._blow = function() { var pool = new Buffer(4096); // alloc every time? do { - try { - chunkBytes = this._blower(pool, bytesRead, pool.length - bytesRead); - } catch (e) { + chunkBytes = this._blower(pool, bytesRead, pool.length - bytesRead); + + if (this.pair._ssl && this.pair._ssl.error) { if (this.pair._secureEstablished) { - this.pair._error(e); + this.pair._error(); } else { this.pair._destroy(); } @@ -244,7 +244,6 @@ CryptoStream.prototype._blow = function() { // }); // CryptoStream.prototype._suck = function() { - var rv; var havePending = this._pending.length > 0; while (this._pending.length > 0) { @@ -253,18 +252,18 @@ CryptoStream.prototype._suck = function() { assert(this._pending.length === this._pendingCallbacks.length); - try { - rv = this._sucker(tmp); - } catch (e) { + var rv = this._sucker(tmp); + + if (this.pair._ssl && this.pair._ssl.error) { if (this.pair._secureEstablished) { - this.pair._error(e); + this.pair._error(); } else { this.pair._destroy(); } return; } - if (rv === 0) { + if (rv === 0 || rv < 0) { this._pending.unshift(tmp); this._pendingCallbacks.unshift(cb); break; @@ -453,9 +452,10 @@ SecurePair.prototype._cycle = function() { }; -SecurePair.prototype._destroy = function(err) { +SecurePair.prototype._destroy = function() { if (!this._done) { this._done = true; + this._ssl.error = null; this._ssl.close(); this._ssl = null; @@ -469,7 +469,10 @@ SecurePair.prototype._destroy = function(err) { }; -SecurePair.prototype._error = function(err) { +SecurePair.prototype._error = function() { + var err = this._ssl.error; + this._ssl.error = null; + if (this._isServer && this._rejectUnauthorized && /peer did not return a certificate/.test(err.message)) { diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 37e28690d..5cfbef5fe 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -287,28 +287,55 @@ Handle SecureContext::Close(const Arguments& args) { return False(); } -char ssl_error_buf[512]; +#ifdef SSL_PRINT_DEBUG +# define DEBUG_PRINT(...) fprintf (stderr, __VA_ARGS__) +#else +# define DEBUG_PRINT(...) +#endif -static int serr(SSL *ssl, const char* func, int rv) { - if (rv >= 0) { - return rv; - } - int err = SSL_get_error(ssl, rv); - if (err != SSL_ERROR_WANT_WRITE && - err != SSL_ERROR_WANT_READ) { - ERR_error_string_n(ERR_get_error(), &ssl_error_buf[0], sizeof(ssl_error_buf)); - /* fprintf(stderr, "[%p] SSL: %s failed: (%d:%d) %s\n", ssl, func, err, rv, buf); */ - return rv; - } else if (err == SSL_ERROR_WANT_WRITE) { - /* fprintf(stderr, "[%p] SSL: %s want write\n", ssl, func); */ +int Connection::HandleError(const char* func, int rv, bool ignore_error) { + if (rv >= 0) return rv; + + int err = SSL_get_error(ssl_, rv); + + if (err == SSL_ERROR_WANT_WRITE) { + DEBUG_PRINT("[%p] SSL: %s want write\n", ssl_, func); + return 0; + } else if (err == SSL_ERROR_WANT_READ) { - /* fprintf(stderr, "[%p] SSL: %s want read\n", ssl, func); */ + DEBUG_PRINT("[%p] SSL: %s want read\n", ssl_, func); + return 0; + + } else { + static char ssl_error_buf[512]; + ERR_error_string_n(err, ssl_error_buf, sizeof(ssl_error_buf)); + + if (!ignore_error) { + HandleScope scope; + Local e = Exception::Error(String::New(ssl_error_buf)); + handle_->Set(String::New("error"), e); + } + + DEBUG_PRINT("[%p] SSL: %s failed: (%d:%d) %s\n", ssl_, func, err, rv, ssl_error_buf); + + return rv; } return 0; } + +void Connection::ClearError() { +#ifndef NDEBUG + HandleScope scope; + + // We should clear the error in JS-land + assert(handle_->Get(String::New("error"))->BooleanValue() == false); +#endif // NDEBUG +} + + void Connection::Initialize(Handle target) { HandleScope scope; @@ -440,7 +467,7 @@ Handle Connection::New(const Arguments& args) { Handle Connection::EncIn(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (args.Length() < 3) { return ThrowException(Exception::TypeError( @@ -468,12 +495,9 @@ Handle Connection::EncIn(const Arguments& args) { String::New("Length is extends beyond buffer"))); } - int bytes_written = serr(ss->ssl_, "BIO_write", BIO_write(ss->bio_read_, (char*)buffer_data + off, len)); + int bytes_written = BIO_write(ss->bio_read_, (char*)buffer_data + off, len); - if (bytes_written < 0) { - if (errno == EAGAIN || errno == EINTR) return Null(); - return ThrowException(ErrnoException(errno, "read")); - } + ss->HandleError("BIO_write", bytes_written); return scope.Close(Integer::New(bytes_written)); } @@ -482,7 +506,7 @@ Handle Connection::EncIn(const Arguments& args) { Handle Connection::ClearOut(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (args.Length() < 3) { return ThrowException(Exception::TypeError( @@ -510,24 +534,23 @@ Handle Connection::ClearOut(const Arguments& args) { String::New("Length is extends beyond buffer"))); } - int bytes_read; if (!SSL_is_init_finished(ss->ssl_)) { + int rv; + if (ss->is_server_) { - bytes_read = serr(ss->ssl_, "SSL_accept:ClearOut", SSL_accept(ss->ssl_)); + rv = SSL_accept(ss->ssl_); + ss->HandleError("SSL_accept:ClearOut", rv); } else { - bytes_read = serr(ss->ssl_, "SSL_connect:ClearOut", SSL_connect(ss->ssl_)); + rv = SSL_connect(ss->ssl_); + ss->HandleError("SSL_connect:ClearOut", rv); } - if (bytes_read < 0) { - return ThrowException(Exception::Error(v8::String::New(ssl_error_buf))); - } - return scope.Close(Integer::New(0)); + + if (rv < 0) return scope.Close(Integer::New(rv)); } - bytes_read = serr(ss->ssl_, "SSL_read:ClearOut", SSL_read(ss->ssl_, (char*)buffer_data + off, len)); - if (bytes_read < 0) { - return ThrowException(Exception::Error(v8::String::New(ssl_error_buf))); - } + int bytes_read = SSL_read(ss->ssl_, (char*)buffer_data + off, len); + ss->HandleError("SSL_read:ClearOut", bytes_read); return scope.Close(Integer::New(bytes_read)); } @@ -536,7 +559,8 @@ Handle Connection::ClearOut(const Arguments& args) { Handle Connection::ClearPending(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); + int bytes_pending = BIO_pending(ss->bio_read_); return scope.Close(Integer::New(bytes_pending)); } @@ -545,7 +569,8 @@ Handle Connection::ClearPending(const Arguments& args) { Handle Connection::EncPending(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); + int bytes_pending = BIO_pending(ss->bio_write_); return scope.Close(Integer::New(bytes_pending)); } @@ -554,7 +579,7 @@ Handle Connection::EncPending(const Arguments& args) { Handle Connection::EncOut(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (args.Length() < 3) { return ThrowException(Exception::TypeError( @@ -582,7 +607,9 @@ Handle Connection::EncOut(const Arguments& args) { String::New("Length is extends beyond buffer"))); } - int bytes_read = serr(ss->ssl_, "BIO_read:EncOut", BIO_read(ss->bio_write_, (char*)buffer_data + off, len)); + int bytes_read = BIO_read(ss->bio_write_, (char*)buffer_data + off, len); + + ss->HandleError("BIO_read:EncOut", bytes_read, true); return scope.Close(Integer::New(bytes_read)); } @@ -591,7 +618,7 @@ Handle Connection::EncOut(const Arguments& args) { Handle Connection::ClearIn(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (args.Length() < 3) { return ThrowException(Exception::TypeError( @@ -620,25 +647,21 @@ Handle Connection::ClearIn(const Arguments& args) { } if (!SSL_is_init_finished(ss->ssl_)) { - int s; + int rv; if (ss->is_server_) { - s = serr(ss->ssl_, "SSL_accept:ClearIn", SSL_accept(ss->ssl_)); + rv = SSL_accept(ss->ssl_); + ss->HandleError("SSL_accept:ClearIn", rv); } else { - s = serr(ss->ssl_, "SSL_connect:ClearIn", SSL_connect(ss->ssl_)); + rv = SSL_connect(ss->ssl_); + ss->HandleError("SSL_connect:ClearIn", rv); } - if (s < 0) { - return ThrowException(Exception::Error(v8::String::New(ssl_error_buf))); - } - - return scope.Close(Integer::New(0)); + if (rv < 0) return scope.Close(Integer::New(rv)); } - int bytes_written = serr(ss->ssl_, "SSL_write:ClearIn", SSL_write(ss->ssl_, (char*)buffer_data + off, len)); + int bytes_written = SSL_write(ss->ssl_, (char*)buffer_data + off, len); - if (bytes_written < 0) { - return ThrowException(Exception::Error(v8::String::New(ssl_error_buf))); - } + ss->HandleError("SSL_write:ClearIn", bytes_written); return scope.Close(Integer::New(bytes_written)); } @@ -647,7 +670,7 @@ Handle Connection::ClearIn(const Arguments& args) { Handle Connection::GetPeerCertificate(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (ss->ssl_ == NULL) return Undefined(); Local info = Object::New(); @@ -719,36 +742,30 @@ Handle Connection::GetPeerCertificate(const Arguments& args) { Handle Connection::Start(const Arguments& args) { HandleScope scope; - int rv; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (!SSL_is_init_finished(ss->ssl_)) { + int rv; if (ss->is_server_) { - rv = serr(ss->ssl_, "SSL_accept:Start", SSL_accept(ss->ssl_)); + rv = SSL_accept(ss->ssl_); + ss->HandleError("SSL_accept:Start", rv); } else { - rv = serr(ss->ssl_, "SSL_connect:Start", SSL_connect(ss->ssl_)); + rv = SSL_connect(ss->ssl_); + ss->HandleError("SSL_connect:Start", rv); } - if (rv < 0) { - return ThrowException(Exception::Error(v8::String::New(ssl_error_buf))); - } - - if (rv == 1) { - return True(); - } else { - return False(); - } + return scope.Close(Integer::New(rv)); } - return True(); + return scope.Close(Integer::New(0)); } Handle Connection::Shutdown(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (ss->ssl_ == NULL) return False(); int r = SSL_shutdown(ss->ssl_); @@ -760,7 +777,7 @@ Handle Connection::Shutdown(const Arguments& args) { Handle Connection::ReceivedShutdown(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (ss->ssl_ == NULL) return False(); int r = SSL_get_shutdown(ss->ssl_); @@ -773,7 +790,9 @@ Handle Connection::ReceivedShutdown(const Arguments& args) { Handle Connection::IsInitFinished(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + + Connection *ss = Connection::Unwrap(args); + if (ss->ssl_ == NULL) return False(); return SSL_is_init_finished(ss->ssl_) ? True() : False(); } @@ -782,7 +801,7 @@ Handle Connection::IsInitFinished(const Arguments& args) { Handle Connection::VerifyError(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (ss->ssl_ == NULL) return Null(); @@ -926,7 +945,8 @@ Handle Connection::VerifyError(const Arguments& args) { Handle Connection::GetCurrentCipher(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); + OPENSSL_CONST SSL_CIPHER *c; if ( ss->ssl_ == NULL ) return Undefined(); @@ -943,7 +963,7 @@ Handle Connection::GetCurrentCipher(const Arguments& args) { Handle Connection::Close(const Arguments& args) { HandleScope scope; - Connection *ss = ObjectWrap::Unwrap(args.Holder()); + Connection *ss = Connection::Unwrap(args); if (ss->ssl_ != NULL) { SSL_free(ss->ssl_); diff --git a/src/node_crypto.h b/src/node_crypto.h index 73120aa86..c32086446 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -74,6 +74,15 @@ class Connection : ObjectWrap { static v8::Handle Start(const v8::Arguments& args); static v8::Handle Close(const v8::Arguments& args); + int HandleError(const char* func, int rv, bool ignore_error=false); + void ClearError(); + + static Connection* Unwrap(const v8::Arguments& args) { + Connection* ss = ObjectWrap::Unwrap(args.Holder()); + ss->ClearError(); + return ss; + } + Connection() : ObjectWrap() { bio_read_ = bio_write_ = NULL; ssl_ = NULL;