parent
9e6498d5fa
commit
c9b40da368
10
lib/https.js
10
lib/https.js
@ -23,9 +23,15 @@ var tls = require('tls');
|
|||||||
var http = require('http');
|
var http = require('http');
|
||||||
var inherits = require('util').inherits;
|
var inherits = require('util').inherits;
|
||||||
|
|
||||||
|
var NPN_ENABLED = process.binding('constants').NPN_ENABLED;
|
||||||
|
|
||||||
function Server(opts, requestListener) {
|
function Server(opts, requestListener) {
|
||||||
if (!(this instanceof Server)) return new Server(opts, requestListener);
|
if (!(this instanceof Server)) return new Server(opts, requestListener);
|
||||||
|
|
||||||
|
if (NPN_ENABLED && !opts.NPNProtocols) {
|
||||||
|
opts.NPNProtocols = ['http/1.1', 'http/1.0'];
|
||||||
|
}
|
||||||
|
|
||||||
tls.Server.call(this, opts, http._connectionListener);
|
tls.Server.call(this, opts, http._connectionListener);
|
||||||
|
|
||||||
this.httpAllowHalfOpen = false;
|
this.httpAllowHalfOpen = false;
|
||||||
@ -58,6 +64,10 @@ Agent.prototype.defaultPort = 443;
|
|||||||
|
|
||||||
|
|
||||||
Agent.prototype._getConnection = function(host, port, cb) {
|
Agent.prototype._getConnection = function(host, port, cb) {
|
||||||
|
if (NPN_ENABLED && !this.options.NPNProtocols) {
|
||||||
|
this.options.NPNProtocols = ['http/1.1', 'http/1.0'];
|
||||||
|
}
|
||||||
|
|
||||||
var s = tls.connect(port, host, this.options, function() {
|
var s = tls.connect(port, host, this.options, function() {
|
||||||
// do other checks here?
|
// do other checks here?
|
||||||
if (cb) cb();
|
if (cb) cb();
|
||||||
|
53
lib/tls.js
53
lib/tls.js
@ -27,6 +27,8 @@ var stream = require('stream');
|
|||||||
var END_OF_FILE = 42;
|
var END_OF_FILE = 42;
|
||||||
var assert = require('assert').ok;
|
var assert = require('assert').ok;
|
||||||
|
|
||||||
|
var NPN_ENABLED = process.binding('constants').NPN_ENABLED;
|
||||||
|
|
||||||
var debug;
|
var debug;
|
||||||
if (process.env.NODE_DEBUG && /tls/.test(process.env.NODE_DEBUG)) {
|
if (process.env.NODE_DEBUG && /tls/.test(process.env.NODE_DEBUG)) {
|
||||||
debug = function(a) { console.error('TLS:', a); };
|
debug = function(a) { console.error('TLS:', a); };
|
||||||
@ -38,10 +40,36 @@ if (process.env.NODE_DEBUG && /tls/.test(process.env.NODE_DEBUG)) {
|
|||||||
var Connection = null;
|
var Connection = null;
|
||||||
try {
|
try {
|
||||||
Connection = process.binding('crypto').Connection;
|
Connection = process.binding('crypto').Connection;
|
||||||
|
exports.NPN_ENABLED = NPN_ENABLED;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('node.js not compiled with openssl crypto support.');
|
throw new Error('node.js not compiled with openssl crypto support.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert protocols array into valid OpenSSL protocols list
|
||||||
|
// ("\x06spdy/2\x08http/1.1\x08http/1.0")
|
||||||
|
function convertNPNProtocols(NPNProtocols, out) {
|
||||||
|
// If NPNProtocols is Array - translate it into buffer
|
||||||
|
if (Array.isArray(NPNProtocols)) {
|
||||||
|
var buff = new Buffer(NPNProtocols.reduce(function(p, c) {
|
||||||
|
return p + 1 + Buffer.byteLength(c);
|
||||||
|
}, 0));
|
||||||
|
|
||||||
|
NPNProtocols.reduce(function(offset, c) {
|
||||||
|
var clen = Buffer.byteLength(c);
|
||||||
|
buff[offset] = clen;
|
||||||
|
buff.write(c, offset + 1);
|
||||||
|
|
||||||
|
return offset + 1 + clen;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
NPNProtocols = buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's already a Buffer - store it
|
||||||
|
if (Buffer.isBuffer(NPNProtocols)) {
|
||||||
|
out.NPNProtocols = NPNProtocols;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Base class of both CleartextStream and EncryptedStream
|
// Base class of both CleartextStream and EncryptedStream
|
||||||
function CryptoStream(pair) {
|
function CryptoStream(pair) {
|
||||||
@ -437,12 +465,14 @@ EncryptedStream.prototype._pusher = function(pool, offset, length) {
|
|||||||
* Provides a pair of streams to do encrypted communication.
|
* Provides a pair of streams to do encrypted communication.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
|
function SecurePair(credentials, isServer, requestCert, rejectUnauthorized,
|
||||||
|
NPNProtocols) {
|
||||||
if (!(this instanceof SecurePair)) {
|
if (!(this instanceof SecurePair)) {
|
||||||
return new SecurePair(credentials,
|
return new SecurePair(credentials,
|
||||||
isServer,
|
isServer,
|
||||||
requestCert,
|
requestCert,
|
||||||
rejectUnauthorized);
|
rejectUnauthorized,
|
||||||
|
NPNProtocols);
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -478,6 +508,10 @@ function SecurePair(credentials, isServer, requestCert, rejectUnauthorized) {
|
|||||||
this._requestCert,
|
this._requestCert,
|
||||||
this._rejectUnauthorized);
|
this._rejectUnauthorized);
|
||||||
|
|
||||||
|
if (NPN_ENABLED && NPNProtocols) {
|
||||||
|
this._ssl.setNPNProtocols(NPNProtocols);
|
||||||
|
this.npnProtocol = null;
|
||||||
|
}
|
||||||
|
|
||||||
/* Acts as a r/w stream to the cleartext side of the stream. */
|
/* Acts as a r/w stream to the cleartext side of the stream. */
|
||||||
this.cleartext = new CleartextStream(this);
|
this.cleartext = new CleartextStream(this);
|
||||||
@ -588,6 +622,10 @@ SecurePair.prototype._cycle = function(depth) {
|
|||||||
|
|
||||||
SecurePair.prototype._maybeInitFinished = function() {
|
SecurePair.prototype._maybeInitFinished = function() {
|
||||||
if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) {
|
if (this._ssl && !this._secureEstablished && this._ssl.isInitFinished()) {
|
||||||
|
if (NPN_ENABLED) {
|
||||||
|
this.npnProtocol = this._ssl.getNegotiatedProtocol();
|
||||||
|
}
|
||||||
|
|
||||||
this._secureEstablished = true;
|
this._secureEstablished = true;
|
||||||
debug('secure established');
|
debug('secure established');
|
||||||
this.emit('secure');
|
this.emit('secure');
|
||||||
@ -745,13 +783,15 @@ function Server(/* [options], listener */) {
|
|||||||
var pair = new SecurePair(creds,
|
var pair = new SecurePair(creds,
|
||||||
true,
|
true,
|
||||||
self.requestCert,
|
self.requestCert,
|
||||||
self.rejectUnauthorized);
|
self.rejectUnauthorized,
|
||||||
|
self.NPNProtocols);
|
||||||
|
|
||||||
var cleartext = pipe(pair, socket);
|
var cleartext = pipe(pair, socket);
|
||||||
cleartext._controlReleased = false;
|
cleartext._controlReleased = false;
|
||||||
|
|
||||||
pair.on('secure', function() {
|
pair.on('secure', function() {
|
||||||
pair.cleartext.authorized = false;
|
pair.cleartext.authorized = false;
|
||||||
|
pair.cleartext.npnProtocol = pair.npnProtocol;
|
||||||
if (!self.requestCert) {
|
if (!self.requestCert) {
|
||||||
cleartext._controlReleased = true;
|
cleartext._controlReleased = true;
|
||||||
self.emit('secureConnection', pair.cleartext, pair.encrypted);
|
self.emit('secureConnection', pair.cleartext, pair.encrypted);
|
||||||
@ -812,6 +852,7 @@ Server.prototype.setOptions = function(options) {
|
|||||||
if (options.ciphers) this.ciphers = options.ciphers;
|
if (options.ciphers) this.ciphers = options.ciphers;
|
||||||
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
|
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
|
||||||
if (options.secureOptions) this.secureOptions = options.secureOptions;
|
if (options.secureOptions) this.secureOptions = options.secureOptions;
|
||||||
|
if (options.NPNProtocols) convertNPNProtocols(options.NPNProtocols, this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -854,7 +895,9 @@ exports.connect = function(port /* host, options, cb */) {
|
|||||||
var sslcontext = crypto.createCredentials(options);
|
var sslcontext = crypto.createCredentials(options);
|
||||||
//sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
|
//sslcontext.context.setCiphers('RC4-SHA:AES128-SHA:AES256-SHA');
|
||||||
|
|
||||||
var pair = new SecurePair(sslcontext, false);
|
convertNPNProtocols(options.NPNProtocols, this);
|
||||||
|
var pair = new SecurePair(sslcontext, false, true, false,
|
||||||
|
this.NPNProtocols);
|
||||||
|
|
||||||
var cleartext = pipe(pair, socket);
|
var cleartext = pipe(pair, socket);
|
||||||
|
|
||||||
@ -863,6 +906,8 @@ exports.connect = function(port /* host, options, cb */) {
|
|||||||
pair.on('secure', function() {
|
pair.on('secure', function() {
|
||||||
var verifyError = pair._ssl.verifyError();
|
var verifyError = pair._ssl.verifyError();
|
||||||
|
|
||||||
|
cleartext.npnProtocol = pair.npnProtocol;
|
||||||
|
|
||||||
if (verifyError) {
|
if (verifyError) {
|
||||||
cleartext.authorized = false;
|
cleartext.authorized = false;
|
||||||
cleartext.authorizationError = verifyError;
|
cleartext.authorizationError = verifyError;
|
||||||
|
@ -912,6 +912,11 @@ void DefineConstants(Handle<Object> target) {
|
|||||||
#ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
|
#ifdef SSL_OP_CRYPTOPRO_TLSEXT_BUG
|
||||||
NODE_DEFINE_CONSTANT(target, SSL_OP_CRYPTOPRO_TLSEXT_BUG);
|
NODE_DEFINE_CONSTANT(target, SSL_OP_CRYPTOPRO_TLSEXT_BUG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
#define NPN_ENABLED 1
|
||||||
|
NODE_DEFINE_CONSTANT(target, NPN_ENABLED);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -565,6 +565,11 @@ void Connection::Initialize(Handle<Object> target) {
|
|||||||
NODE_SET_PROTOTYPE_METHOD(t, "receivedShutdown", Connection::ReceivedShutdown);
|
NODE_SET_PROTOTYPE_METHOD(t, "receivedShutdown", Connection::ReceivedShutdown);
|
||||||
NODE_SET_PROTOTYPE_METHOD(t, "close", Connection::Close);
|
NODE_SET_PROTOTYPE_METHOD(t, "close", Connection::Close);
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
NODE_SET_PROTOTYPE_METHOD(t, "getNegotiatedProtocol", Connection::GetNegotiatedProto);
|
||||||
|
NODE_SET_PROTOTYPE_METHOD(t, "setNPNProtocols", Connection::SetNPNProtocols);
|
||||||
|
#endif
|
||||||
|
|
||||||
target->Set(String::NewSymbol("Connection"), t->GetFunction());
|
target->Set(String::NewSymbol("Connection"), t->GetFunction());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,6 +619,76 @@ static int VerifyCallback(int preverify_ok, X509_STORE_CTX *ctx) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
|
||||||
|
int Connection::AdvertiseNextProtoCallback_(SSL *s,
|
||||||
|
const unsigned char **data,
|
||||||
|
unsigned int *len,
|
||||||
|
void *arg) {
|
||||||
|
|
||||||
|
Connection *p = static_cast<Connection*>(SSL_get_app_data(s));
|
||||||
|
|
||||||
|
if (p->npnProtos_.IsEmpty()) {
|
||||||
|
// No initialization - no NPN protocols
|
||||||
|
*data = reinterpret_cast<const unsigned char*>("");
|
||||||
|
*len = 0;
|
||||||
|
} else {
|
||||||
|
*data = reinterpret_cast<const unsigned char*>(Buffer::Data(p->npnProtos_));
|
||||||
|
*len = Buffer::Length(p->npnProtos_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSL_TLSEXT_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Connection::SelectNextProtoCallback_(SSL *s,
|
||||||
|
unsigned char **out, unsigned char *outlen,
|
||||||
|
const unsigned char* in,
|
||||||
|
unsigned int inlen, void *arg) {
|
||||||
|
Connection *p = static_cast<Connection*> SSL_get_app_data(s);
|
||||||
|
|
||||||
|
// Release old protocol handler if present
|
||||||
|
if (!p->selectedNPNProto_.IsEmpty()) {
|
||||||
|
p->selectedNPNProto_.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->npnProtos_.IsEmpty()) {
|
||||||
|
// We should at least select one protocol
|
||||||
|
// If server is using NPN
|
||||||
|
*out = reinterpret_cast<unsigned char*>(const_cast<char*>("http/1.1"));
|
||||||
|
*outlen = 8;
|
||||||
|
|
||||||
|
// set status unsupported
|
||||||
|
p->selectedNPNProto_ = Persistent<Value>::New(False());
|
||||||
|
|
||||||
|
return SSL_TLSEXT_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* npnProtos =
|
||||||
|
reinterpret_cast<const unsigned char*>(Buffer::Data(p->npnProtos_));
|
||||||
|
|
||||||
|
int status = SSL_select_next_proto(out, outlen, in, inlen, npnProtos,
|
||||||
|
Buffer::Length(p->npnProtos_));
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case OPENSSL_NPN_UNSUPPORTED:
|
||||||
|
p->selectedNPNProto_ = Persistent<Value>::New(Null());
|
||||||
|
break;
|
||||||
|
case OPENSSL_NPN_NEGOTIATED:
|
||||||
|
p->selectedNPNProto_ = Persistent<Value>::New(String::New(
|
||||||
|
reinterpret_cast<const char*>(*out), *outlen
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
case OPENSSL_NPN_NO_OVERLAP:
|
||||||
|
p->selectedNPNProto_ = Persistent<Value>::New(False());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSL_TLSEXT_ERR_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Handle<Value> Connection::New(const Arguments& args) {
|
Handle<Value> Connection::New(const Arguments& args) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
@ -633,6 +708,23 @@ Handle<Value> Connection::New(const Arguments& args) {
|
|||||||
p->ssl_ = SSL_new(sc->ctx_);
|
p->ssl_ = SSL_new(sc->ctx_);
|
||||||
p->bio_read_ = BIO_new(BIO_s_mem());
|
p->bio_read_ = BIO_new(BIO_s_mem());
|
||||||
p->bio_write_ = BIO_new(BIO_s_mem());
|
p->bio_write_ = BIO_new(BIO_s_mem());
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
SSL_set_app_data(p->ssl_, p);
|
||||||
|
if (is_server) {
|
||||||
|
// Server should advertise NPN protocols
|
||||||
|
SSL_CTX_set_next_protos_advertised_cb(sc->ctx_,
|
||||||
|
AdvertiseNextProtoCallback_,
|
||||||
|
NULL);
|
||||||
|
} else {
|
||||||
|
// Client should select protocol from advertised
|
||||||
|
// If server supports NPN
|
||||||
|
SSL_CTX_set_next_proto_select_cb(sc->ctx_,
|
||||||
|
SelectNextProtoCallback_,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SSL_set_bio(p->ssl_, p->bio_read_, p->bio_write_);
|
SSL_set_bio(p->ssl_, p->bio_read_, p->bio_write_);
|
||||||
|
|
||||||
#ifdef SSL_MODE_RELEASE_BUFFERS
|
#ifdef SSL_MODE_RELEASE_BUFFERS
|
||||||
@ -1184,6 +1276,48 @@ Handle<Value> Connection::Close(const Arguments& args) {
|
|||||||
return True();
|
return True();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
Handle<Value> Connection::GetNegotiatedProto(const Arguments& args) {
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
Connection *ss = Connection::Unwrap(args);
|
||||||
|
|
||||||
|
if (ss->is_server_) {
|
||||||
|
const unsigned char *npn_proto;
|
||||||
|
unsigned int npn_proto_len;
|
||||||
|
|
||||||
|
SSL_get0_next_proto_negotiated(ss->ssl_, &npn_proto, &npn_proto_len);
|
||||||
|
|
||||||
|
if (!npn_proto) {
|
||||||
|
return False();
|
||||||
|
}
|
||||||
|
|
||||||
|
return String::New((const char*) npn_proto, npn_proto_len);
|
||||||
|
} else {
|
||||||
|
return ss->selectedNPNProto_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handle<Value> Connection::SetNPNProtocols(const Arguments& args) {
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
Connection *ss = Connection::Unwrap(args);
|
||||||
|
|
||||||
|
if (args.Length() < 1 || !Buffer::HasInstance(args[0])) {
|
||||||
|
return ThrowException(Exception::Error(String::New(
|
||||||
|
"Must give a Buffer as first argument")));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release old handle
|
||||||
|
if (!ss->npnProtos_.IsEmpty()) {
|
||||||
|
ss->npnProtos_.Dispose();
|
||||||
|
}
|
||||||
|
ss->npnProtos_ = Persistent<Object>::New(args[0]->ToObject());
|
||||||
|
|
||||||
|
return True();
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void HexEncode(unsigned char *md_value,
|
static void HexEncode(unsigned char *md_value,
|
||||||
int md_len,
|
int md_len,
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#define SRC_NODE_CRYPTO_H_
|
#define SRC_NODE_CRYPTO_H_
|
||||||
|
|
||||||
#include <node.h>
|
#include <node.h>
|
||||||
|
|
||||||
#include <node_object_wrap.h>
|
#include <node_object_wrap.h>
|
||||||
#include <v8.h>
|
#include <v8.h>
|
||||||
|
|
||||||
@ -33,6 +34,10 @@
|
|||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
#include <node_buffer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define EVP_F_EVP_DECRYPTFINAL 101
|
#define EVP_F_EVP_DECRYPTFINAL 101
|
||||||
|
|
||||||
|
|
||||||
@ -94,6 +99,11 @@ class Connection : ObjectWrap {
|
|||||||
public:
|
public:
|
||||||
static void Initialize(v8::Handle<v8::Object> target);
|
static void Initialize(v8::Handle<v8::Object> target);
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
v8::Persistent<v8::Object> npnProtos_;
|
||||||
|
v8::Persistent<v8::Value> selectedNPNProto_;
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
static v8::Handle<v8::Value> New(const v8::Arguments& args);
|
||||||
static v8::Handle<v8::Value> EncIn(const v8::Arguments& args);
|
static v8::Handle<v8::Value> EncIn(const v8::Arguments& args);
|
||||||
@ -111,6 +121,20 @@ class Connection : ObjectWrap {
|
|||||||
static v8::Handle<v8::Value> Start(const v8::Arguments& args);
|
static v8::Handle<v8::Value> Start(const v8::Arguments& args);
|
||||||
static v8::Handle<v8::Value> Close(const v8::Arguments& args);
|
static v8::Handle<v8::Value> Close(const v8::Arguments& args);
|
||||||
|
|
||||||
|
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||||
|
// NPN
|
||||||
|
static v8::Handle<v8::Value> GetNegotiatedProto(const v8::Arguments& args);
|
||||||
|
static v8::Handle<v8::Value> SetNPNProtocols(const v8::Arguments& args);
|
||||||
|
static int AdvertiseNextProtoCallback_(SSL *s,
|
||||||
|
const unsigned char **data,
|
||||||
|
unsigned int *len,
|
||||||
|
void *arg);
|
||||||
|
static int SelectNextProtoCallback_(SSL *s,
|
||||||
|
unsigned char **out, unsigned char *outlen,
|
||||||
|
const unsigned char* in,
|
||||||
|
unsigned int inlen, void *arg);
|
||||||
|
#endif
|
||||||
|
|
||||||
int HandleBIOError(BIO *bio, const char* func, int rv);
|
int HandleBIOError(BIO *bio, const char* func, int rv);
|
||||||
int HandleSSLError(const char* func, int rv);
|
int HandleSSLError(const char* func, int rv);
|
||||||
|
|
||||||
@ -139,6 +163,7 @@ class Connection : ObjectWrap {
|
|||||||
BIO *bio_read_;
|
BIO *bio_read_;
|
||||||
BIO *bio_write_;
|
BIO *bio_write_;
|
||||||
SSL *ssl_;
|
SSL *ssl_;
|
||||||
|
|
||||||
bool is_server_; /* coverity[member_decl] */
|
bool is_server_; /* coverity[member_decl] */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
101
test/simple/test-tls-npn-server-client.js
Normal file
101
test/simple/test-tls-npn-server-client.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// Copyright Joyent, Inc. and other Node contributors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the
|
||||||
|
// "Software"), to deal in the Software without restriction, including
|
||||||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
|
// persons to whom the Software is furnished to do so, subject to the
|
||||||
|
// following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included
|
||||||
|
// in all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||||
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
var NPN_ENABLED = process.binding('constants').NPN_ENABLED;
|
||||||
|
|
||||||
|
if (!process.versions.openssl || !NPN_ENABLED) {
|
||||||
|
console.error("Skipping because node compiled without OpenSSL or " +
|
||||||
|
"with old OpenSSL version.");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var common = require('../common'),
|
||||||
|
assert = require('assert'),
|
||||||
|
fs = require('fs'),
|
||||||
|
tls = require('tls');
|
||||||
|
|
||||||
|
function filenamePEM(n) {
|
||||||
|
return require('path').join(common.fixturesDir, 'keys', n + ".pem");
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadPEM(n) {
|
||||||
|
return fs.readFileSync(filenamePEM(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
var serverOptions = {
|
||||||
|
key: loadPEM('agent2-key'),
|
||||||
|
cert: loadPEM('agent2-cert'),
|
||||||
|
crl: loadPEM('ca2-crl'),
|
||||||
|
NPNProtocols: ['a', 'b', 'c']
|
||||||
|
};
|
||||||
|
|
||||||
|
var clientsOptions = [{
|
||||||
|
key: serverOptions.key,
|
||||||
|
cert: serverOptions.cert,
|
||||||
|
crl: serverOptions.crl,
|
||||||
|
NPNProtocols: ['a', 'b', 'c']
|
||||||
|
},{
|
||||||
|
key: serverOptions.key,
|
||||||
|
cert: serverOptions.cert,
|
||||||
|
crl: serverOptions.crl,
|
||||||
|
NPNProtocols: ['c', 'b', 'e']
|
||||||
|
},{
|
||||||
|
key: serverOptions.key,
|
||||||
|
cert: serverOptions.cert,
|
||||||
|
crl: serverOptions.crl,
|
||||||
|
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||||
|
}];
|
||||||
|
|
||||||
|
var serverPort = common.PORT;
|
||||||
|
|
||||||
|
var serverResults = [],
|
||||||
|
clientsResults = [];
|
||||||
|
|
||||||
|
var server = tls.createServer(serverOptions, function(c) {
|
||||||
|
serverResults.push(c.npnProtocol);
|
||||||
|
});
|
||||||
|
server.listen(serverPort, startTest);
|
||||||
|
|
||||||
|
function startTest() {
|
||||||
|
function connectClient(options, callback) {
|
||||||
|
var client = tls.connect(serverPort, 'localhost', options, function() {
|
||||||
|
clientsResults.push(client.npnProtocol);
|
||||||
|
client.destroy();
|
||||||
|
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
connectClient(clientsOptions[0], function() {
|
||||||
|
connectClient(clientsOptions[1], function() {
|
||||||
|
connectClient(clientsOptions[2], function() {
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
process.on('exit', function() {
|
||||||
|
assert.equal(serverResults[0], clientsResults[0]);
|
||||||
|
assert.equal(serverResults[1], clientsResults[1]);
|
||||||
|
assert.equal(serverResults[2], 'first-priority-unsupported');
|
||||||
|
assert.equal(clientsResults[2], false);
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user