summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorShigeki Ohtsu <ohtsu@iij.ad.jp>2015-04-23 15:25:15 +0900
committerShigeki Ohtsu <ohtsu@iij.ad.jp>2015-10-27 01:31:47 +0900
commit802a2e79e1adb22542ba12fba5e331e94277272d (patch)
tree601aa8947e9d78b0f9a912964738909ca40e086a /lib
parentdf738ac56c31ac8a04d6afbd3d7be59cfa5c2e9a (diff)
downloadandroid-node-v8-802a2e79e1adb22542ba12fba5e331e94277272d.tar.gz
android-node-v8-802a2e79e1adb22542ba12fba5e331e94277272d.tar.bz2
android-node-v8-802a2e79e1adb22542ba12fba5e331e94277272d.zip
tls, crypto: add ALPN Support
ALPN is added to tls according to RFC7301, which supersedes NPN. When the server receives both NPN and ALPN extensions from the client, ALPN takes precedence over NPN and the server does not send NPN extension to the client. alpnProtocol in TLSSocket always returns false when no selected protocol exists by ALPN. In https server, http/1.1 token is always set when no options.ALPNProtocols exists. PR-URL: https://github.com/nodejs/node/pull/2564 Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Diffstat (limited to 'lib')
-rw-r--r--lib/_tls_legacy.js15
-rw-r--r--lib/_tls_wrap.js17
-rw-r--r--lib/https.js7
-rw-r--r--lib/tls.js51
4 files changed, 70 insertions, 20 deletions
diff --git a/lib/_tls_legacy.js b/lib/_tls_legacy.js
index 7f7707d149..8c079e341b 100644
--- a/lib/_tls_legacy.js
+++ b/lib/_tls_legacy.js
@@ -177,7 +177,7 @@ CryptoStream.prototype._write = function write(data, encoding, cb) {
if (this.pair.encrypted._internallyPendingBytes())
this.pair.encrypted.read(0);
- // Get NPN and Server name when ready
+ // Get ALPN, NPN and Server name when ready
this.pair.maybeInitFinished();
// Whole buffer was written
@@ -273,7 +273,7 @@ CryptoStream.prototype._read = function read(size) {
bytesRead < size &&
this.pair.ssl !== null);
- // Get NPN and Server name when ready
+ // Get ALPN, NPN and Server name when ready
this.pair.maybeInitFinished();
// Create new buffer if previous was filled up
@@ -726,6 +726,13 @@ function SecurePair(context, isServer, requestCert, rejectUnauthorized,
this.npnProtocol = null;
}
+ if (process.features.tls_alpn && options.ALPNProtocols) {
+ // keep reference in secureContext not to be GC-ed
+ this.ssl._secureContext.alpnBuffer = options.ALPNProtocols;
+ this.ssl.setALPNrotocols(this.ssl._secureContext.alpnBuffer);
+ this.alpnProtocol = null;
+ }
+
/* Acts as a r/w stream to the cleartext side of the stream. */
this.cleartext = new CleartextStream(this, options.cleartext);
@@ -778,6 +785,10 @@ SecurePair.prototype.maybeInitFinished = function() {
this.npnProtocol = this.ssl.getNegotiatedProtocol();
}
+ if (process.features.tls_alpn) {
+ this.alpnProtocol = this.ssl.getALPNNegotiatedProtocol();
+ }
+
if (process.features.tls_sni) {
this.servername = this.ssl.getServername();
}
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index f027347177..d918656a36 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -239,6 +239,7 @@ function TLSSocket(socket, options) {
this._SNICallback = null;
this.servername = null;
this.npnProtocol = null;
+ this.alpnProtocol = null;
this.authorized = false;
this.authorizationError = null;
@@ -453,6 +454,12 @@ TLSSocket.prototype._init = function(socket, wrap) {
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;
+ ssl.setALPNProtocols(ssl._secureContext.alpnBuffer);
+ }
+
if (options.handshakeTimeout > 0)
this.setTimeout(options.handshakeTimeout, this._handleTimeout);
@@ -559,6 +566,10 @@ TLSSocket.prototype._finishInit = function() {
this.npnProtocol = this._handle.getNegotiatedProtocol();
}
+ if (process.features.tls_alpn) {
+ this.alpnProtocol = this.ssl.getALPNNegotiatedProtocol();
+ }
+
if (process.features.tls_sni && this._tlsOptions.isServer) {
this.servername = this._handle.getServername();
}
@@ -766,6 +777,7 @@ function Server(/* [options], listener */) {
rejectUnauthorized: self.rejectUnauthorized,
handshakeTimeout: timeout,
NPNProtocols: self.NPNProtocols,
+ ALPNProtocols: self.ALPNProtocols,
SNICallback: options.SNICallback || SNICallback
});
@@ -876,6 +888,8 @@ Server.prototype.setOptions = function(options) {
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) {
this.sessionIdContext = options.sessionIdContext;
} else {
@@ -968,8 +982,10 @@ exports.connect = function(/* [port, host], options, cb */) {
(options.socket && options.socket._host) ||
'localhost',
NPN = {},
+ ALPN = {},
context = tls.createSecureContext(options);
tls.convertNPNProtocols(options.NPNProtocols, NPN);
+ tls.convertALPNProtocols(options.ALPNProtocols, ALPN);
var socket = new TLSSocket(options.socket, {
pipe: options.path && !options.port,
@@ -979,6 +995,7 @@ exports.connect = function(/* [port, host], options, cb */) {
rejectUnauthorized: options.rejectUnauthorized,
session: options.session,
NPNProtocols: NPN.NPNProtocols,
+ ALPNProtocols: ALPN.ALPNProtocols,
requestOCSP: options.requestOCSP
});
diff --git a/lib/https.js b/lib/https.js
index abe4a20907..edf0aa4432 100644
--- a/lib/https.js
+++ b/lib/https.js
@@ -14,6 +14,13 @@ function Server(opts, requestListener) {
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
+ // /tls-extensiontype-values.xhtml#alpn-protocol-ids
+ opts.ALPNProtocols = ['http/1.1'];
+ }
+
tls.Server.call(this, opts, http._connectionListener);
this.httpAllowHalfOpen = false;
diff --git a/lib/tls.js b/lib/tls.js
index 0d85a948dc..e269e800d3 100644
--- a/lib/tls.js
+++ b/lib/tls.js
@@ -33,27 +33,42 @@ exports.getCiphers = function() {
// Convert protocols array into valid OpenSSL protocols list
// ("\x06spdy/2\x08http/1.1\x08http/1.0")
-exports.convertNPNProtocols = 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;
+function convertProtocols(protocols) {
+ var buff = new Buffer(protocols.reduce(function(p, c) {
+ return p + 1 + Buffer.byteLength(c);
+ }, 0));
+
+ protocols.reduce(function(offset, c) {
+ var clen = Buffer.byteLength(c);
+ buff[offset] = clen;
+ buff.write(c, offset + 1);
+
+ return offset + 1 + clen;
+ }, 0);
+
+ return buff;
+};
+
+exports.convertNPNProtocols = function(protocols, out) {
+ // If protocols is Array - translate it into buffer
+ if (Array.isArray(protocols)) {
+ protocols = convertProtocols(protocols);
}
+ // If it's already a Buffer - store it
+ if (protocols instanceof Buffer) {
+ out.NPNProtocols = protocols;
+ }
+};
+exports.convertALPNProtocols = function(protocols, out) {
+ // If protocols is Array - translate it into buffer
+ if (Array.isArray(protocols)) {
+ protocols = convertProtocols(protocols);
+ }
// If it's already a Buffer - store it
- if (NPNProtocols instanceof Buffer) {
- out.NPNProtocols = NPNProtocols;
+ if (protocols instanceof Buffer) {
+ // copy new buffer not to be modified by user
+ out.ALPNProtocols = new Buffer(protocols);
}
};