mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
Initial openssl support for net2
This commit is contained in:
parent
fdae14070c
commit
fb3a9cd0d8
176
lib/net.js
176
lib/net.js
@ -9,7 +9,6 @@ var debugLevel = process.env['NODE_DEBUG'] ? 1 : 0;
|
||||
function debug () {
|
||||
if (debugLevel > 0) sys.error.apply(this, arguments);
|
||||
}
|
||||
|
||||
var binding = process.binding('net');
|
||||
|
||||
// Note about Buffer interface:
|
||||
@ -45,6 +44,14 @@ var EINPROGRESS = binding.EINPROGRESS;
|
||||
var ENOENT = binding.ENOENT;
|
||||
var END_OF_FILE = 42;
|
||||
|
||||
// Do we have openssl crypto?
|
||||
try {
|
||||
var SecureContext = process.binding('crypto').SecureContext;
|
||||
var SecureStream = process.binding('crypto').SecureStream;
|
||||
var crypto = true;
|
||||
} catch (e) {
|
||||
var crypto = false;
|
||||
}
|
||||
|
||||
// IDLE TIMEOUTS
|
||||
//
|
||||
@ -246,6 +253,16 @@ function allocNewPool () {
|
||||
pool.used = 0;
|
||||
}
|
||||
|
||||
var securePool = null;
|
||||
function allocNewSecurePool () {
|
||||
securePool = new Buffer(40*1024);
|
||||
}
|
||||
var emptyBuffer = null;
|
||||
function allocEmptyBuffer () {
|
||||
emptyBuffer = new Buffer(1);
|
||||
emptyBuffer.sent = 0;
|
||||
emptyBuffer.length = 0;
|
||||
}
|
||||
|
||||
function _doFlush () {
|
||||
var socket = this.socket;
|
||||
@ -271,20 +288,46 @@ function initStream (self) {
|
||||
|
||||
//debug('pool.used ' + pool.used);
|
||||
var bytesRead;
|
||||
var secureBytesRead;
|
||||
|
||||
try {
|
||||
bytesRead = read(self.fd,
|
||||
if (self.secure) {
|
||||
if (!securePool) allocNewSecurePool();
|
||||
secureBytesRead = read(self.fd, securePool, 0, securePool.length);
|
||||
self.secureStream.readInject(securePool, 0, secureBytesRead);
|
||||
bytesRead = self.secureStream.readExtract(pool, pool.used, pool.length - pool.used);
|
||||
if(!self.secureEstablished) {
|
||||
if (self.secureStream.isInitFinished()) {
|
||||
self.secureEstablished = true;
|
||||
if (self._events && self._events['secure']) self.emit('secure');
|
||||
}
|
||||
}
|
||||
if (secureBytesRead === null && !self.server) {
|
||||
// Client needs to write as part of handshake
|
||||
this._writeWatcher.start();
|
||||
}
|
||||
} else {
|
||||
bytesRead = read(self.fd,
|
||||
pool,
|
||||
pool.used,
|
||||
pool.length - pool.used);
|
||||
pool.length - pool.used);
|
||||
}
|
||||
} catch (e) {
|
||||
self.forceClose(e);
|
||||
if (this.forceClose) this.forceClose(e);
|
||||
return;
|
||||
}
|
||||
|
||||
//debug('bytesRead ' + bytesRead + '\n');
|
||||
|
||||
if (bytesRead === 0) {
|
||||
if (self.secure && bytesRead == 0 && secureBytesRead >0){
|
||||
// Deal with SSL handshake
|
||||
if (self.server) {
|
||||
self._checkForSecureHandshake();
|
||||
} else {
|
||||
if (self.secureEstablised) self.flush();
|
||||
else self._checkForSecureHandshake();
|
||||
}
|
||||
} else if (bytesRead === 0) {
|
||||
self.readable = false;
|
||||
self._readWatcher.stop();
|
||||
|
||||
@ -341,10 +384,36 @@ function initStream (self) {
|
||||
self.writable = false;
|
||||
}
|
||||
|
||||
function Credentials(method) {
|
||||
if (!crypto) {
|
||||
throw new Error('node.js not compiled with openssl crypto support.');
|
||||
}
|
||||
this.context = new SecureContext();
|
||||
if (method) this.context.init(method);
|
||||
else this.context.init();
|
||||
}
|
||||
|
||||
exports.createCredentials = function(cred) {
|
||||
var c = new Credentials(cred.method);
|
||||
if (cred.key) c.context.setKey(cred.key);
|
||||
if (cred.cert) c.context.setCert(cred.cert);
|
||||
if (cred.ca) {
|
||||
if ( (typeof(cred.ca) == 'object') && cred.ca.length ) {
|
||||
for(var i=0; i<cred.ca.length; i++)
|
||||
c.context.addCACert(cred.ca[i]);
|
||||
} else {
|
||||
c.context.addCACert(cred.ca);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
exports.Credentials = Credentials;
|
||||
|
||||
function Stream (fd) {
|
||||
events.EventEmitter.call(this);
|
||||
|
||||
this.fd = null;
|
||||
this.secure = false;
|
||||
|
||||
if (parseInt(fd) >= 0) {
|
||||
this.open(fd);
|
||||
@ -353,6 +422,55 @@ function Stream (fd) {
|
||||
sys.inherits(Stream, events.EventEmitter);
|
||||
exports.Stream = Stream;
|
||||
|
||||
Stream.prototype.setSecure = function(credentials) {
|
||||
if (!crypto) {
|
||||
throw new Error('node.js not compiled with openssl crypto support.');
|
||||
}
|
||||
this.secure = true;
|
||||
this.secureEstablished = false;
|
||||
// If no credentials given, create a new one for just this Stream
|
||||
if (!credentials) {
|
||||
this.credentials = new Credentials();
|
||||
} else {
|
||||
this.credentials = credentials;
|
||||
}
|
||||
this.secureStream = new SecureStream(this.credentials.context, this.server?1:0);
|
||||
|
||||
if (!this.server) {
|
||||
// If client, trigger handshake
|
||||
this._checkForSecureHandshake();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Stream.prototype.verifyPeer = function() {
|
||||
if (!this.secure) {
|
||||
throw new Error('Stream is not a secure stream.');
|
||||
}
|
||||
return this.secureStream.verifyPeer(this.credentials.context);
|
||||
}
|
||||
|
||||
Stream.prototype._checkForSecureHandshake = function() {
|
||||
// Do an empty write to see if we need to write out as part of handshake
|
||||
if (!emptyBuffer) allocEmptyBuffer();
|
||||
this.write(emptyBuffer);
|
||||
}
|
||||
|
||||
Stream.prototype.getPeerCertificate = function(credentials) {
|
||||
if (!this.secure) {
|
||||
throw new Error('Stream is not a secure stream.');
|
||||
}
|
||||
return this.secureStream.getPeerCertificate();
|
||||
}
|
||||
|
||||
Stream.prototype.getCipher = function() {
|
||||
if (!this.secure) {
|
||||
throw new Error('Stream is not a secure stream.');
|
||||
}
|
||||
return this.secureStream.getCurrentCipher();
|
||||
}
|
||||
|
||||
|
||||
Stream.prototype.open = function (fd) {
|
||||
initStream(this);
|
||||
@ -411,6 +529,15 @@ Stream.prototype.write = function (data, encoding) {
|
||||
};
|
||||
|
||||
|
||||
Stream.prototype._shutdownSecure = function () {
|
||||
this.secureStream.shutdown();
|
||||
if (!securePool) allocNewSecurePool();
|
||||
var secureLen = this.secureStream.writeExtract(securePool, 0, securePool.length);
|
||||
try {
|
||||
var secureBytesWritten = write(this.fd, securePool, 0, secureLen);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// Directly writes the data to socket.
|
||||
//
|
||||
// Steps:
|
||||
@ -420,14 +547,15 @@ Stream.prototype.write = function (data, encoding) {
|
||||
// 3. Slice out remaining
|
||||
// 4. Unshift remaining onto _writeQueue. Return false.
|
||||
Stream.prototype._writeOut = function (data, encoding) {
|
||||
if (!this.writable) throw new Error('Stream is not writable');
|
||||
if (!this.writable) {
|
||||
if (this.secure) return false;
|
||||
else throw new Error('Stream is not writable');
|
||||
}
|
||||
|
||||
|
||||
var buffer, off, len;
|
||||
var bytesWritten, charsWritten;
|
||||
|
||||
var queuedData = false;
|
||||
|
||||
if (typeof data != 'string') {
|
||||
// 'data' is a buffer, ignore 'encoding'
|
||||
buffer = data;
|
||||
@ -458,7 +586,7 @@ Stream.prototype._writeOut = function (data, encoding) {
|
||||
assert(charsWritten <= data.length);
|
||||
}
|
||||
|
||||
assert(bytesWritten > 0);
|
||||
if (encoding) assert(bytesWritten > 0);
|
||||
|
||||
buffer = pool;
|
||||
len = bytesWritten;
|
||||
@ -478,11 +606,26 @@ Stream.prototype._writeOut = function (data, encoding) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send the buffer.
|
||||
|
||||
try {
|
||||
bytesWritten = write(this.fd, buffer, off, len);
|
||||
if (this.secure) {
|
||||
if (!buffer) return false;
|
||||
bytesWritten = this.secureStream.writeInject(buffer, off, len);
|
||||
if (!securePool) allocNewSecurePool();
|
||||
var secureLen = this.secureStream.writeExtract(securePool, 0, securePool.length);
|
||||
if (secureLen==-1) {
|
||||
// Check our read again for secure handshake
|
||||
this._readWatcher.callback();
|
||||
secureBytesWritten = 0;
|
||||
} else {
|
||||
var secureBytesWritten = write(this.fd, securePool, 0, secureLen);
|
||||
}
|
||||
if(!this.secureEstablished && this.secureStream.isInitFinished()) {
|
||||
this.secureEstablished = true;
|
||||
if (this._events && this._events['secure']) this.emit('secure');
|
||||
}
|
||||
} else {
|
||||
bytesWritten = write(this.fd, buffer, off, len);
|
||||
}
|
||||
} catch (e) {
|
||||
this.forceClose(e);
|
||||
return false;
|
||||
@ -675,6 +818,10 @@ Stream.prototype.forceClose = function (exception) {
|
||||
|
||||
timeout.unenroll(this);
|
||||
|
||||
if (this.secure) {
|
||||
this.secureStream.close();
|
||||
}
|
||||
|
||||
// FIXME Bug when this.fd == 0
|
||||
if (typeof this.fd == 'number') {
|
||||
close(this.fd);
|
||||
@ -691,6 +838,9 @@ Stream.prototype._shutdown = function () {
|
||||
if (this.writable) {
|
||||
this.writable = false;
|
||||
|
||||
if (this.secure) {
|
||||
this._shutdownSecure();
|
||||
}
|
||||
try {
|
||||
shutdown(this.fd, 'write')
|
||||
} catch (e) {
|
||||
|
14
src/node.cc
14
src/node.cc
@ -32,6 +32,9 @@
|
||||
#include <node_stdio.h>
|
||||
#include <node_natives.h>
|
||||
#include <node_version.h>
|
||||
#ifdef HAVE_OPENSSL
|
||||
#include <node_crypto.h>
|
||||
#endif
|
||||
|
||||
#include <v8-debug.h>
|
||||
|
||||
@ -1179,7 +1182,16 @@ static Handle<Value> Binding(const Arguments& args) {
|
||||
Buffer::Initialize(exports);
|
||||
binding_cache->Set(module, exports);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
} else if (!strcmp(*module_v, "crypto")) {
|
||||
if (binding_cache->Has(module)) {
|
||||
exports = binding_cache->Get(module)->ToObject();
|
||||
} else {
|
||||
exports = Object::New();
|
||||
InitCrypto(exports);
|
||||
binding_cache->Set(module, exports);
|
||||
}
|
||||
#endif
|
||||
} else if (!strcmp(*module_v, "natives")) {
|
||||
if (binding_cache->Has(module)) {
|
||||
exports = binding_cache->Get(module)->ToObject();
|
||||
|
971
src/node_crypto.cc
Normal file
971
src/node_crypto.cc
Normal file
@ -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
|
||||
|
73
src/node_crypto.h
Normal file
73
src/node_crypto.h
Normal file
@ -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_
|
14
wscript
14
wscript
@ -134,6 +134,13 @@ def configure(conf):
|
||||
if sys.platform.startswith("freebsd"):
|
||||
conf.fatal("Install the libexecinfo port from /usr/ports/devel/libexecinfo.")
|
||||
|
||||
if conf.check_cfg(package='openssl',
|
||||
args='--cflags --libs',
|
||||
#libpath=['/usr/lib', '/usr/local/lib'],
|
||||
uselib_store='OPENSSL'):
|
||||
conf.env["USE_OPENSSL"] = True
|
||||
conf.env.append_value("CXXFLAGS", "-DHAVE_OPENSSL=1")
|
||||
|
||||
if conf.check_cfg(package='gnutls',
|
||||
args='--cflags --libs',
|
||||
atleast_version='2.5.0',
|
||||
@ -415,6 +422,9 @@ def build(bld):
|
||||
src/node_timer.cc
|
||||
src/node_idle_watcher.cc
|
||||
"""
|
||||
if bld.env["USE_OPENSSL"]:
|
||||
node.source += "src/node_crypto.cc"
|
||||
|
||||
if not bld.env["USE_SYSTEM"]:
|
||||
node.includes = """
|
||||
src/
|
||||
@ -428,7 +438,7 @@ def build(bld):
|
||||
"""
|
||||
node.add_objects = 'ev eio evcom http_parser coupling'
|
||||
node.uselib_local = ''
|
||||
node.uselib = 'GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL'
|
||||
node.uselib = 'OPENSSL GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL'
|
||||
else:
|
||||
node.includes = """
|
||||
src/
|
||||
@ -439,7 +449,7 @@ def build(bld):
|
||||
"""
|
||||
node.add_objects = 'eio evcom http_parser coupling'
|
||||
node.uselib_local = 'eio'
|
||||
node.uselib = 'EV GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL'
|
||||
node.uselib = 'EV OPENSSL GNUTLS GPGERROR UDNS V8 EXECINFO DL KVM SOCKET NSL'
|
||||
|
||||
node.install_path = '${PREFIX}/lib'
|
||||
node.install_path = '${PREFIX}/bin'
|
||||
|
Loading…
Reference in New Issue
Block a user