tls: drop NPN (next protocol negotiation) support
NPN has been superseded by ALPN. Chrome and Firefox removed support for NPN in 2016 and 2017 respectively to no ill effect. Fixes: https://github.com/nodejs/node/issues/14602 PR-URL: https://github.com/nodejs/node/pull/19403 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de>
This commit is contained in:
parent
b3f23910a2
commit
5bfbe5ceae
3
deps/openssl/openssl.gypi
vendored
3
deps/openssl/openssl.gypi
vendored
@ -1268,6 +1268,9 @@
|
||||
# the real driver but that poses a security liability when an attacker
|
||||
# is able to create a malicious DLL in one of the default search paths.
|
||||
'OPENSSL_NO_HW',
|
||||
|
||||
# Disable NPN (Next Protocol Negotiation), superseded by ALPN.
|
||||
'OPENSSL_NO_NEXTPROTONEG',
|
||||
],
|
||||
'openssl_default_defines_win': [
|
||||
'MK1MF_BUILD',
|
||||
|
@ -2412,10 +2412,6 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL.
|
||||
<td><code>DH_NOT_SUITABLE_GENERATOR</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>NPN_ENABLED</code></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALPN_ENABLED</code></td>
|
||||
<td></td>
|
||||
|
@ -104,22 +104,17 @@ not required and a default ECDHE curve will be used. The `ecdhCurve` property
|
||||
can be used when creating a TLS Server to specify the list of names of supported
|
||||
curves to use, see [`tls.createServer()`] for more info.
|
||||
|
||||
### ALPN, NPN, and SNI
|
||||
### ALPN and SNI
|
||||
|
||||
<!-- type=misc -->
|
||||
|
||||
ALPN (Application-Layer Protocol Negotiation Extension), NPN (Next
|
||||
Protocol Negotiation) and, SNI (Server Name Indication) are TLS
|
||||
handshake extensions:
|
||||
ALPN (Application-Layer Protocol Negotiation Extension) and
|
||||
SNI (Server Name Indication) are TLS handshake extensions:
|
||||
|
||||
* ALPN/NPN - Allows the use of one TLS server for multiple protocols (HTTP,
|
||||
SPDY, HTTP/2)
|
||||
* ALPN - Allows the use of one TLS server for multiple protocols (HTTP, HTTP/2)
|
||||
* SNI - Allows the use of one TLS server for multiple hostnames with different
|
||||
SSL certificates.
|
||||
|
||||
Use of ALPN is recommended over NPN. The NPN extension has never been
|
||||
formally defined or documented and generally not recommended for use.
|
||||
|
||||
### Client-initiated renegotiation attack mitigation
|
||||
|
||||
<!-- type=misc -->
|
||||
@ -332,12 +327,9 @@ server. If `tlsSocket.authorized` is `false`, then `socket.authorizationError`
|
||||
is set to describe how authorization failed. Note that depending on the settings
|
||||
of the TLS server, unauthorized connections may still be accepted.
|
||||
|
||||
The `tlsSocket.npnProtocol` and `tlsSocket.alpnProtocol` properties are strings
|
||||
that contain the selected NPN and ALPN protocols, respectively. When both NPN
|
||||
and ALPN extensions are received, ALPN takes precedence over NPN and the next
|
||||
protocol is selected by ALPN.
|
||||
|
||||
When ALPN has no selected protocol, `tlsSocket.alpnProtocol` returns `false`.
|
||||
The `tlsSocket.alpnProtocol` property is a string that contains the selected
|
||||
ALPN protocol. When ALPN has no selected protocol, `tlsSocket.alpnProtocol`
|
||||
equals `false`.
|
||||
|
||||
The `tlsSocket.servername` property is a string containing the server name
|
||||
requested via SNI.
|
||||
@ -468,7 +460,6 @@ changes:
|
||||
(`isServer` is true) may optionally set `requestCert` to true to request a
|
||||
client certificate.
|
||||
* `rejectUnauthorized`: Optional, see [`tls.createServer()`][]
|
||||
* `NPNProtocols`: Optional, see [`tls.createServer()`][]
|
||||
* `ALPNProtocols`: Optional, see [`tls.createServer()`][]
|
||||
* `SNICallback`: Optional, see [`tls.createServer()`][]
|
||||
* `session` {Buffer} An optional `Buffer` instance containing a TLS session.
|
||||
@ -509,9 +500,9 @@ regardless of whether or not the server's certificate has been authorized. It
|
||||
is the client's responsibility to check the `tlsSocket.authorized` property to
|
||||
determine if the server certificate was signed by one of the specified CAs. If
|
||||
`tlsSocket.authorized === false`, then the error can be found by examining the
|
||||
`tlsSocket.authorizationError` property. If either ALPN or NPN was used,
|
||||
the `tlsSocket.alpnProtocol` or `tlsSocket.npnProtocol` properties can be
|
||||
checked to determine the negotiated protocol.
|
||||
`tlsSocket.authorizationError` property. If ALPN was used, the
|
||||
`tlsSocket.alpnProtocol` property can be checked to determine the negotiated
|
||||
protocol.
|
||||
|
||||
### tlsSocket.address()
|
||||
<!-- YAML
|
||||
@ -841,8 +832,7 @@ changes:
|
||||
description: The `lookup` option is supported now.
|
||||
- version: v8.0.0
|
||||
pr-url: https://github.com/nodejs/node/pull/11984
|
||||
description: The `ALPNProtocols` and `NPNProtocols` options can
|
||||
be `Uint8Array`s now.
|
||||
description: The `ALPNProtocols` option can be a `Uint8Array` now.
|
||||
- version: v5.3.0, v4.7.0
|
||||
pr-url: https://github.com/nodejs/node/pull/4246
|
||||
description: The `secureContext` option is supported now.
|
||||
@ -869,12 +859,6 @@ changes:
|
||||
verified against the list of supplied CAs. An `'error'` event is emitted if
|
||||
verification fails; `err.code` contains the OpenSSL error code. Defaults to
|
||||
`true`.
|
||||
* `NPNProtocols` {string[]|Buffer[]|Uint8Array[]|Buffer|Uint8Array}
|
||||
An array of strings, `Buffer`s or `Uint8Array`s, or a single `Buffer` or
|
||||
`Uint8Array` containing supported NPN protocols. `Buffer`s should have the
|
||||
format `[len][name][len][name]...` e.g. `0x05hello0x05world`, where the
|
||||
first byte is the length of the next protocol name. Passing an array is
|
||||
usually much simpler, e.g. `['hello', 'world']`.
|
||||
* `ALPNProtocols`: {string[]|Buffer[]|Uint8Array[]|Buffer|Uint8Array}
|
||||
An array of strings, `Buffer`s or `Uint8Array`s, or a single `Buffer` or
|
||||
`Uint8Array` containing the supported ALPN protocols. `Buffer`s should have
|
||||
@ -1116,8 +1100,7 @@ changes:
|
||||
description: The `options` parameter can now include `clientCertEngine`.
|
||||
- version: v8.0.0
|
||||
pr-url: https://github.com/nodejs/node/pull/11984
|
||||
description: The `ALPNProtocols` and `NPNProtocols` options can
|
||||
be `Uint8Array`s now.
|
||||
description: The `ALPNProtocols` option can be a `Uint8Array` now.
|
||||
- version: v5.0.0
|
||||
pr-url: https://github.com/nodejs/node/pull/2564
|
||||
description: ALPN options are supported now.
|
||||
@ -1136,13 +1119,6 @@ changes:
|
||||
* `rejectUnauthorized` {boolean} If not `false` the server will reject any
|
||||
connection which is not authorized with the list of supplied CAs. This
|
||||
option only has an effect if `requestCert` is `true`. Defaults to `true`.
|
||||
* `NPNProtocols` {string[]|Buffer[]|Uint8Array[]|Buffer|Uint8Array}
|
||||
An array of strings, `Buffer`s or `Uint8Array`s, or a single `Buffer` or
|
||||
`Uint8Array` containing supported NPN protocols. `Buffer`s should have the
|
||||
format `[len][name][len][name]...` e.g. `0x05hello0x05world`, where the
|
||||
first byte is the length of the next protocol name. Passing an array is
|
||||
usually much simpler, e.g. `['hello', 'world']`.
|
||||
(Protocols should be ordered by their priority.)
|
||||
* `ALPNProtocols`: {string[]|Buffer[]|Uint8Array[]|Buffer|Uint8Array}
|
||||
An array of strings, `Buffer`s or `Uint8Array`s, or a single `Buffer` or
|
||||
`Uint8Array` containing the supported ALPN protocols. `Buffer`s should have
|
||||
@ -1150,9 +1126,6 @@ changes:
|
||||
first byte is the length of the next protocol name. Passing an array is
|
||||
usually much simpler, e.g. `['hello', 'world']`.
|
||||
(Protocols should be ordered by their priority.)
|
||||
When the server receives both NPN and ALPN extensions from the client,
|
||||
ALPN takes precedence over NPN and the server does not send an NPN
|
||||
extension to the client.
|
||||
* `SNICallback(servername, cb)` {Function} A function that will be called if
|
||||
the client supports SNI TLS extension. Two arguments will be passed when
|
||||
called: `servername` and `cb`. `SNICallback` should invoke `cb(null, ctx)`,
|
||||
@ -1333,7 +1306,6 @@ changes:
|
||||
* `server` {net.Server} An optional [`net.Server`][] instance
|
||||
* `requestCert`: Optional, see [`tls.createServer()`][]
|
||||
* `rejectUnauthorized`: Optional, see [`tls.createServer()`][]
|
||||
* `NPNProtocols`: Optional, see [`tls.createServer()`][]
|
||||
* `ALPNProtocols`: Optional, see [`tls.createServer()`][]
|
||||
* `SNICallback`: Optional, see [`tls.createServer()`][]
|
||||
* `session` {Buffer} An optional `Buffer` instance containing a TLS session.
|
||||
|
@ -294,8 +294,6 @@ function initRead(tls, wrapped) {
|
||||
function TLSSocket(socket, opts) {
|
||||
const tlsOptions = Object.assign({}, opts);
|
||||
|
||||
if (tlsOptions.NPNProtocols)
|
||||
tls.convertNPNProtocols(tlsOptions.NPNProtocols, tlsOptions);
|
||||
if (tlsOptions.ALPNProtocols)
|
||||
tls.convertALPNProtocols(tlsOptions.ALPNProtocols, tlsOptions);
|
||||
|
||||
@ -306,7 +304,6 @@ function TLSSocket(socket, opts) {
|
||||
this._controlReleased = false;
|
||||
this._SNICallback = null;
|
||||
this.servername = null;
|
||||
this.npnProtocol = null;
|
||||
this.alpnProtocol = null;
|
||||
this.authorized = false;
|
||||
this.authorizationError = null;
|
||||
@ -529,9 +526,6 @@ TLSSocket.prototype._init = function(socket, wrap) {
|
||||
ssl.enableCertCb();
|
||||
}
|
||||
|
||||
if (process.features.tls_npn && options.NPNProtocols)
|
||||
ssl.setNPNProtocols(options.NPNProtocols);
|
||||
|
||||
if (process.features.tls_alpn && options.ALPNProtocols) {
|
||||
// keep reference in secureContext not to be GC-ed
|
||||
ssl._secureContext.alpnBuffer = options.ALPNProtocols;
|
||||
@ -630,10 +624,6 @@ TLSSocket.prototype._releaseControl = function() {
|
||||
};
|
||||
|
||||
TLSSocket.prototype._finishInit = function() {
|
||||
if (process.features.tls_npn) {
|
||||
this.npnProtocol = this._handle.getNegotiatedProtocol();
|
||||
}
|
||||
|
||||
if (process.features.tls_alpn) {
|
||||
this.alpnProtocol = this._handle.getALPNNegotiatedProtocol();
|
||||
}
|
||||
@ -790,7 +780,6 @@ function tlsConnectionListener(rawSocket) {
|
||||
requestCert: this.requestCert,
|
||||
rejectUnauthorized: this.rejectUnauthorized,
|
||||
handshakeTimeout: this[kHandshakeTimeout],
|
||||
NPNProtocols: this.NPNProtocols,
|
||||
ALPNProtocols: this.ALPNProtocols,
|
||||
SNICallback: this[kSNICallback] || SNICallback
|
||||
});
|
||||
@ -982,7 +971,6 @@ Server.prototype.setOptions = function(options) {
|
||||
else
|
||||
this.honorCipherOrder = true;
|
||||
if (secureOptions) this.secureOptions = secureOptions;
|
||||
if (options.NPNProtocols) tls.convertNPNProtocols(options.NPNProtocols, this);
|
||||
if (options.ALPNProtocols)
|
||||
tls.convertALPNProtocols(options.ALPNProtocols, this);
|
||||
if (options.sessionIdContext) {
|
||||
@ -1149,7 +1137,6 @@ exports.connect = function(...args /* [port,] [host,] [options,] [cb] */) {
|
||||
requestCert: true,
|
||||
rejectUnauthorized: options.rejectUnauthorized !== false,
|
||||
session: options.session,
|
||||
NPNProtocols: options.NPNProtocols,
|
||||
ALPNProtocols: options.ALPNProtocols,
|
||||
requestOCSP: options.requestOCSP
|
||||
});
|
||||
|
@ -49,10 +49,6 @@ function Server(opts, requestListener) {
|
||||
}
|
||||
opts = util._extend({}, opts);
|
||||
|
||||
if (process.features.tls_npn && !opts.NPNProtocols) {
|
||||
opts.NPNProtocols = ['http/1.1', 'http/1.0'];
|
||||
}
|
||||
|
||||
if (process.features.tls_alpn && !opts.ALPNProtocols) {
|
||||
// http/1.0 is not defined as Protocol IDs in IANA
|
||||
// http://www.iana.org/assignments/tls-extensiontype-values
|
||||
|
4
node.gyp
4
node.gyp
@ -586,8 +586,8 @@
|
||||
'mkssldef_flags': [
|
||||
# Categories to export.
|
||||
'-CAES,BF,BIO,DES,DH,DSA,EC,ECDH,ECDSA,ENGINE,EVP,HMAC,MD4,MD5,'
|
||||
'NEXTPROTONEG,PSK,RC2,RC4,RSA,SHA,SHA0,SHA1,SHA256,SHA512,SOCK,'
|
||||
'STDIO,TLSEXT,FP_API',
|
||||
'PSK,RC2,RC4,RSA,SHA,SHA0,SHA1,SHA256,SHA512,SOCK,STDIO,TLSEXT,'
|
||||
'FP_API',
|
||||
# Defines.
|
||||
'-DWIN32',
|
||||
# Symbols to filter from the export list.
|
||||
|
@ -103,8 +103,6 @@ struct PackageConfig {
|
||||
V(contextify_context_private_symbol, "node:contextify:context") \
|
||||
V(contextify_global_private_symbol, "node:contextify:global") \
|
||||
V(decorated_private_symbol, "node:decorated") \
|
||||
V(npn_buffer_private_symbol, "node:npnBuffer") \
|
||||
V(selected_npn_buffer_private_symbol, "node:selectedNpnBuffer") \
|
||||
V(napi_env, "node:napi:env") \
|
||||
V(napi_wrapper, "node:napi:wrapper") \
|
||||
|
||||
|
@ -2824,13 +2824,6 @@ static Local<Object> GetFeatures(Environment* env) {
|
||||
// TODO(bnoordhuis) ping libuv
|
||||
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ipv6"), True(env->isolate()));
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
Local<Boolean> tls_npn = True(env->isolate());
|
||||
#else
|
||||
Local<Boolean> tls_npn = False(env->isolate());
|
||||
#endif
|
||||
obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_npn"), tls_npn);
|
||||
|
||||
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
||||
Local<Boolean> tls_alpn = True(env->isolate());
|
||||
#else
|
||||
|
@ -971,11 +971,6 @@ void DefineOpenSSLConstants(Local<Object> target) {
|
||||
NODE_DEFINE_CONSTANT(target, DH_NOT_SUITABLE_GENERATOR);
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
#define NPN_ENABLED 1
|
||||
NODE_DEFINE_CONSTANT(target, NPN_ENABLED);
|
||||
#endif
|
||||
|
||||
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
||||
#define ALPN_ENABLED 1
|
||||
NODE_DEFINE_CONSTANT(target, ALPN_ENABLED);
|
||||
|
@ -81,7 +81,6 @@ using v8::DontDelete;
|
||||
using v8::EscapableHandleScope;
|
||||
using v8::Exception;
|
||||
using v8::External;
|
||||
using v8::False;
|
||||
using v8::FunctionCallbackInfo;
|
||||
using v8::FunctionTemplate;
|
||||
using v8::HandleScope;
|
||||
@ -231,7 +230,7 @@ static X509_STORE* root_cert_store;
|
||||
// Just to generate static methods
|
||||
template void SSLWrap<TLSWrap>::AddMethods(Environment* env,
|
||||
Local<FunctionTemplate> t);
|
||||
template void SSLWrap<TLSWrap>::InitNPN(SecureContext* sc);
|
||||
template void SSLWrap<TLSWrap>::ConfigureSecureContext(SecureContext* sc);
|
||||
template void SSLWrap<TLSWrap>::SetSNIContext(SecureContext* sc);
|
||||
template int SSLWrap<TLSWrap>::SetCACerts(SecureContext* sc);
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
@ -253,21 +252,6 @@ template void SSLWrap<TLSWrap>::OnClientHello(
|
||||
void* arg,
|
||||
const ClientHelloParser::ClientHello& hello);
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
template int SSLWrap<TLSWrap>::AdvertiseNextProtoCallback(
|
||||
SSL* s,
|
||||
const unsigned char** data,
|
||||
unsigned int* len,
|
||||
void* arg);
|
||||
template int SSLWrap<TLSWrap>::SelectNextProtoCallback(
|
||||
SSL* s,
|
||||
unsigned char** out,
|
||||
unsigned char* outlen,
|
||||
const unsigned char* in,
|
||||
unsigned int inlen,
|
||||
void* arg);
|
||||
#endif
|
||||
|
||||
#ifdef NODE__HAVE_TLSEXT_STATUS_CB
|
||||
template int SSLWrap<TLSWrap>::TLSExtStatusCallback(SSL* s, void* arg);
|
||||
#endif
|
||||
@ -1593,31 +1577,13 @@ void SSLWrap<Base>::AddMethods(Environment* env, Local<FunctionTemplate> t) {
|
||||
env->SetProtoMethod(t, "setMaxSendFragment", SetMaxSendFragment);
|
||||
#endif // SSL_set_max_send_fragment
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
env->SetProtoMethod(t, "getNegotiatedProtocol", GetNegotiatedProto);
|
||||
#endif // OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
env->SetProtoMethod(t, "setNPNProtocols", SetNPNProtocols);
|
||||
#endif
|
||||
|
||||
env->SetProtoMethod(t, "getALPNNegotiatedProtocol", GetALPNNegotiatedProto);
|
||||
env->SetProtoMethod(t, "setALPNProtocols", SetALPNProtocols);
|
||||
}
|
||||
|
||||
|
||||
template <class Base>
|
||||
void SSLWrap<Base>::InitNPN(SecureContext* sc) {
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
// Server should advertise NPN protocols
|
||||
SSL_CTX_set_next_protos_advertised_cb(sc->ctx_,
|
||||
AdvertiseNextProtoCallback,
|
||||
nullptr);
|
||||
// Client should select protocol from list of advertised
|
||||
// If server supports NPN
|
||||
SSL_CTX_set_next_proto_select_cb(sc->ctx_, SelectNextProtoCallback, nullptr);
|
||||
#endif // OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
void SSLWrap<Base>::ConfigureSecureContext(SecureContext* sc) {
|
||||
#ifdef NODE__HAVE_TLSEXT_STATUS_CB
|
||||
// OCSP stapling
|
||||
SSL_CTX_set_tlsext_status_cb(sc->ctx_, TLSExtStatusCallback);
|
||||
@ -2474,148 +2440,6 @@ void SSLWrap<Base>::GetProtocol(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
template <class Base>
|
||||
int SSLWrap<Base>::AdvertiseNextProtoCallback(SSL* s,
|
||||
const unsigned char** data,
|
||||
unsigned int* len,
|
||||
void* arg) {
|
||||
Base* w = static_cast<Base*>(SSL_get_app_data(s));
|
||||
Environment* env = w->env();
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
|
||||
auto npn_buffer =
|
||||
w->object()->GetPrivate(
|
||||
env->context(),
|
||||
env->npn_buffer_private_symbol()).ToLocalChecked();
|
||||
|
||||
if (npn_buffer->IsUndefined()) {
|
||||
// No initialization - no NPN protocols
|
||||
*data = reinterpret_cast<const unsigned char*>("");
|
||||
*len = 0;
|
||||
} else {
|
||||
CHECK(Buffer::HasInstance(npn_buffer));
|
||||
*data = reinterpret_cast<const unsigned char*>(Buffer::Data(npn_buffer));
|
||||
*len = Buffer::Length(npn_buffer);
|
||||
}
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
template <class Base>
|
||||
int SSLWrap<Base>::SelectNextProtoCallback(SSL* s,
|
||||
unsigned char** out,
|
||||
unsigned char* outlen,
|
||||
const unsigned char* in,
|
||||
unsigned int inlen,
|
||||
void* arg) {
|
||||
Base* w = static_cast<Base*>(SSL_get_app_data(s));
|
||||
Environment* env = w->env();
|
||||
HandleScope handle_scope(env->isolate());
|
||||
Context::Scope context_scope(env->context());
|
||||
|
||||
auto npn_buffer =
|
||||
w->object()->GetPrivate(
|
||||
env->context(),
|
||||
env->npn_buffer_private_symbol()).ToLocalChecked();
|
||||
|
||||
if (npn_buffer->IsUndefined()) {
|
||||
// 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
|
||||
CHECK(
|
||||
w->object()->SetPrivate(
|
||||
env->context(),
|
||||
env->selected_npn_buffer_private_symbol(),
|
||||
False(env->isolate())).FromJust());
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
CHECK(Buffer::HasInstance(npn_buffer));
|
||||
const unsigned char* npn_protos =
|
||||
reinterpret_cast<const unsigned char*>(Buffer::Data(npn_buffer));
|
||||
size_t len = Buffer::Length(npn_buffer);
|
||||
|
||||
int status = SSL_select_next_proto(out, outlen, in, inlen, npn_protos, len);
|
||||
Local<Value> result;
|
||||
switch (status) {
|
||||
case OPENSSL_NPN_UNSUPPORTED:
|
||||
result = Null(env->isolate());
|
||||
break;
|
||||
case OPENSSL_NPN_NEGOTIATED:
|
||||
result = OneByteString(env->isolate(), *out, *outlen);
|
||||
break;
|
||||
case OPENSSL_NPN_NO_OVERLAP:
|
||||
result = False(env->isolate());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CHECK(
|
||||
w->object()->SetPrivate(
|
||||
env->context(),
|
||||
env->selected_npn_buffer_private_symbol(),
|
||||
result).FromJust());
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
template <class Base>
|
||||
void SSLWrap<Base>::GetNegotiatedProto(
|
||||
const FunctionCallbackInfo<Value>& args) {
|
||||
Base* w;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
|
||||
Environment* env = w->env();
|
||||
|
||||
if (w->is_client()) {
|
||||
auto selected_npn_buffer =
|
||||
w->object()->GetPrivate(
|
||||
env->context(),
|
||||
env->selected_npn_buffer_private_symbol()).ToLocalChecked();
|
||||
args.GetReturnValue().Set(selected_npn_buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned char* npn_proto;
|
||||
unsigned int npn_proto_len;
|
||||
|
||||
SSL_get0_next_proto_negotiated(w->ssl_, &npn_proto, &npn_proto_len);
|
||||
|
||||
if (!npn_proto)
|
||||
return args.GetReturnValue().Set(false);
|
||||
|
||||
args.GetReturnValue().Set(
|
||||
OneByteString(args.GetIsolate(), npn_proto, npn_proto_len));
|
||||
}
|
||||
|
||||
|
||||
template <class Base>
|
||||
void SSLWrap<Base>::SetNPNProtocols(const FunctionCallbackInfo<Value>& args) {
|
||||
Base* w;
|
||||
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
|
||||
Environment* env = w->env();
|
||||
|
||||
if (args.Length() < 1)
|
||||
return env->ThrowTypeError("NPN protocols argument is mandatory");
|
||||
|
||||
THROW_AND_RETURN_IF_NOT_BUFFER(args[0], "NPN protocols");
|
||||
|
||||
CHECK(
|
||||
w->object()->SetPrivate(
|
||||
env->context(),
|
||||
env->npn_buffer_private_symbol(),
|
||||
args[0]).FromJust());
|
||||
}
|
||||
#endif // OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
|
||||
template <class Base>
|
||||
int SSLWrap<Base>::SelectALPNCallback(SSL* s,
|
||||
@ -2883,7 +2707,7 @@ void SSLWrap<Base>::DestroySSL() {
|
||||
|
||||
template <class Base>
|
||||
void SSLWrap<Base>::SetSNIContext(SecureContext* sc) {
|
||||
InitNPN(sc);
|
||||
ConfigureSecureContext(sc);
|
||||
CHECK_EQ(SSL_set_SSL_CTX(ssl_, sc->ctx_), sc->ctx_);
|
||||
|
||||
SetCACerts(sc);
|
||||
|
@ -249,7 +249,7 @@ class SSLWrap {
|
||||
static const int64_t kExternalSize = 4448 + 1024 + 42 * 1024;
|
||||
#endif
|
||||
|
||||
static void InitNPN(SecureContext* sc);
|
||||
static void ConfigureSecureContext(SecureContext* sc);
|
||||
static void AddMethods(Environment* env, v8::Local<v8::FunctionTemplate> t);
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
@ -295,22 +295,6 @@ class SSLWrap {
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
#endif // SSL_set_max_send_fragment
|
||||
|
||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||
static void GetNegotiatedProto(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SetNPNProtocols(const v8::FunctionCallbackInfo<v8::Value>& 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 // OPENSSL_NO_NEXTPROTONEG
|
||||
|
||||
static void GetALPNNegotiatedProto(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
static void SetALPNProtocols(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||
|
@ -135,7 +135,7 @@ void TLSWrap::InitSSL() {
|
||||
}
|
||||
#endif // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
||||
|
||||
InitNPN(sc_);
|
||||
ConfigureSecureContext(sc_);
|
||||
|
||||
SSL_set_cert_cb(ssl_, SSLWrap<TLSWrap>::SSLCertCallback, this);
|
||||
|
||||
|
@ -12,12 +12,13 @@ const dftProtocol = {};
|
||||
|
||||
// test for immutable `opts`
|
||||
{
|
||||
const opts = { foo: 'bar', NPNProtocols: [ 'http/1.1' ] };
|
||||
const opts = { foo: 'bar', ALPNProtocols: [ 'http/1.1' ] };
|
||||
const server = https.createServer(opts);
|
||||
|
||||
tls.convertNPNProtocols([ 'http/1.1' ], dftProtocol);
|
||||
assert.deepStrictEqual(opts, { foo: 'bar', NPNProtocols: [ 'http/1.1' ] });
|
||||
assert.strictEqual(server.NPNProtocols.compare(dftProtocol.NPNProtocols), 0);
|
||||
tls.convertALPNProtocols([ 'http/1.1' ], dftProtocol);
|
||||
assert.deepStrictEqual(opts, { foo: 'bar', ALPNProtocols: [ 'http/1.1' ] });
|
||||
assert.strictEqual(server.ALPNProtocols.compare(dftProtocol.ALPNProtocols),
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
@ -26,8 +27,9 @@ const dftProtocol = {};
|
||||
const mustNotCall = common.mustNotCall();
|
||||
const server = https.createServer(mustNotCall);
|
||||
|
||||
tls.convertNPNProtocols([ 'http/1.1', 'http/1.0' ], dftProtocol);
|
||||
assert.strictEqual(server.NPNProtocols.compare(dftProtocol.NPNProtocols), 0);
|
||||
tls.convertALPNProtocols([ 'http/1.1' ], dftProtocol);
|
||||
assert.strictEqual(server.ALPNProtocols.compare(dftProtocol.ALPNProtocols),
|
||||
0);
|
||||
assert.strictEqual(server.listeners('request').length, 1);
|
||||
assert.strictEqual(server.listeners('request')[0], mustNotCall);
|
||||
}
|
||||
@ -37,6 +39,7 @@ const dftProtocol = {};
|
||||
{
|
||||
const server = https.createServer();
|
||||
|
||||
assert.strictEqual(server.NPNProtocols.compare(dftProtocol.NPNProtocols), 0);
|
||||
assert.strictEqual(server.ALPNProtocols.compare(dftProtocol.ALPNProtocols),
|
||||
0);
|
||||
assert.strictEqual(server.listeners('request').length, 0);
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
if (!process.features.tls_alpn || !process.features.tls_npn) {
|
||||
if (!process.features.tls_alpn) {
|
||||
common.skip(
|
||||
'Skipping because node compiled without NPN or ALPN feature of OpenSSL.');
|
||||
'Skipping because node compiled without ALPN feature of OpenSSL.');
|
||||
}
|
||||
|
||||
const assert = require('assert');
|
||||
@ -21,9 +21,7 @@ const serverIP = common.localhostIPv4;
|
||||
|
||||
function checkResults(result, expected) {
|
||||
assert.strictEqual(result.server.ALPN, expected.server.ALPN);
|
||||
assert.strictEqual(result.server.NPN, expected.server.NPN);
|
||||
assert.strictEqual(result.client.ALPN, expected.client.ALPN);
|
||||
assert.strictEqual(result.client.NPN, expected.client.NPN);
|
||||
}
|
||||
|
||||
function runTest(clientsOptions, serverOptions, cb) {
|
||||
@ -32,7 +30,7 @@ function runTest(clientsOptions, serverOptions, cb) {
|
||||
const results = [];
|
||||
let index = 0;
|
||||
const server = tls.createServer(serverOptions, function(c) {
|
||||
results[index].server = { ALPN: c.alpnProtocol, NPN: c.npnProtocol };
|
||||
results[index].server = { ALPN: c.alpnProtocol };
|
||||
});
|
||||
|
||||
server.listen(0, serverIP, function() {
|
||||
@ -47,8 +45,7 @@ function runTest(clientsOptions, serverOptions, cb) {
|
||||
|
||||
results[index] = {};
|
||||
const client = tls.connect(opt, function() {
|
||||
results[index].client = { ALPN: client.alpnProtocol,
|
||||
NPN: client.npnProtocol };
|
||||
results[index].client = { ALPN: client.alpnProtocol };
|
||||
client.destroy();
|
||||
if (options.length) {
|
||||
index++;
|
||||
@ -62,471 +59,109 @@ function runTest(clientsOptions, serverOptions, cb) {
|
||||
|
||||
}
|
||||
|
||||
// Server: ALPN/NPN, Client: ALPN/NPN
|
||||
// Server: ALPN, Client: ALPN
|
||||
function Test1() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNProtocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e'],
|
||||
NPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y'],
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// 'a' is selected by ALPN
|
||||
checkResults(results[0],
|
||||
{ server: { ALPN: 'a', NPN: false },
|
||||
client: { ALPN: 'a', NPN: undefined } });
|
||||
{ server: { ALPN: 'a' },
|
||||
client: { ALPN: 'a' } });
|
||||
// 'b' is selected by ALPN
|
||||
checkResults(results[1],
|
||||
{ server: { ALPN: 'b', NPN: false },
|
||||
client: { ALPN: 'b', NPN: undefined } });
|
||||
{ server: { ALPN: 'b' },
|
||||
client: { ALPN: 'b' } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'first-priority-unsupported' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
{ server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// execute next test
|
||||
Test2();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: ALPN/NPN, Client: ALPN
|
||||
// Server: ALPN, Client: Nothing
|
||||
function Test2() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
const clientsOptions = [{}, {}, {}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// 'a' is selected by ALPN
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[0],
|
||||
{ server: { ALPN: 'a', NPN: false },
|
||||
client: { ALPN: 'a', NPN: undefined } });
|
||||
// 'b' is selected by ALPN
|
||||
{ server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[1],
|
||||
{ server: { ALPN: 'b', NPN: false },
|
||||
client: { ALPN: 'b', NPN: undefined } });
|
||||
{ server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
{ server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// execute next test
|
||||
Test3();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: ALPN/NPN, Client: NPN
|
||||
// Server: Nothing, Client: ALPN
|
||||
function Test3() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
const serverOptions = {};
|
||||
|
||||
const clientsOptions = [{
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
ALPNrotocols: ['a', 'b', 'c'],
|
||||
}, {
|
||||
NPPNProtocols: ['c', 'b', 'e']
|
||||
ALPNProtocols: ['c', 'b', 'e'],
|
||||
}, {
|
||||
NPPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y'],
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// 'a' is selected by NPN
|
||||
checkResults(results[0],
|
||||
{ server: { ALPN: false, NPN: 'a' },
|
||||
client: { ALPN: false, NPN: 'a' } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[1],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
// nothing is selected
|
||||
checkResults(results[0], { server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[1], { server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
{ server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// execute next test
|
||||
Test4();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: ALPN/NPN, Client: Nothing
|
||||
function Test4() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{}, {}, {}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[0],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[1],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test5();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: ALPN, Client: ALPN/NPN
|
||||
function Test5() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNProtocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e'],
|
||||
NPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y'],
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// 'a' is selected by ALPN
|
||||
checkResults(results[0], { server: { ALPN: 'a', NPN: false },
|
||||
client: { ALPN: 'a', NPN: undefined } });
|
||||
// 'b' is selected by ALPN
|
||||
checkResults(results[1], { server: { ALPN: 'b', NPN: false },
|
||||
client: { ALPN: 'b', NPN: undefined } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[2], { server: { ALPN: false,
|
||||
NPN: 'first-priority-unsupported' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test6();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: ALPN, Client: ALPN
|
||||
function Test6() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// 'a' is selected by ALPN
|
||||
checkResults(results[0], { server: { ALPN: 'a', NPN: false },
|
||||
client: { ALPN: 'a', NPN: undefined } });
|
||||
// 'b' is selected by ALPN
|
||||
checkResults(results[1], { server: { ALPN: 'b', NPN: false },
|
||||
client: { ALPN: 'b', NPN: undefined } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[2], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test7();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: ALPN, Client: NPN
|
||||
function Test7() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
NPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'a' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'c' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'first-priority-unsupported' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test8();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: ALPN, Client: Nothing
|
||||
function Test8() {
|
||||
const serverOptions = {
|
||||
ALPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{}, {}, {}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected by ALPN
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test9();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: NPN, Client: ALPN/NPN
|
||||
function Test9() {
|
||||
const serverOptions = {
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNrotocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e'],
|
||||
NPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y'],
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// 'a' is selected by NPN
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'a' },
|
||||
client: { ALPN: false, NPN: 'a' } });
|
||||
// 'b' is selected by NPN
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'b' },
|
||||
client: { ALPN: false, NPN: 'b' } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'first-priority-unsupported' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test10();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: NPN, Client: ALPN
|
||||
function Test10() {
|
||||
const serverOptions = {
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[2], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test11();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: NPN, Client: NPN
|
||||
function Test11() {
|
||||
const serverOptions = {
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
NPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// 'a' is selected by NPN
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'a' },
|
||||
client: { ALPN: false, NPN: 'a' } });
|
||||
// 'b' is selected by NPN
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'b' },
|
||||
client: { ALPN: false, NPN: 'b' } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'first-priority-unsupported' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test12();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: NPN, Client: Nothing
|
||||
function Test12() {
|
||||
const serverOptions = {
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{}, {}, {}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test13();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: Nothing, Client: ALPN/NPN
|
||||
function Test13() {
|
||||
const serverOptions = {};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNrotocols: ['a', 'b', 'c'],
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e'],
|
||||
NPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y'],
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'a' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'c' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'first-priority-unsupported' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test14();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: Nothing, Client: ALPN
|
||||
function Test14() {
|
||||
const serverOptions = {};
|
||||
|
||||
const clientsOptions = [{
|
||||
ALPNrotocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
ALPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
ALPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test15();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: Nothing, Client: NPN
|
||||
function Test15() {
|
||||
const serverOptions = {};
|
||||
|
||||
const clientsOptions = [{
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
}, {
|
||||
NPNProtocols: ['c', 'b', 'e']
|
||||
}, {
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y']
|
||||
}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'a' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'c' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'first-priority-unsupported' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
// execute next test
|
||||
Test16();
|
||||
});
|
||||
}
|
||||
|
||||
// Server: Nothing, Client: Nothing
|
||||
function Test16() {
|
||||
function Test4() {
|
||||
const serverOptions = {};
|
||||
|
||||
const clientsOptions = [{}, {}, {}];
|
||||
|
||||
runTest(clientsOptions, serverOptions, function(results) {
|
||||
// nothing is selected
|
||||
checkResults(results[0], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
checkResults(results[0], { server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[1], { server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
checkResults(results[1], { server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
// nothing is selected
|
||||
checkResults(results[2],
|
||||
{ server: { ALPN: false, NPN: 'http/1.1' },
|
||||
client: { ALPN: false, NPN: false } });
|
||||
{ server: { ALPN: false },
|
||||
client: { ALPN: false } });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
// 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.
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
if (!process.features.tls_npn)
|
||||
common.skip('Skipping because node compiled without NPN feature of OpenSSL.');
|
||||
|
||||
const assert = require('assert');
|
||||
const tls = require('tls');
|
||||
const fixtures = require('../common/fixtures');
|
||||
|
||||
function loadPEM(n) {
|
||||
return fixtures.readKey(`${n}.pem`);
|
||||
}
|
||||
|
||||
const serverOptions = {
|
||||
key: loadPEM('agent2-key'),
|
||||
cert: loadPEM('agent2-cert'),
|
||||
crl: loadPEM('ca2-crl'),
|
||||
SNICallback: function(servername, cb) {
|
||||
cb(null, tls.createSecureContext({
|
||||
key: loadPEM('agent2-key'),
|
||||
cert: loadPEM('agent2-cert'),
|
||||
crl: loadPEM('ca2-crl'),
|
||||
}));
|
||||
},
|
||||
NPNProtocols: ['a', 'b', 'c']
|
||||
};
|
||||
|
||||
const clientsOptions = [{
|
||||
port: undefined,
|
||||
key: serverOptions.key,
|
||||
cert: serverOptions.cert,
|
||||
crl: serverOptions.crl,
|
||||
NPNProtocols: ['a', 'b', 'c'],
|
||||
rejectUnauthorized: false
|
||||
}, {
|
||||
port: undefined,
|
||||
key: serverOptions.key,
|
||||
cert: serverOptions.cert,
|
||||
crl: serverOptions.crl,
|
||||
NPNProtocols: ['c', 'b', 'e'],
|
||||
rejectUnauthorized: false
|
||||
}, {
|
||||
port: undefined,
|
||||
key: serverOptions.key,
|
||||
cert: serverOptions.cert,
|
||||
crl: serverOptions.crl,
|
||||
rejectUnauthorized: false
|
||||
}, {
|
||||
port: undefined,
|
||||
key: serverOptions.key,
|
||||
cert: serverOptions.cert,
|
||||
crl: serverOptions.crl,
|
||||
NPNProtocols: ['first-priority-unsupported', 'x', 'y'],
|
||||
rejectUnauthorized: false
|
||||
}];
|
||||
|
||||
const serverResults = [];
|
||||
const clientsResults = [];
|
||||
|
||||
const server = tls.createServer(serverOptions, function(c) {
|
||||
serverResults.push(c.npnProtocol);
|
||||
});
|
||||
server.listen(0, startTest);
|
||||
|
||||
function startTest() {
|
||||
function connectClient(options, callback) {
|
||||
options.port = server.address().port;
|
||||
const client = tls.connect(options, function() {
|
||||
clientsResults.push(client.npnProtocol);
|
||||
client.destroy();
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
connectClient(clientsOptions[0], function() {
|
||||
connectClient(clientsOptions[1], function() {
|
||||
connectClient(clientsOptions[2], function() {
|
||||
connectClient(clientsOptions[3], function() {
|
||||
server.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
process.on('exit', function() {
|
||||
assert.strictEqual(serverResults[0], clientsResults[0]);
|
||||
assert.strictEqual(serverResults[1], clientsResults[1]);
|
||||
assert.strictEqual(serverResults[2], 'http/1.1');
|
||||
assert.strictEqual(clientsResults[2], false);
|
||||
assert.strictEqual(serverResults[3], 'first-priority-unsupported');
|
||||
assert.strictEqual(clientsResults[3], false);
|
||||
});
|
@ -1,7 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
// Test that TLSSocket can take arrays of strings for ALPNProtocols and
|
||||
// NPNProtocols.
|
||||
// Test that TLSSocket can take arrays of strings for ALPNProtocols.
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
@ -12,12 +11,8 @@ const tls = require('tls');
|
||||
|
||||
new tls.TLSSocket(null, {
|
||||
ALPNProtocols: ['http/1.1'],
|
||||
NPNProtocols: ['http/1.1']
|
||||
});
|
||||
|
||||
if (!process.features.tls_npn)
|
||||
common.skip('node compiled without NPN feature of OpenSSL');
|
||||
|
||||
if (!process.features.tls_alpn)
|
||||
common.skip('node compiled without ALPN feature of OpenSSL');
|
||||
|
||||
@ -37,17 +32,15 @@ const server = net.createServer(common.mustCall((s) => {
|
||||
key,
|
||||
cert,
|
||||
ALPNProtocols: ['http/1.1'],
|
||||
NPNProtocols: ['http/1.1']
|
||||
});
|
||||
|
||||
tlsSocket.on('secure', common.mustCall(() => {
|
||||
protocols.push({
|
||||
alpnProtocol: tlsSocket.alpnProtocol,
|
||||
npnProtocol: tlsSocket.npnProtocol
|
||||
});
|
||||
tlsSocket.end();
|
||||
}));
|
||||
}, 2));
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
const alpnOpts = {
|
||||
@ -55,24 +48,14 @@ server.listen(0, common.mustCall(() => {
|
||||
rejectUnauthorized: false,
|
||||
ALPNProtocols: ['h2', 'http/1.1']
|
||||
};
|
||||
const npnOpts = {
|
||||
port: server.address().port,
|
||||
rejectUnauthorized: false,
|
||||
NPNProtocols: ['h2', 'http/1.1']
|
||||
};
|
||||
|
||||
tls.connect(alpnOpts, function() {
|
||||
this.end();
|
||||
|
||||
tls.connect(npnOpts, function() {
|
||||
this.end();
|
||||
server.close();
|
||||
|
||||
server.close();
|
||||
|
||||
assert.deepStrictEqual(protocols, [
|
||||
{ alpnProtocol: 'http/1.1', npnProtocol: false },
|
||||
{ alpnProtocol: false, npnProtocol: 'http/1.1' }
|
||||
]);
|
||||
});
|
||||
assert.deepStrictEqual(protocols, [
|
||||
{ alpnProtocol: 'http/1.1' },
|
||||
]);
|
||||
});
|
||||
}));
|
Loading…
x
Reference in New Issue
Block a user