TLS: better error reporting at binding layer

Closes GH-612.
This commit is contained in:
Ryan Dahl
2011-02-01 13:00:00 -08:00
parent ff7fc093a1
commit 2ff593ad23
3 changed files with 114 additions and 82 deletions

View File

@@ -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)) {

View File

@@ -287,28 +287,55 @@ Handle<Value> 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<Value> 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<Object> target) {
HandleScope scope;
@@ -440,7 +467,7 @@ Handle<Value> Connection::New(const Arguments& args) {
Handle<Value> Connection::EncIn(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (args.Length() < 3) {
return ThrowException(Exception::TypeError(
@@ -468,12 +495,9 @@ Handle<Value> 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<Value> Connection::EncIn(const Arguments& args) {
Handle<Value> Connection::ClearOut(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (args.Length() < 3) {
return ThrowException(Exception::TypeError(
@@ -510,24 +534,23 @@ Handle<Value> 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<Value> Connection::ClearOut(const Arguments& args) {
Handle<Value> Connection::ClearPending(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(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<Value> Connection::ClearPending(const Arguments& args) {
Handle<Value> Connection::EncPending(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(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<Value> Connection::EncPending(const Arguments& args) {
Handle<Value> Connection::EncOut(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (args.Length() < 3) {
return ThrowException(Exception::TypeError(
@@ -582,7 +607,9 @@ Handle<Value> 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<Value> Connection::EncOut(const Arguments& args) {
Handle<Value> Connection::ClearIn(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (args.Length() < 3) {
return ThrowException(Exception::TypeError(
@@ -620,25 +647,21 @@ Handle<Value> 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<Value> Connection::ClearIn(const Arguments& args) {
Handle<Value> Connection::GetPeerCertificate(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (ss->ssl_ == NULL) return Undefined();
Local<Object> info = Object::New();
@@ -719,36 +742,30 @@ Handle<Value> Connection::GetPeerCertificate(const Arguments& args) {
Handle<Value> Connection::Start(const Arguments& args) {
HandleScope scope;
int rv;
Connection *ss = ObjectWrap::Unwrap<Connection>(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<Value> Connection::Shutdown(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (ss->ssl_ == NULL) return False();
int r = SSL_shutdown(ss->ssl_);
@@ -760,7 +777,7 @@ Handle<Value> Connection::Shutdown(const Arguments& args) {
Handle<Value> Connection::ReceivedShutdown(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(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<Value> Connection::ReceivedShutdown(const Arguments& args) {
Handle<Value> Connection::IsInitFinished(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(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<Value> Connection::IsInitFinished(const Arguments& args) {
Handle<Value> Connection::VerifyError(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (ss->ssl_ == NULL) return Null();
@@ -926,7 +945,8 @@ Handle<Value> Connection::VerifyError(const Arguments& args) {
Handle<Value> Connection::GetCurrentCipher(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
OPENSSL_CONST SSL_CIPHER *c;
if ( ss->ssl_ == NULL ) return Undefined();
@@ -943,7 +963,7 @@ Handle<Value> Connection::GetCurrentCipher(const Arguments& args) {
Handle<Value> Connection::Close(const Arguments& args) {
HandleScope scope;
Connection *ss = ObjectWrap::Unwrap<Connection>(args.Holder());
Connection *ss = Connection::Unwrap(args);
if (ss->ssl_ != NULL) {
SSL_free(ss->ssl_);

View File

@@ -74,6 +74,15 @@ class Connection : ObjectWrap {
static v8::Handle<v8::Value> Start(const v8::Arguments& args);
static v8::Handle<v8::Value> 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<Connection>(args.Holder());
ss->ClearError();
return ss;
}
Connection() : ObjectWrap() {
bio_read_ = bio_write_ = NULL;
ssl_ = NULL;