Repository navigation
Cannot read property 'getALPNNegotiatedProtocol' of null #24658
Description
Activity
@indutny @nodejs/http @nodejs/crypto
Adding
options.caequal to the same thing asoptions.certalso fixes it... According to the docs:"For self-signed certificates, the certificate is its own CA, and must be provided."
So I guess it makes sense that it was failing, but it would be nice to fail when I'm creating the server, not during connection handling, and with a more sensible error message.
Thanks :)- addedtlsIssues and PRs related to the tls subsystem.Issues and PRs related to the tls subsystem.httpsIssues and PRs related to the https subsystem.Issues and PRs related to the https subsystem.
on Nov 26, 2018 Are you getting that exception on the server side or the client side (i.e., when trying to connect to the server you started)?
As to the exception itself, it looks like the connection is already dead (and
this._handle === null) by the time the onhandshakedone callback is invoked.Should be easy to fix with an
if (this._handle === null) return;guard.it would be nice to fail when I'm creating the server
Probably hard to do because there are combinations of options where that condition isn't an error.
With the guard in place, you should get a
'tlsClientError'event on the server instance.The exception is on the server side
@petoknm Your example code lacks a client. I added one, see below, and cannot reproduce. Could you provide a complete example?
const https = require('https'); const fs = require('fs'); // Some valid paths to CA files const crtPath = process.env.CA_CERT_PATH || "server.crt"; const keyPath = process.env.CA_CERT_KEY || "server.key"; const options = { key: fs.readFileSync(keyPath), cert: fs.readFileSync(crtPath), requestCert: true, }; https.createServer(options, (req, res) => { res.writeHead(200); res.end("hello world\n"); }).listen(0) .on('listening', function() { const port = this.address().port; console.log('server on port', port); console.log('node version', process.versions.node); https.get({ key: fs.readFileSync(keyPath), cert: fs.readFileSync(crtPath), port, }).on('error', (err) => { console.error('client err', err); }); }) .on('tlsClientError', (err) => { console.error('server tlsClientError:', err); }) ;Output, as expected the server resets the connection because it can't find a trusted CA for the client.
server on port 37479 node version 11.2.0 server tlsClientError: { Error: socket hang up at TLSSocket.onSocketClose (_tls_wrap.js:737:23) at TLSSocket.emit (events.js:187:15) at _handle.close (net.js:616:12) at Socket.done (_tls_wrap.js:384:7) at Object.onceWrapper (events.js:273:13) at Socket.emit (events.js:182:13) at TCP._handle.close (net.js:616:12) code: 'ECONNRESET' } client err { Error: Client network socket disconnected before secure TLS connection was established at TLSSocket.onConnectEnd (_tls_wrap.js:1159:19) at Object.onceWrapper (events.js:273:13) at TLSSocket.emit (events.js:187:15) at endReadableNT (_stream_readable.js:1098:12) at process.internalTickCallback (internal/process/next_tick.js:72:19) code: 'ECONNRESET', path: null, host: 'localhost', port: 37479, localAddress: undefined }Well, I cant exactly reproduce it using
https.request(), but I can with the following code and a curl command:code:
const https = require('https'); const fs = require('fs'); const options = { cert: fs.readFileSync('server.crt'), key: fs.readFileSync('server.key'), requestCert: true }; const server = https.createServer(options, (req, res) => { res.writeHead(200); res.end("hello world\n"); }); server.listen(8443); server.on('listening', () => { const port = server.address().port; console.log('server on port', port); console.log('node version', process.versions.node); }); server.on('tlsClientError', (err) => { console.error('server tlsClientError:', err); });request:
$ curl https://localhost:8443/ -kv -E client.crt.pem --key client.key.pem * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Request CERT (13): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, [no content] (0): * TLSv1.3 (OUT), TLS handshake, Certificate (11): * TLSv1.3 (OUT), TLS handshake, [no content] (0): * TLSv1.3 (OUT), TLS handshake, CERT verify (15): * TLSv1.3 (OUT), TLS handshake, [no content] (0): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: [redacted] * SSL certificate verify result: self signed certificate (18), continuing anyway. * TLSv1.3 (OUT), TLS app data, [no content] (0): > GET / HTTP/1.1 > Host: localhost:8443 > User-Agent: curl/7.62.0 > Accept: */* > * OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 104 * Closing connection 0 * TLSv1.3 (OUT), TLS alert, [no content] (0): curl: (56) OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 104output:
$ node app.js server on port 8443 node version 11.2.0 _tls_wrap.js:620 this.alpnProtocol = this._handle.getALPNNegotiatedProtocol(); ^ TypeError: Cannot read property 'getALPNNegotiatedProtocol' of null at TLSSocket._finishInit (_tls_wrap.js:620:36) at TLSWrap.onhandshakedone (_tls_wrap.js:101:9)Upgraded to 11.3.0, issue still remains, even after PR #18987
After some investigation I'm reasonably sure it's caused by the use of TLSv1.3. Can you check whether it works for you when you add
--tlsv1.2to the curl command?Indeed, using TLSv1.2 seems fine
$ curl https://localhost:8443/ --tls-max 1.2 -kv -E server.crt --key server.key * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt CApath: none * TLSv1.2 (OUT), TLS handshake, Client hello (1): * TLSv1.2 (IN), TLS handshake, Server hello (2): * TLSv1.2 (IN), TLS handshake, Certificate (11): * TLSv1.2 (IN), TLS handshake, Server key exchange (12): * TLSv1.2 (IN), TLS handshake, Request CERT (13): * TLSv1.2 (IN), TLS handshake, Server finished (14): * TLSv1.2 (OUT), TLS handshake, Certificate (11): * TLSv1.2 (OUT), TLS handshake, Client key exchange (16): * TLSv1.2 (OUT), TLS handshake, CERT verify (15): * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.2 (OUT), TLS handshake, Finished (20): * OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:8443 * Closing connection 0 curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to localhost:8443$ node app.js server on port 8443 node version 11.3.0 server tlsClientError: { Error: socket hang up at TLSSocket.onSocketClose (_tls_wrap.js:737:23) at TLSSocket.emit (events.js:187:15) at _handle.close (net.js:616:12) at Socket.done (_tls_wrap.js:384:7) at Object.onceWrapper (events.js:273:13) at Socket.emit (events.js:182:13) at TCP._handle.close (net.js:616:12) code: 'ECONNRESET' }- TLSv1.3 (IN), TLS handshake, Server hello (2):
This is very strange because the node TLS server returns TLS1.3 ServerHello. We have not supported OpenSSL-1.1.1 and TLS1.3 yet.
@petknm Are you using Node.js built with openssl shared library of OpenSSL-1.1.1? Please give us the output result of
process.versions.openssl.> process.versions.openssl '1.1.1'I'm running node from the arch linux packages, so the configuration and build arguments are in this PKGBUILD file: https://git.archlinux.org/svntogit/community.git/tree/trunk/PKGBUILD?h=packages/nodejs&id=27476317f60e8e7a74aba2107fd9dbcd14a64257
@petoknm Can you report to Arch that openssl 1.1.1 is not similar enough to openssl 1.1.0 to be a drop-in replacement, at least not for Node.js?
At least, not unless we do #25024, pulled from work on getting 1.1.1 support, see #18770 and sam-github@0b140c2 from https://github.com/sam-github/node/tree/update_openssl1.1.1a
- added a commit that references this issue
on Dec 17, 2018 - added a commit that references this issue
on Dec 25, 2018 - added a commit that references this issue
on Jan 14, 2019 - added a commit that references this issue
on Feb 12, 2019 - added a commit that references this issue
on Feb 20, 2019 - added a commit that references this issue
on Feb 28, 2019 - added a commit that references this issue
on Jul 27, 2026
Version:
v11.2.0Platform:
Linux xps15 4.19.2-arch1-1-ARCH #1 SMP PREEMPT Tue Nov 13 21:16:19 UTC 2018 x86_64 GNU/LinuxSubsystem:
https, tlsI am trying to get https client certificate authentication to work but I get the following error:
code:
when I set
requestCert: falsein the options it works fine, but I need the client to present a certificate, thus need therequestCert: true.Edit:
Adding
rejectUnauthorized: falsemakes it work. But I still think that it should not throw an error when rejecting unauthorized clients.