mirror of https://github.com/lukechilds/node.git
Rhys Jones
15 years ago
committed by
Ryan Dahl
5 changed files with 1232 additions and 16 deletions
@ -0,0 +1,971 @@ |
|||
#include <node_crypto.h> |
|||
#include <v8.h> |
|||
|
|||
#include <node.h> |
|||
#include <node_buffer.h> |
|||
|
|||
#include <string.h> |
|||
#include <stdlib.h> |
|||
|
|||
#include <errno.h> |
|||
|
|||
namespace node { |
|||
|
|||
using namespace v8; |
|||
|
|||
static Persistent<String> errno_symbol; |
|||
static Persistent<String> syscall_symbol; |
|||
static Persistent<String> subject_symbol; |
|||
static Persistent<String> issuer_symbol; |
|||
static Persistent<String> valid_from_symbol; |
|||
static Persistent<String> valid_to_symbol; |
|||
static Persistent<String> name_symbol; |
|||
static Persistent<String> version_symbol; |
|||
|
|||
static int x509_verify_error; |
|||
|
|||
static inline const char *errno_string(int errorno) { |
|||
#define ERRNO_CASE(e) case e: return #e; |
|||
switch (errorno) { |
|||
|
|||
#ifdef EACCES |
|||
ERRNO_CASE(EACCES); |
|||
#endif |
|||
|
|||
#ifdef EADDRINUSE |
|||
ERRNO_CASE(EADDRINUSE); |
|||
#endif |
|||
|
|||
#ifdef EADDRNOTAVAIL |
|||
ERRNO_CASE(EADDRNOTAVAIL); |
|||
#endif |
|||
|
|||
#ifdef EAFNOSUPPORT |
|||
ERRNO_CASE(EAFNOSUPPORT); |
|||
#endif |
|||
|
|||
#ifdef EAGAIN |
|||
ERRNO_CASE(EAGAIN); |
|||
#else |
|||
# ifdef EWOULDBLOCK |
|||
ERRNO_CASE(EWOULDBLOCK); |
|||
# endif |
|||
#endif |
|||
|
|||
#ifdef EALREADY |
|||
ERRNO_CASE(EALREADY); |
|||
#endif |
|||
|
|||
#ifdef EBADF |
|||
ERRNO_CASE(EBADF); |
|||
#endif |
|||
|
|||
#ifdef EBADMSG |
|||
ERRNO_CASE(EBADMSG); |
|||
#endif |
|||
|
|||
#ifdef EBUSY |
|||
ERRNO_CASE(EBUSY); |
|||
#endif |
|||
|
|||
#ifdef ECANCELED |
|||
ERRNO_CASE(ECANCELED); |
|||
#endif |
|||
|
|||
#ifdef ECHILD |
|||
ERRNO_CASE(ECHILD); |
|||
#endif |
|||
|
|||
#ifdef ECONNABORTED |
|||
ERRNO_CASE(ECONNABORTED); |
|||
#endif |
|||
|
|||
#ifdef ECONNREFUSED |
|||
ERRNO_CASE(ECONNREFUSED); |
|||
#endif |
|||
|
|||
#ifdef ECONNRESET |
|||
ERRNO_CASE(ECONNRESET); |
|||
#endif |
|||
|
|||
#ifdef EDEADLK |
|||
ERRNO_CASE(EDEADLK); |
|||
#endif |
|||
|
|||
#ifdef EDESTADDRREQ |
|||
ERRNO_CASE(EDESTADDRREQ); |
|||
#endif |
|||
|
|||
#ifdef EDOM |
|||
ERRNO_CASE(EDOM); |
|||
#endif |
|||
|
|||
#ifdef EDQUOT |
|||
ERRNO_CASE(EDQUOT); |
|||
#endif |
|||
|
|||
#ifdef EEXIST |
|||
ERRNO_CASE(EEXIST); |
|||
#endif |
|||
|
|||
#ifdef EFAULT |
|||
ERRNO_CASE(EFAULT); |
|||
#endif |
|||
|
|||
#ifdef EFBIG |
|||
ERRNO_CASE(EFBIG); |
|||
#endif |
|||
|
|||
#ifdef EHOSTUNREACH |
|||
ERRNO_CASE(EHOSTUNREACH); |
|||
#endif |
|||
|
|||
#ifdef EIDRM |
|||
ERRNO_CASE(EIDRM); |
|||
#endif |
|||
|
|||
#ifdef EILSEQ |
|||
ERRNO_CASE(EILSEQ); |
|||
#endif |
|||
|
|||
#ifdef EINPROGRESS |
|||
ERRNO_CASE(EINPROGRESS); |
|||
#endif |
|||
|
|||
#ifdef EINTR |
|||
ERRNO_CASE(EINTR); |
|||
#endif |
|||
|
|||
#ifdef EINVAL |
|||
ERRNO_CASE(EINVAL); |
|||
#endif |
|||
|
|||
#ifdef EIO |
|||
ERRNO_CASE(EIO); |
|||
#endif |
|||
|
|||
#ifdef EISCONN |
|||
ERRNO_CASE(EISCONN); |
|||
#endif |
|||
|
|||
#ifdef EISDIR |
|||
ERRNO_CASE(EISDIR); |
|||
#endif |
|||
|
|||
#ifdef ELOOP |
|||
ERRNO_CASE(ELOOP); |
|||
#endif |
|||
|
|||
#ifdef EMFILE |
|||
ERRNO_CASE(EMFILE); |
|||
#endif |
|||
|
|||
#ifdef EMLINK |
|||
ERRNO_CASE(EMLINK); |
|||
#endif |
|||
|
|||
#ifdef EMSGSIZE |
|||
ERRNO_CASE(EMSGSIZE); |
|||
#endif |
|||
|
|||
#ifdef EMULTIHOP |
|||
ERRNO_CASE(EMULTIHOP); |
|||
#endif |
|||
|
|||
#ifdef ENAMETOOLONG |
|||
ERRNO_CASE(ENAMETOOLONG); |
|||
#endif |
|||
|
|||
#ifdef ENETDOWN |
|||
ERRNO_CASE(ENETDOWN); |
|||
#endif |
|||
|
|||
#ifdef ENETRESET |
|||
ERRNO_CASE(ENETRESET); |
|||
#endif |
|||
|
|||
#ifdef ENETUNREACH |
|||
ERRNO_CASE(ENETUNREACH); |
|||
#endif |
|||
|
|||
#ifdef ENFILE |
|||
ERRNO_CASE(ENFILE); |
|||
#endif |
|||
|
|||
#ifdef ENOBUFS |
|||
ERRNO_CASE(ENOBUFS); |
|||
#endif |
|||
|
|||
#ifdef ENODATA |
|||
ERRNO_CASE(ENODATA); |
|||
#endif |
|||
|
|||
#ifdef ENODEV |
|||
ERRNO_CASE(ENODEV); |
|||
#endif |
|||
|
|||
#ifdef ENOENT |
|||
ERRNO_CASE(ENOENT); |
|||
#endif |
|||
|
|||
#ifdef ENOEXEC |
|||
ERRNO_CASE(ENOEXEC); |
|||
#endif |
|||
|
|||
#ifdef ENOLCK |
|||
ERRNO_CASE(ENOLCK); |
|||
#endif |
|||
|
|||
#ifdef ENOLINK |
|||
ERRNO_CASE(ENOLINK); |
|||
#endif |
|||
|
|||
#ifdef ENOMEM |
|||
ERRNO_CASE(ENOMEM); |
|||
#endif |
|||
|
|||
#ifdef ENOMSG |
|||
ERRNO_CASE(ENOMSG); |
|||
#endif |
|||
|
|||
#ifdef ENOPROTOOPT |
|||
ERRNO_CASE(ENOPROTOOPT); |
|||
#endif |
|||
|
|||
#ifdef ENOSPC |
|||
ERRNO_CASE(ENOSPC); |
|||
#endif |
|||
|
|||
#ifdef ENOSR |
|||
ERRNO_CASE(ENOSR); |
|||
#endif |
|||
|
|||
#ifdef ENOSTR |
|||
ERRNO_CASE(ENOSTR); |
|||
#endif |
|||
|
|||
#ifdef ENOSYS |
|||
ERRNO_CASE(ENOSYS); |
|||
#endif |
|||
|
|||
#ifdef ENOTCONN |
|||
ERRNO_CASE(ENOTCONN); |
|||
#endif |
|||
|
|||
#ifdef ENOTDIR |
|||
ERRNO_CASE(ENOTDIR); |
|||
#endif |
|||
|
|||
#ifdef ENOTEMPTY |
|||
ERRNO_CASE(ENOTEMPTY); |
|||
#endif |
|||
|
|||
#ifdef ENOTSOCK |
|||
ERRNO_CASE(ENOTSOCK); |
|||
#endif |
|||
|
|||
#ifdef ENOTSUP |
|||
ERRNO_CASE(ENOTSUP); |
|||
#else |
|||
# ifdef EOPNOTSUPP |
|||
ERRNO_CASE(EOPNOTSUPP); |
|||
# endif |
|||
#endif |
|||
|
|||
#ifdef ENOTTY |
|||
ERRNO_CASE(ENOTTY); |
|||
#endif |
|||
|
|||
#ifdef ENXIO |
|||
ERRNO_CASE(ENXIO); |
|||
#endif |
|||
|
|||
|
|||
#ifdef EOVERFLOW |
|||
ERRNO_CASE(EOVERFLOW); |
|||
#endif |
|||
|
|||
#ifdef EPERM |
|||
ERRNO_CASE(EPERM); |
|||
#endif |
|||
|
|||
#ifdef EPIPE |
|||
ERRNO_CASE(EPIPE); |
|||
#endif |
|||
|
|||
#ifdef EPROTO |
|||
ERRNO_CASE(EPROTO); |
|||
#endif |
|||
|
|||
#ifdef EPROTONOSUPPORT |
|||
ERRNO_CASE(EPROTONOSUPPORT); |
|||
#endif |
|||
|
|||
#ifdef EPROTOTYPE |
|||
ERRNO_CASE(EPROTOTYPE); |
|||
#endif |
|||
|
|||
#ifdef ERANGE |
|||
ERRNO_CASE(ERANGE); |
|||
#endif |
|||
|
|||
#ifdef EROFS |
|||
ERRNO_CASE(EROFS); |
|||
#endif |
|||
|
|||
#ifdef ESPIPE |
|||
ERRNO_CASE(ESPIPE); |
|||
#endif |
|||
|
|||
#ifdef ESRCH |
|||
ERRNO_CASE(ESRCH); |
|||
#endif |
|||
|
|||
#ifdef ESTALE |
|||
ERRNO_CASE(ESTALE); |
|||
#endif |
|||
|
|||
#ifdef ETIME |
|||
ERRNO_CASE(ETIME); |
|||
#endif |
|||
|
|||
#ifdef ETIMEDOUT |
|||
ERRNO_CASE(ETIMEDOUT); |
|||
#endif |
|||
|
|||
#ifdef ETXTBSY |
|||
ERRNO_CASE(ETXTBSY); |
|||
#endif |
|||
|
|||
#ifdef EXDEV |
|||
ERRNO_CASE(EXDEV); |
|||
#endif |
|||
|
|||
default: return ""; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
static int verify_callback(int ok, X509_STORE_CTX *ctx) { |
|||
x509_verify_error = ctx->error; |
|||
return(ok); |
|||
} |
|||
|
|||
static inline Local<Value> ErrnoException(int errorno, |
|||
const char *syscall, |
|||
const char *msg = "") { |
|||
Local<String> estring = String::NewSymbol(errno_string(errorno)); |
|||
if (!msg[0]) msg = strerror(errorno); |
|||
Local<String> message = String::NewSymbol(msg); |
|||
|
|||
Local<String> cons1 = String::Concat(estring, String::NewSymbol(", ")); |
|||
Local<String> cons2 = String::Concat(cons1, message); |
|||
|
|||
Local<Value> e = Exception::Error(cons2); |
|||
|
|||
Local<Object> obj = e->ToObject(); |
|||
obj->Set(errno_symbol, Integer::New(errorno)); |
|||
obj->Set(syscall_symbol, String::NewSymbol(syscall)); |
|||
return e; |
|||
} |
|||
|
|||
void SecureContext::Initialize(Handle<Object> target) { |
|||
HandleScope scope; |
|||
|
|||
Local<FunctionTemplate> t = FunctionTemplate::New(SecureContext::New); |
|||
t->InstanceTemplate()->SetInternalFieldCount(1); |
|||
t->SetClassName(String::NewSymbol("SecureContext")); |
|||
|
|||
NODE_SET_PROTOTYPE_METHOD(t, "init", SecureContext::Init); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "setKey", SecureContext::SetKey); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "setCert", SecureContext::SetCert); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "addCACert", SecureContext::AddCACert); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "setCiphers", SecureContext::SetCiphers); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "close", SecureContext::Close); |
|||
|
|||
target->Set(String::NewSymbol("SecureContext"), t->GetFunction()); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureContext::New(const Arguments& args) { |
|||
HandleScope scope; |
|||
SecureContext *p = new SecureContext(); |
|||
p->Wrap(args.Holder()); |
|||
return args.This(); |
|||
} |
|||
|
|||
Handle<Value> SecureContext::Init(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder()); |
|||
|
|||
SSL_METHOD *method = SSLv23_method(); |
|||
|
|||
if (args.Length() == 1) { |
|||
if (!args[0]->IsString()) |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Bad parameter"))); |
|||
|
|||
String::Utf8Value sslmethod(args[0]->ToString()); |
|||
if (strcmp(*sslmethod, "SSLv2_method") == 0) |
|||
method = SSLv2_method(); |
|||
if (strcmp(*sslmethod, "SSLv2_server_method") == 0) |
|||
method = SSLv2_server_method(); |
|||
if (strcmp(*sslmethod, "SSLv2_client_method") == 0) |
|||
method = SSLv2_client_method(); |
|||
if (strcmp(*sslmethod, "SSLv3_method") == 0) |
|||
method = SSLv3_method(); |
|||
if (strcmp(*sslmethod, "SSLv3_server_method") == 0) |
|||
method = SSLv3_server_method(); |
|||
if (strcmp(*sslmethod, "SSLv3_client_method") == 0) |
|||
method = SSLv3_client_method(); |
|||
if (strcmp(*sslmethod, "SSLv23_method") == 0) |
|||
method = SSLv23_method(); |
|||
if (strcmp(*sslmethod, "SSLv23_server_method") == 0) |
|||
method = SSLv23_server_method(); |
|||
if (strcmp(*sslmethod, "SSLv23_client_method") == 0) |
|||
method = SSLv23_client_method(); |
|||
if (strcmp(*sslmethod, "TLSv1_method") == 0) |
|||
method = TLSv1_method(); |
|||
if (strcmp(*sslmethod, "TLSv1_server_method") == 0) |
|||
method = TLSv1_server_method(); |
|||
if (strcmp(*sslmethod, "TLSv1_client_method") == 0) |
|||
method = TLSv1_client_method(); |
|||
} |
|||
|
|||
|
|||
|
|||
sc->pCtx = SSL_CTX_new(method); |
|||
// Enable session caching?
|
|||
SSL_CTX_set_session_cache_mode(sc->pCtx, SSL_SESS_CACHE_SERVER); |
|||
// SSL_CTX_set_session_cache_mode(sc->pCtx,SSL_SESS_CACHE_OFF);
|
|||
|
|||
sc->caStore = X509_STORE_new(); |
|||
return True(); |
|||
} |
|||
|
|||
Handle<Value> SecureContext::SetKey(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder()); |
|||
|
|||
if (args.Length() != 1 || |
|||
!args[0]->IsString()) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Bad parameter"))); |
|||
} |
|||
String::Utf8Value keyPem(args[0]->ToString()); |
|||
|
|||
BIO *bp = NULL; |
|||
EVP_PKEY* pkey; |
|||
bp = BIO_new(BIO_s_mem()); |
|||
if (!BIO_write(bp, *keyPem, strlen(*keyPem))) |
|||
return False(); |
|||
|
|||
pkey = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL); |
|||
if (pkey == NULL) |
|||
return False(); |
|||
|
|||
SSL_CTX_use_PrivateKey(sc->pCtx, pkey); |
|||
BIO_free(bp); |
|||
|
|||
return True(); |
|||
} |
|||
|
|||
Handle<Value> SecureContext::SetCert(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder()); |
|||
|
|||
if (args.Length() != 1 || |
|||
!args[0]->IsString()) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Bad parameter"))); |
|||
} |
|||
String::Utf8Value certPem(args[0]->ToString()); |
|||
|
|||
BIO *bp = NULL; |
|||
X509 * x509; |
|||
bp = BIO_new(BIO_s_mem()); |
|||
if (!BIO_write(bp, *certPem, strlen(*certPem))) |
|||
return False(); |
|||
|
|||
x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL); |
|||
if (x509 == NULL) |
|||
return False(); |
|||
|
|||
SSL_CTX_use_certificate(sc->pCtx, x509); |
|||
BIO_free(bp); |
|||
X509_free(x509); |
|||
|
|||
return True(); |
|||
} |
|||
|
|||
Handle<Value> SecureContext::AddCACert(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder()); |
|||
|
|||
if (args.Length() != 1 || |
|||
!args[0]->IsString()) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Bad parameter"))); |
|||
} |
|||
String::Utf8Value certPem(args[0]->ToString()); |
|||
|
|||
BIO *bp = NULL; |
|||
X509 *x509; |
|||
bp = BIO_new(BIO_s_mem()); |
|||
if (!BIO_write(bp, *certPem, strlen(*certPem))) |
|||
return False(); |
|||
|
|||
x509 = PEM_read_bio_X509(bp, NULL, NULL, NULL); |
|||
if (x509 == NULL) |
|||
return False(); |
|||
|
|||
X509_STORE_add_cert(sc->caStore, x509); |
|||
|
|||
BIO_free(bp); |
|||
X509_free(x509); |
|||
|
|||
return True(); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureContext::SetCiphers(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder()); |
|||
|
|||
if (args.Length() != 1 || |
|||
!args[0]->IsString()) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Bad parameter"))); |
|||
} |
|||
String::Utf8Value ciphers(args[0]->ToString()); |
|||
SSL_CTX_set_cipher_list(sc->pCtx, *ciphers); |
|||
|
|||
return True(); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureContext::Close(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder()); |
|||
|
|||
if (sc->pCtx != NULL) { |
|||
SSL_CTX_free(sc->pCtx); |
|||
return True(); |
|||
} |
|||
return False(); |
|||
} |
|||
|
|||
|
|||
|
|||
void SecureStream::Initialize(Handle<Object> target) { |
|||
HandleScope scope; |
|||
|
|||
Local<FunctionTemplate> t = FunctionTemplate::New(SecureStream::New); |
|||
t->InstanceTemplate()->SetInternalFieldCount(1); |
|||
t->SetClassName(String::NewSymbol("SecureStream")); |
|||
|
|||
NODE_SET_PROTOTYPE_METHOD(t, "readInject", |
|||
SecureStream::ReadInject); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "readExtract", |
|||
SecureStream::ReadExtract); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "writeInject", |
|||
SecureStream::WriteInject); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "writeExtract", |
|||
SecureStream::WriteExtract); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "writeCanExtract", |
|||
SecureStream::WriteCanExtract); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "getPeerCertificate", |
|||
SecureStream::GetPeerCertificate); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "isInitFinished", |
|||
SecureStream::IsInitFinished); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "verifyPeer", |
|||
SecureStream::VerifyPeer); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "getCurrentCipher", |
|||
SecureStream::GetCurrentCipher); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", |
|||
SecureStream::Shutdown); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "close", |
|||
SecureStream::Close); |
|||
|
|||
target->Set(String::NewSymbol("SecureStream"), t->GetFunction()); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureStream::New(const Arguments& args) { |
|||
HandleScope scope; |
|||
SecureStream *p = new SecureStream(); |
|||
p->Wrap(args.Holder()); |
|||
|
|||
if (args.Length() != 2 || |
|||
!args[0]->IsObject() || |
|||
!args[1]->IsNumber()) { |
|||
return ThrowException(Exception::Error(String::New("Bad arguments."))); |
|||
} |
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args[0]->ToObject()); |
|||
int isServer = args[1]->Int32Value(); |
|||
|
|||
p->pSSL = SSL_new(sc->pCtx); |
|||
p->pbioRead = BIO_new(BIO_s_mem()); |
|||
p->pbioWrite = BIO_new(BIO_s_mem()); |
|||
SSL_set_bio(p->pSSL, p->pbioRead, p->pbioWrite); |
|||
p->server = isServer>0; |
|||
if (p->server) { |
|||
SSL_set_accept_state(p->pSSL); |
|||
} else { |
|||
SSL_set_connect_state(p->pSSL); |
|||
} |
|||
|
|||
return args.This(); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureStream::ReadInject(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (args.Length() < 3) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Takes 3 parameters"))); |
|||
} |
|||
|
|||
if (!Buffer::HasInstance(args[0])) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Second argument should be a buffer"))); |
|||
} |
|||
|
|||
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject()); |
|||
|
|||
size_t off = args[1]->Int32Value(); |
|||
if (off >= buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Offset is out of bounds"))); |
|||
} |
|||
|
|||
size_t len = args[2]->Int32Value(); |
|||
if (off + len > buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Length is extends beyond buffer"))); |
|||
} |
|||
|
|||
int bytes_written = BIO_write(ss->pbioRead, (char*)buffer->data() + off, len); |
|||
|
|||
if (bytes_written < 0) { |
|||
if (errno == EAGAIN || errno == EINTR) return Null(); |
|||
return ThrowException(ErrnoException(errno, "read")); |
|||
} |
|||
|
|||
return scope.Close(Integer::New(bytes_written)); |
|||
} |
|||
|
|||
Handle<Value> SecureStream::ReadExtract(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (args.Length() < 3) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Takes 3 parameters"))); |
|||
} |
|||
|
|||
if (!Buffer::HasInstance(args[0])) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Second argument should be a buffer"))); |
|||
} |
|||
|
|||
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject()); |
|||
|
|||
size_t off = args[1]->Int32Value(); |
|||
if (off >= buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Offset is out of bounds"))); |
|||
} |
|||
|
|||
size_t len = args[2]->Int32Value(); |
|||
if (off + len > buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Length is extends beyond buffer"))); |
|||
} |
|||
|
|||
int bytes_read; |
|||
|
|||
if (!SSL_is_init_finished(ss->pSSL)) { |
|||
if (ss->server) { |
|||
bytes_read = SSL_accept(ss->pSSL); |
|||
} else { |
|||
bytes_read = SSL_connect(ss->pSSL); |
|||
} |
|||
if (bytes_read < 0) { |
|||
int err; |
|||
if ((err = SSL_get_error(ss->pSSL, bytes_read)) == SSL_ERROR_WANT_READ) { |
|||
return scope.Close(Integer::New(0)); |
|||
} |
|||
} |
|||
return scope.Close(Integer::New(0)); |
|||
} |
|||
|
|||
bytes_read = SSL_read(ss->pSSL, (char*)buffer->data() + off, len); |
|||
if (bytes_read < 0) { |
|||
int err = SSL_get_error(ss->pSSL, bytes_read); |
|||
if (err == SSL_ERROR_WANT_READ) { |
|||
return scope.Close(Integer::New(0)); |
|||
} |
|||
// SSL read error
|
|||
return scope.Close(Integer::New(-2)); |
|||
} |
|||
|
|||
if (bytes_read < 0) { |
|||
if (errno == EAGAIN || errno == EINTR) return Null(); |
|||
return ThrowException(ErrnoException(errno, "read")); |
|||
} |
|||
|
|||
return scope.Close(Integer::New(bytes_read)); |
|||
} |
|||
|
|||
Handle<Value> SecureStream::WriteCanExtract(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
int bytes_pending = BIO_pending(ss->pbioWrite); |
|||
return scope.Close(Integer::New(bytes_pending)); |
|||
} |
|||
|
|||
Handle<Value> SecureStream::WriteExtract(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (args.Length() < 3) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Takes 3 parameters"))); |
|||
} |
|||
|
|||
if (!Buffer::HasInstance(args[0])) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Second argument should be a buffer"))); |
|||
} |
|||
|
|||
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject()); |
|||
|
|||
size_t off = args[1]->Int32Value(); |
|||
if (off >= buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Offset is out of bounds"))); |
|||
} |
|||
|
|||
size_t len = args[2]->Int32Value(); |
|||
if (off + len > buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Length is extends beyond buffer"))); |
|||
} |
|||
|
|||
int bytes_read = BIO_read(ss->pbioWrite, (char*)buffer->data() + off, len); |
|||
|
|||
return scope.Close(Integer::New(bytes_read)); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureStream::WriteInject(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (args.Length() < 3) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Takes 3 parameters"))); |
|||
} |
|||
|
|||
if (!Buffer::HasInstance(args[0])) { |
|||
return ThrowException(Exception::TypeError( |
|||
String::New("Second argument should be a buffer"))); |
|||
} |
|||
|
|||
Buffer * buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject()); |
|||
|
|||
size_t off = args[1]->Int32Value(); |
|||
if (off >= buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Offset is out of bounds"))); |
|||
} |
|||
|
|||
size_t len = args[2]->Int32Value(); |
|||
if (off + len > buffer->length()) { |
|||
return ThrowException(Exception::Error( |
|||
String::New("Length is extends beyond buffer"))); |
|||
} |
|||
|
|||
if (!SSL_is_init_finished(ss->pSSL)) { |
|||
int s; |
|||
if (ss->server) { |
|||
s = SSL_accept(ss->pSSL); |
|||
} else { |
|||
s = SSL_connect(ss->pSSL); |
|||
} |
|||
return scope.Close(Integer::New(0)); |
|||
} |
|||
int bytes_written = SSL_write(ss->pSSL, (char*)buffer->data() + off, len); |
|||
|
|||
return scope.Close(Integer::New(bytes_written)); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureStream::GetPeerCertificate(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (ss->pSSL == NULL) return Undefined(); |
|||
Local<Object> info = Object::New(); |
|||
X509* peer_cert = SSL_get_peer_certificate(ss->pSSL); |
|||
if (peer_cert != NULL) { |
|||
char* subject = X509_NAME_oneline(X509_get_subject_name(peer_cert), 0, 0); |
|||
if (subject != NULL) { |
|||
info->Set(subject_symbol, String::New(subject)); |
|||
OPENSSL_free(subject); |
|||
} |
|||
char* issuer = X509_NAME_oneline(X509_get_issuer_name(peer_cert), 0, 0); |
|||
if (subject != NULL) { |
|||
info->Set(issuer_symbol, String::New(issuer)); |
|||
OPENSSL_free(issuer); |
|||
} |
|||
char buf[256]; |
|||
BIO* bio = BIO_new(BIO_s_mem()); |
|||
ASN1_TIME_print(bio, X509_get_notBefore(peer_cert)); |
|||
memset(buf, 0, sizeof(buf)); |
|||
BIO_read(bio, buf, sizeof(buf) - 1); |
|||
info->Set(valid_from_symbol, String::New(buf)); |
|||
ASN1_TIME_print(bio, X509_get_notAfter(peer_cert)); |
|||
memset(buf, 0, sizeof(buf)); |
|||
BIO_read(bio, buf, sizeof(buf) - 1); |
|||
BIO_free(bio); |
|||
info->Set(valid_to_symbol, String::New(buf)); |
|||
|
|||
X509_free(peer_cert); |
|||
} |
|||
return scope.Close(info); |
|||
} |
|||
|
|||
Handle<Value> SecureStream::Shutdown(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (ss->pSSL == NULL) return False(); |
|||
if (SSL_shutdown(ss->pSSL) == 1) { |
|||
return True(); |
|||
} |
|||
return False(); |
|||
} |
|||
|
|||
Handle<Value> SecureStream::IsInitFinished(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (ss->pSSL == NULL) return False(); |
|||
if (SSL_is_init_finished(ss->pSSL)) { |
|||
return True(); |
|||
} |
|||
return False(); |
|||
} |
|||
|
|||
|
|||
Handle<Value> SecureStream::VerifyPeer(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args[0]->ToObject()); |
|||
|
|||
if (ss->pSSL == NULL) return False(); |
|||
if (sc->caStore == NULL) return False(); |
|||
|
|||
X509 *cert = SSL_get_peer_certificate(ss->pSSL); |
|||
STACK_OF(X509) *certChain = SSL_get_peer_cert_chain(ss->pSSL); |
|||
X509_STORE_set_verify_cb_func(sc->caStore, verify_callback); |
|||
X509_STORE_CTX *storeCtx = X509_STORE_CTX_new(); |
|||
X509_STORE_CTX_init(storeCtx, sc->caStore, cert, certChain); |
|||
|
|||
x509_verify_error = 0; |
|||
// OS X Bug in openssl : x509_verify_cert is always true?
|
|||
// This is why we have our global.
|
|||
X509_verify_cert(storeCtx); |
|||
|
|||
X509_STORE_CTX_free(storeCtx); |
|||
|
|||
// Can also check for:
|
|||
// X509_V_ERR_CERT_HAS_EXPIRED
|
|||
// X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
|
|||
// X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
|
|||
// X509_V_ERR_INVALID_CA
|
|||
// X509_V_ERR_PATH_LENGTH_EXCEEDED
|
|||
// X509_V_ERR_INVALID_PURPOSE
|
|||
// X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
|
|||
|
|||
// printf("%s\n", X509_verify_cert_error_string(x509_verify_error));
|
|||
|
|||
if (!x509_verify_error) return True(); |
|||
return False(); |
|||
} |
|||
|
|||
Handle<Value> SecureStream::GetCurrentCipher(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
SSL_CIPHER *c; |
|||
|
|||
if ( ss->pSSL == NULL ) return Undefined(); |
|||
c = SSL_get_current_cipher(ss->pSSL); |
|||
if ( c == NULL ) return Undefined(); |
|||
Local<Object> info = Object::New(); |
|||
const char *cipher_name = SSL_CIPHER_get_name(c); |
|||
info->Set(name_symbol, String::New(cipher_name)); |
|||
const char *cipher_version = SSL_CIPHER_get_version(c); |
|||
info->Set(version_symbol, String::New(cipher_version)); |
|||
return scope.Close(info); |
|||
} |
|||
|
|||
Handle<Value> SecureStream::Close(const Arguments& args) { |
|||
HandleScope scope; |
|||
|
|||
SecureStream *ss = ObjectWrap::Unwrap<SecureStream>(args.Holder()); |
|||
|
|||
if (ss->pSSL != NULL) { |
|||
SSL_free(ss->pSSL); |
|||
ss->pSSL = NULL; |
|||
} |
|||
return True(); |
|||
} |
|||
|
|||
|
|||
|
|||
void InitCrypto(Handle<Object> target) { |
|||
HandleScope scope; |
|||
|
|||
SSL_library_init(); |
|||
OpenSSL_add_ssl_algorithms(); |
|||
SSL_load_error_strings(); |
|||
ERR_load_crypto_strings(); |
|||
|
|||
SecureContext::Initialize(target); |
|||
SecureStream::Initialize(target); |
|||
|
|||
subject_symbol = NODE_PSYMBOL("subject"); |
|||
issuer_symbol = NODE_PSYMBOL("issuer"); |
|||
valid_from_symbol = NODE_PSYMBOL("valid_from"); |
|||
valid_to_symbol = NODE_PSYMBOL("valid_to"); |
|||
name_symbol = NODE_PSYMBOL("name"); |
|||
version_symbol = NODE_PSYMBOL("version"); |
|||
} |
|||
|
|||
|
|||
|
|||
} // namespace node
|
|||
|
@ -0,0 +1,73 @@ |
|||
#ifndef SRC_NODE_CRYPTO_H_ |
|||
#define SRC_NODE_CRYPTO_H_ |
|||
|
|||
#include <node.h> |
|||
#include <node_object_wrap.h> |
|||
#include <v8.h> |
|||
|
|||
#include <openssl/ssl.h> |
|||
#include <openssl/err.h> |
|||
|
|||
namespace node { |
|||
|
|||
class SecureContext : ObjectWrap { |
|||
public: |
|||
static void Initialize(v8::Handle<v8::Object> target); |
|||
|
|||
SSL_CTX *pCtx; |
|||
X509_STORE *caStore; |
|||
|
|||
protected: |
|||
static v8::Handle<v8::Value> New(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> Init(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> SetKey(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> SetCert(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> AddCACert(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> SetCiphers(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> Close(const v8::Arguments& args); |
|||
|
|||
SecureContext() : ObjectWrap() { |
|||
} |
|||
|
|||
~SecureContext() { |
|||
// Free up
|
|||
} |
|||
|
|||
private: |
|||
}; |
|||
|
|||
class SecureStream : ObjectWrap { |
|||
public: |
|||
static void Initialize(v8::Handle<v8::Object> target); |
|||
|
|||
protected: |
|||
static v8::Handle<v8::Value> New(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> ReadInject(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> ReadExtract(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> WriteCanExtract(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> WriteExtract(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> WriteInject(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> GetPeerCertificate(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> IsInitFinished(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> VerifyPeer(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> GetCurrentCipher(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> Shutdown(const v8::Arguments& args); |
|||
static v8::Handle<v8::Value> Close(const v8::Arguments& args); |
|||
|
|||
SecureStream() : ObjectWrap() { |
|||
} |
|||
|
|||
~SecureStream() { |
|||
} |
|||
|
|||
private: |
|||
BIO *pbioRead; |
|||
BIO *pbioWrite; |
|||
SSL *pSSL; |
|||
bool server; |
|||
}; |
|||
|
|||
void InitCrypto(v8::Handle<v8::Object> target); |
|||
} |
|||
|
|||
#endif // SRC_NODE_CRYPTO_H_
|
Loading…
Reference in new issue