镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Cannot read property 'getALPNNegotiatedProtocol' of null #24658

Description

@petoknm

Version: v11.2.0
Platform: Linux xps15 4.19.2-arch1-1-ARCH #1 SMP PREEMPT Tue Nov 13 21:16:19 UTC 2018 x86_64 GNU/Linux
Subsystem: https, tls

I am trying to get https client certificate authentication to work but I get the following error:

_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)

code:

const https = require('https');
const fs = require('fs');

// Some valid paths to CA files
const crtPath = process.env.CA_CERT_PATH || "/var/run/secrets/certs/ca.crt";
const keyPath = process.env.CA_CERT_KEY || "/var/run/secrets/certs/ca.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(8443);

when I set requestCert: false in the options it works fine, but I need the client to present a certificate, thus need the requestCert: true.

Edit:
Adding rejectUnauthorized: false makes it work. But I still think that it should not throw an error when rejecting unauthorized clients.

Activity

  1. Trott commented on Nov 26, 2018

    @Trott
    Member

    @indutny @nodejs/http @nodejs/crypto

  2. petoknm commented on Nov 26, 2018

    @petoknm
    Author

    Adding options.ca equal to the same thing as options.cert also 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 :)

  3. added
    tlsIssues and PRs related to the tls subsystem.
    httpsIssues and PRs related to the https subsystem.
    on Nov 26, 2018
  4. bnoordhuis commented on Nov 27, 2018

    @bnoordhuis
    Member

    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.

  5. petoknm commented on Nov 27, 2018

    @petoknm
    Author

    The exception is on the server side

  6. sam-github commented on Nov 27, 2018

    @sam-github
    Contributor

    @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 }
    
  7. petoknm commented on Nov 28, 2018

    @petoknm
    Author

    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 104
    

    output:

    $ 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)
    
  8. petoknm commented on Nov 28, 2018

    @petoknm
    Author

    Upgraded to 11.3.0, issue still remains, even after PR #18987

  9. bnoordhuis commented on Dec 11, 2018

    @bnoordhuis
    Member

    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.2 to the curl command?

  10. petoknm commented on Dec 11, 2018

    @petoknm
    Author

    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' }
    
  11. shigeki commented on Dec 12, 2018

    @shigeki
    Contributor
    • 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.

  12. petoknm commented on Dec 13, 2018

    @petoknm
    Author
    > 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

  13. sam-github commented on Dec 13, 2018

    @sam-github
    Contributor

    @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

  14. added a commit that references this issue on Oct 22, 2020
  15. added a commit that references this issue on Jul 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    httpsIssues and PRs related to the https subsystem.tlsIssues and PRs related to the tls subsystem.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions