| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 1a968e6 commit 62ad1d0
11 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -66,14 +66,15 @@ and tap `R<CR>` (that's the letter `R` followed by a carriage return) a few | |||
| 66 | 66 | times. | |
| 67 | 67 | ||
| 68 | 68 | ||
| 69 | - ## NPN and SNI | ||
| 69 | + ## ALPN, NPN and SNI | ||
| 70 | 70 | ||
| 71 | 71 | <!-- type=misc --> | |
| 72 | 72 | ||
| 73 | - NPN (Next Protocol Negotiation) and SNI (Server Name Indication) are TLS | ||
| 73 | + ALPN (Application-Layer Protocol Negotiation Extension), NPN (Next | ||
| 74 | + Protocol Negotiation) and SNI (Server Name Indication) are TLS | ||
| 74 | 75 | handshake extensions allowing you: | |
| 75 | 76 | ||
| 76 | - * NPN - to use one TLS server for multiple protocols (HTTP, SPDY) | ||
| 77 | + * ALPN/NPN - to use one TLS server for multiple protocols (HTTP, SPDY, HTTP/2) | ||
| 77 | 78 | * SNI - to use one TLS server for multiple hostnames with different SSL | |
| 78 | 79 | certificates. | |
| 79 | 80 | ||
@@ -249,6 +250,12 @@ automatically set as a listener for the [secureConnection][] event. The | |||
| 249 | 250 | - `NPNProtocols`: An array or `Buffer` of possible NPN protocols. (Protocols | |
| 250 | 251 | should be ordered by their priority). | |
| 251 | 252 | ||
| 253 | + - `ALPNProtocols`: An array or `Buffer` of possible ALPN | ||
| 254 | + protocols. (Protocols should be ordered by their priority). When | ||
| 255 | + the server receives both NPN and ALPN extensions from the client, | ||
| 256 | + ALPN takes precedence over NPN and the server does not send an NPN | ||
| 257 | + extension to the client. | ||
| 258 | + | ||
| 252 | 259 | - `SNICallback(servername, cb)`: A function that will be called if client | |
| 253 | 260 | supports SNI TLS extension. Two argument will be passed to it: `servername`, | |
| 254 | 261 | and `cb`. `SNICallback` should invoke `cb(null, ctx)`, where `ctx` is a | |
@@ -372,9 +379,16 @@ Creates a new client connection to the given `port` and `host` (old API) or | |||
| 372 | 379 | fails; `err.code` contains the OpenSSL error code. Default: `true`. | |
| 373 | 380 | ||
| 374 | 381 | - `NPNProtocols`: An array of strings or `Buffer`s containing supported NPN | |
| 375 | - protocols. `Buffer`s should have following format: `0x05hello0x05world`, | ||
| 376 | - where first byte is next protocol name's length. (Passing array should | ||
| 377 | - usually be much simpler: `['hello', 'world']`.) | ||
| 382 | + protocols. `Buffer`s should have the following format: | ||
| 383 | + `0x05hello0x05world`, where first byte is next protocol name's | ||
| 384 | + length. (Passing array should usually be much simpler: | ||
| 385 | + `['hello', 'world']`.) | ||
| 386 | + | ||
| 387 | + - `ALPNProtocols`: An array of strings or `Buffer`s containing | ||
| 388 | + supported ALPN protocols. `Buffer`s should have following format: | ||
| 389 | + `0x05hello0x05world`, where the first byte is the next protocol | ||
| 390 | + name's length. (Passing array should usually be much simpler: | ||
| 391 | + `['hello', 'world']`.) | ||
| 378 | 392 | ||
| 379 | 393 | - `servername`: Servername for SNI (Server Name Indication) TLS extension. | |
| 380 | 394 | ||
@@ -476,6 +490,8 @@ Construct a new TLSSocket object from existing TCP socket. | |||
| 476 | 490 | ||
| 477 | 491 | - `NPNProtocols`: Optional, see [tls.createServer][] | |
| 478 | 492 | ||
| 493 | + - `ALPNProtocols`: Optional, see [tls.createServer][] | ||
| 494 | + | ||
| 479 | 495 | - `SNICallback`: Optional, see [tls.createServer][] | |
| 480 | 496 | ||
| 481 | 497 | - `session`: Optional, a `Buffer` instance, containing TLS session | |
@@ -571,7 +587,13 @@ server. If `socket.authorized` is false, then | |||
| 571 | 587 | `socket.authorizationError` is set to describe how authorization | |
| 572 | 588 | failed. Implied but worth mentioning: depending on the settings of the TLS | |
| 573 | 589 | server, you unauthorized connections may be accepted. | |
| 574 | - `socket.npnProtocol` is a string containing selected NPN protocol. | ||
| 590 | + | ||
| 591 | + `socket.npnProtocol` is a string containing the selected NPN protocol | ||
| 592 | + and `socket.alpnProtocol` is a string containing the selected ALPN | ||
| 593 | + protocol, When both NPN and ALPN extensions are received, ALPN takes | ||
| 594 | + precedence over NPN and the next protocol is selected by ALPN. When | ||
| 595 | + ALPN has no selected protocol, this returns false. | ||
| 596 | + | ||
| 575 | 597 | `socket.servername` is a string containing servername requested with | |
| 576 | 598 | SNI. | |
| 577 | 599 | ||
@@ -744,8 +766,9 @@ The listener will be called no matter if the server's certificate was | |||
| 744 | 766 | authorized or not. It is up to the user to test `tlsSocket.authorized` | |
| 745 | 767 | to see if the server certificate was signed by one of the specified CAs. | |
| 746 | 768 | If `tlsSocket.authorized === false` then the error can be found in | |
| 747 | - `tlsSocket.authorizationError`. Also if NPN was used - you can check | ||
| 748 | - `tlsSocket.npnProtocol` for negotiated protocol. | ||
| 769 | + `tlsSocket.authorizationError`. Also if ALPN or NPN was used - you can | ||
| 770 | + check `tlsSocket.alpnProtocol` or `tlsSocket.npnProtocol` for the | ||
| 771 | + negotiated protocol. | ||
| 749 | 772 | ||
| 750 | 773 | ### Event: 'OCSPResponse' | |
| 751 | 774 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -177,7 +177,7 @@ CryptoStream.prototype._write = function write(data, encoding, cb) { | |||
| 177 | 177 | if (this.pair.encrypted._internallyPendingBytes()) | |
| 178 | 178 | this.pair.encrypted.read(0); | |
| 179 | 179 | ||
| 180 | - // Get NPN and Server name when ready | ||
| 180 | + // Get ALPN, NPN and Server name when ready | ||
| 181 | 181 | this.pair.maybeInitFinished(); | |
| 182 | 182 | ||
| 183 | 183 | // Whole buffer was written | |
@@ -273,7 +273,7 @@ CryptoStream.prototype._read = function read(size) { | |||
| 273 | 273 | bytesRead < size && | |
| 274 | 274 | this.pair.ssl !== null); | |
| 275 | 275 | ||
| 276 | - // Get NPN and Server name when ready | ||
| 276 | + // Get ALPN, NPN and Server name when ready | ||
| 277 | 277 | this.pair.maybeInitFinished(); | |
| 278 | 278 | ||
| 279 | 279 | // Create new buffer if previous was filled up | |
@@ -726,6 +726,13 @@ function SecurePair(context, isServer, requestCert, rejectUnauthorized, | |||
| 726 | 726 | this.npnProtocol = null; | |
| 727 | 727 | } | |
| 728 | 728 | ||
| 729 | + if (process.features.tls_alpn && options.ALPNProtocols) { | ||
| 730 | + // keep reference in secureContext not to be GC-ed | ||
| 731 | + this.ssl._secureContext.alpnBuffer = options.ALPNProtocols; | ||
| 732 | + this.ssl.setALPNrotocols(this.ssl._secureContext.alpnBuffer); | ||
| 733 | + this.alpnProtocol = null; | ||
| 734 | + } | ||
| 735 | + | ||
| 729 | 736 | /* Acts as a r/w stream to the cleartext side of the stream. */ | |
| 730 | 737 | this.cleartext = new CleartextStream(this, options.cleartext); | |
| 731 | 738 | ||
@@ -778,6 +785,10 @@ SecurePair.prototype.maybeInitFinished = function() { | |||
| 778 | 785 | this.npnProtocol = this.ssl.getNegotiatedProtocol(); | |
| 779 | 786 | } | |
| 780 | 787 | ||
| 788 | + if (process.features.tls_alpn) { | ||
| 789 | + this.alpnProtocol = this.ssl.getALPNNegotiatedProtocol(); | ||
| 790 | + } | ||
| 791 | + | ||
| 781 | 792 | if (process.features.tls_sni) { | |
| 782 | 793 | this.servername = this.ssl.getServername(); | |
| 783 | 794 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -239,6 +239,7 @@ function TLSSocket(socket, options) { | |||
| 239 | 239 | this._SNICallback = null; | |
| 240 | 240 | this.servername = null; | |
| 241 | 241 | this.npnProtocol = null; | |
| 242 | + this.alpnProtocol = null; | ||
| 242 | 243 | this.authorized = false; | |
| 243 | 244 | this.authorizationError = null; | |
| 244 | 245 | ||
@@ -453,6 +454,12 @@ TLSSocket.prototype._init = function(socket, wrap) { | |||
| 453 | 454 | if (process.features.tls_npn && options.NPNProtocols) | |
| 454 | 455 | ssl.setNPNProtocols(options.NPNProtocols); | |
| 455 | 456 | ||
| 457 | + if (process.features.tls_alpn && options.ALPNProtocols) { | ||
| 458 | + // keep reference in secureContext not to be GC-ed | ||
| 459 | + ssl._secureContext.alpnBuffer = options.ALPNProtocols; | ||
| 460 | + ssl.setALPNProtocols(ssl._secureContext.alpnBuffer); | ||
| 461 | + } | ||
| 462 | + | ||
| 456 | 463 | if (options.handshakeTimeout > 0) | |
| 457 | 464 | this.setTimeout(options.handshakeTimeout, this._handleTimeout); | |
| 458 | 465 | ||
@@ -559,6 +566,10 @@ TLSSocket.prototype._finishInit = function() { | |||
| 559 | 566 | this.npnProtocol = this._handle.getNegotiatedProtocol(); | |
| 560 | 567 | } | |
| 561 | 568 | ||
| 569 | + if (process.features.tls_alpn) { | ||
| 570 | + this.alpnProtocol = this.ssl.getALPNNegotiatedProtocol(); | ||
| 571 | + } | ||
| 572 | + | ||
| 562 | 573 | if (process.features.tls_sni && this._tlsOptions.isServer) { | |
| 563 | 574 | this.servername = this._handle.getServername(); | |
| 564 | 575 | } | |
@@ -766,6 +777,7 @@ function Server(/* [options], listener */) { | |||
| 766 | 777 | rejectUnauthorized: self.rejectUnauthorized, | |
| 767 | 778 | handshakeTimeout: timeout, | |
| 768 | 779 | NPNProtocols: self.NPNProtocols, | |
| 780 | + ALPNProtocols: self.ALPNProtocols, | ||
| 769 | 781 | SNICallback: options.SNICallback || SNICallback | |
| 770 | 782 | }); | |
| 771 | 783 | ||
@@ -876,6 +888,8 @@ Server.prototype.setOptions = function(options) { | |||
| 876 | 888 | this.honorCipherOrder = true; | |
| 877 | 889 | if (secureOptions) this.secureOptions = secureOptions; | |
| 878 | 890 | if (options.NPNProtocols) tls.convertNPNProtocols(options.NPNProtocols, this); | |
| 891 | + if (options.ALPNProtocols) | ||
| 892 | + tls.convertALPNProtocols(options.ALPNProtocols, this); | ||
| 879 | 893 | if (options.sessionIdContext) { | |
| 880 | 894 | this.sessionIdContext = options.sessionIdContext; | |
| 881 | 895 | } else { | |
@@ -968,8 +982,10 @@ exports.connect = function(/* [port, host], options, cb */) { | |||
| 968 | 982 | (options.socket && options.socket._host) || | |
| 969 | 983 | 'localhost', | |
| 970 | 984 | NPN = {}, | |
| 985 | + ALPN = {}, | ||
| 971 | 986 | context = tls.createSecureContext(options); | |
| 972 | 987 | tls.convertNPNProtocols(options.NPNProtocols, NPN); | |
| 988 | + tls.convertALPNProtocols(options.ALPNProtocols, ALPN); | ||
| 973 | 989 | ||
| 974 | 990 | var socket = new TLSSocket(options.socket, { | |
| 975 | 991 | pipe: options.path && !options.port, | |
@@ -979,6 +995,7 @@ exports.connect = function(/* [port, host], options, cb */) { | |||
| 979 | 995 | rejectUnauthorized: options.rejectUnauthorized, | |
| 980 | 996 | session: options.session, | |
| 981 | 997 | NPNProtocols: NPN.NPNProtocols, | |
| 998 | + ALPNProtocols: ALPN.ALPNProtocols, | ||
| 982 | 999 | requestOCSP: options.requestOCSP | |
| 983 | 1000 | }); | |
| 984 | 1001 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -14,6 +14,13 @@ function Server(opts, requestListener) { | |||
| 14 | 14 | opts.NPNProtocols = ['http/1.1', 'http/1.0']; | |
| 15 | 15 | } | |
| 16 | 16 | ||
| 17 | + if (process.features.tls_alpn && !opts.ALPNProtocols) { | ||
| 18 | + // http/1.0 is not defined as Protocol IDs in IANA | ||
| 19 | + // http://www.iana.org/assignments/tls-extensiontype-values | ||
| 20 | + // /tls-extensiontype-values.xhtml#alpn-protocol-ids | ||
| 21 | + opts.ALPNProtocols = ['http/1.1']; | ||
| 22 | + } | ||
| 23 | + | ||
| 17 | 24 | tls.Server.call(this, opts, http._connectionListener); | |
| 18 | 25 | ||
| 19 | 26 | this.httpAllowHalfOpen = false; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -33,27 +33,42 @@ exports.getCiphers = function() { | |||
| 33 | 33 | ||
| 34 | 34 | // Convert protocols array into valid OpenSSL protocols list | |
| 35 | 35 | // ("\x06spdy/2\x08http/1.1\x08http/1.0") | |
| 36 | - exports.convertNPNProtocols = function convertNPNProtocols(NPNProtocols, out) { | ||
| 37 | - // If NPNProtocols is Array - translate it into buffer | ||
| 38 | - if (Array.isArray(NPNProtocols)) { | ||
| 39 | - var buff = new Buffer(NPNProtocols.reduce(function(p, c) { | ||
| 40 | - return p + 1 + Buffer.byteLength(c); | ||
| 41 | - }, 0)); | ||
| 42 | - | ||
| 43 | - NPNProtocols.reduce(function(offset, c) { | ||
| 44 | - var clen = Buffer.byteLength(c); | ||
| 45 | - buff[offset] = clen; | ||
| 46 | - buff.write(c, offset + 1); | ||
| 47 | - | ||
| 48 | - return offset + 1 + clen; | ||
| 49 | - }, 0); | ||
| 50 | - | ||
| 51 | - NPNProtocols = buff; | ||
| 36 | + function convertProtocols(protocols) { | ||
| 37 | + var buff = new Buffer(protocols.reduce(function(p, c) { | ||
| 38 | + return p + 1 + Buffer.byteLength(c); | ||
| 39 | + }, 0)); | ||
| 40 | + | ||
| 41 | + protocols.reduce(function(offset, c) { | ||
| 42 | + var clen = Buffer.byteLength(c); | ||
| 43 | + buff[offset] = clen; | ||
| 44 | + buff.write(c, offset + 1); | ||
| 45 | + | ||
| 46 | + return offset + 1 + clen; | ||
| 47 | + }, 0); | ||
| 48 | + | ||
| 49 | + return buff; | ||
| 50 | + }; | ||
| 51 | + | ||
| 52 | + exports.convertNPNProtocols = function(protocols, out) { | ||
| 53 | + // If protocols is Array - translate it into buffer | ||
| 54 | + if (Array.isArray(protocols)) { | ||
| 55 | + protocols = convertProtocols(protocols); | ||
| 52 | 56 | } | |
| 57 | + // If it's already a Buffer - store it | ||
| 58 | + if (protocols instanceof Buffer) { | ||
| 59 | + out.NPNProtocols = protocols; | ||
| 60 | + } | ||
| 61 | + }; | ||
| 53 | 62 | ||
| 63 | + exports.convertALPNProtocols = function(protocols, out) { | ||
| 64 | + // If protocols is Array - translate it into buffer | ||
| 65 | + if (Array.isArray(protocols)) { | ||
| 66 | + protocols = convertProtocols(protocols); | ||
| 67 | + } | ||
| 54 | 68 | // If it's already a Buffer - store it | |
| 55 | - if (NPNProtocols instanceof Buffer) { | ||
| 56 | - out.NPNProtocols = NPNProtocols; | ||
| 69 | + if (protocols instanceof Buffer) { | ||
| 70 | + // copy new buffer not to be modified by user | ||
| 71 | + out.ALPNProtocols = new Buffer(protocols); | ||
| 57 | 72 | } | |
| 58 | 73 | }; | |
| 59 | 74 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -42,6 +42,7 @@ namespace node { | |||
| 42 | 42 | // for the sake of convenience. Strings should be ASCII-only. | |
| 43 | 43 | #define PER_ISOLATE_STRING_PROPERTIES(V) \ | |
| 44 | 44 | V(address_string, "address") \ | |
| 45 | + V(alpn_buffer_string, "alpnBuffer") \ | ||
| 45 | 46 | V(args_string, "args") \ | |
| 46 | 47 | V(argv_string, "argv") \ | |
| 47 | 48 | V(arrow_message_string, "arrowMessage") \ | |
@@ -205,6 +206,7 @@ namespace node { | |||
| 205 | 206 | V(timestamp_string, "timestamp") \ | |
| 206 | 207 | V(title_string, "title") \ | |
| 207 | 208 | V(tls_npn_string, "tls_npn") \ | |
| 209 | + V(tls_alpn_string, "tls_alpn") \ | ||
| 208 | 210 | V(tls_ocsp_string, "tls_ocsp") \ | |
| 209 | 211 | V(tls_sni_string, "tls_sni") \ | |
| 210 | 212 | V(tls_string, "tls") \ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2582,6 +2582,13 @@ static Local<Object> GetFeatures(Environment* env) { | |||
| 2582 | 2582 | #endif | |
| 2583 | 2583 | obj->Set(env->tls_npn_string(), tls_npn); | |
| 2584 | 2584 | ||
| 2585 | + #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation | ||
| 2586 | + Local<Boolean> tls_alpn = True(env->isolate()); | ||
| 2587 | + #else | ||
| 2588 | + Local<Boolean> tls_alpn = False(env->isolate()); | ||
| 2589 | + #endif | ||
| 2590 | + obj->Set(env->tls_alpn_string(), tls_alpn); | ||
| 2591 | + | ||
| 2585 | 2592 | #ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB | |
| 2586 | 2593 | Local<Boolean> tls_sni = True(env->isolate()); | |
| 2587 | 2594 | #else | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -935,6 +935,11 @@ void DefineOpenSSLConstants(Local<Object> target) { | |||
| 935 | 935 | NODE_DEFINE_CONSTANT(target, NPN_ENABLED); | |
| 936 | 936 | #endif | |
| 937 | 937 | ||
| 938 | + #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation | ||
| 939 | + #define ALPN_ENABLED 1 | ||
| 940 | + NODE_DEFINE_CONSTANT(target, ALPN_ENABLED); | ||
| 941 | + #endif | ||
| 942 | + | ||
| 938 | 943 | #ifdef RSA_PKCS1_PADDING | |
| 939 | 944 | NODE_DEFINE_CONSTANT(target, RSA_PKCS1_PADDING); | |
| 940 | 945 | #endif | |
| Back | FazBrowse Home | New Git URL |
0 commit comments