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

tls.connect Error: self signed certificate when connect to imap.gmail.com:933 #28167

Description

@CoNETProject
  • Version: v12.0.0 ~ v12.4.0 (Old ~ v11.15.0 have no same issue )
  • Platform: MacOS, Debian, Windows
  • Subsystem: no
  • Module (and version) (if relevant): tls.connect(options[, callback])

Error: self signed certificate

When?
looks happened connect to imap.gmail.com:933 only.

imap.mail.me.com have no same issue.

//	This only happen at v12.0.0 ~ v12.4.0 (Old version ~ v11.15.0 have no same issue )

const socket = tls.connect (993, 'imap.gmail.com', () => {
	...
)
socket.on('error', err => {
	// Will ERROR!
	// Error: self signed certificate
	...
})
//	Apple mail have no same problem
const socket = tls.connect (993, 'imap.mail.me.com', () => {
	...
)
socket.on('error', err => {
	...
})

I checked tls connect with openssl command to imap.gmail.com at same OS, looks Good. It have not Man-in-the-middle attack OS. The code have no problem when I back NodeJS to v11.

Activity

  1. added
    tlsIssues and PRs related to the tls subsystem.
    on Jun 11, 2019
  2. addaleax commented on Jun 11, 2019

    @addaleax
    Member

    @nodejs/crypto

  3. bnoordhuis commented on Jun 11, 2019

    @bnoordhuis
    Member

    The issue is that Node.js (no longer?) sends a SNI record by default. You can work around it like this:

    const options = {
      port: 993,
      host: 'imap.gmail.com',
      servername: 'imap.gmail.com',  // SNI
    };
    tls.connect(options, () => { /* ... */ });

    It might have been caused by an openssl upgrade because I can reproduce with out/Release/openssl-cli, that also won't validate unless you pass -servername imap.gmail.com.

    (GMail helpfully sends back a certificate with Issuer: OU = "No SNI provided; please fix your client.", CN = invalid2.invalid ^^)

  4. CoNETProject commented on Jun 11, 2019

    @CoNETProject
    Author

    Thank you.
    Looks have no problem now via use both host and servername.

  5. silverwind commented on Jun 11, 2019

    @silverwind
    Contributor

    I can reproduce with out/Release/openssl-cli

    Sending SNI on the openssl CLI was always opt-in via -servername, so that's probably not related.

  6. sam-github commented on Jun 11, 2019

    @sam-github
    Contributor

    This might be a bug. 11.x and 12.x have the same OpenSSL version, but different behaviour, so it looks like something changed in node, not in openssl:

    w/core % cat imap.gmail.js
    console.log(process.versions.openssl);
    require('tls').connect(993, 'imap.gmail.com', function() {
      console.log('CONNECT');
      this.end();
    });
    w/core % nvm run 11 imap.gmail.js
    Running node v11.15.0 (npm v6.7.0)
    1.1.1b
    CONNECT
    w/core % nvm run 12 imap.gmail.js
    Running node v12.4.0 (npm v6.9.0)
    1.1.1b
    events.js:177
          throw er; // Unhandled 'error' event
          ^
    
    Error: self signed certificate
        at TLSSocket.onConnectSecure (_tls_wrap.js:1317:34)
        at TLSSocket.emit (events.js:200:13)
        at TLSSocket._finishInit (_tls_wrap.js:792:8)
        at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:606:12)
    Emitted 'error' event at:
        at emitErrorNT (internal/streams/destroy.js:91:8)
        at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
        at processTicksAndRejections (internal/process/task_queues.js:84:9) {
      code: 'DEPTH_ZERO_SELF_SIGNED_CERT'
    }
    
  7. sam-github commented on Jun 11, 2019

    @sam-github
    Contributor

    I'm bisecting, maybe I can pinpoint a specific change.

  8. bnoordhuis commented on Jun 11, 2019

    @bnoordhuis
    Member

    Sending SNI on the openssl CLI was always opt-in via -servername, so that's probably not related.

    The reason I mention it is that the stock openssl s_client on my system works without -servername.

  9. silverwind commented on Jun 11, 2019

    @silverwind
    Contributor

    openssl s_client on my system works without -servername

    We're offtopic but it's because it was changed in 1.1.1 as per this changelog entry:

    s_client will now send the Server Name Indication (SNI) extension by
    default unless the new "-noservername" option is used. The server name is
    based on the host provided to the "-connect" option unless overridden by
    using "-servername".

  10. sam-github commented on Jun 12, 2019

    @sam-github
    Contributor

    bisect pointed to 42dbaed, my commit to add TLS1.3 support, and indeed it works with TLS1.2:

    core/lts (master $% u=) % ./out/Release/node --tls-max-v1.3 ../imap.gmail.js
    1.1.1b
    events.js:177
          throw er; // Unhandled 'error' event
          ^
    
    Error: self signed certificate
        at TLSSocket.onConnectSecure (_tls_wrap.js:1317:34)
        at TLSSocket.emit (events.js:200:13)
        at TLSSocket._finishInit (_tls_wrap.js:792:8)
        at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:606:12)
    Emitted 'error' event at:
        at emitErrorNT (internal/streams/destroy.js:91:8)
        at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
        at processTicksAndRejections (internal/process/task_queues.js:74:11) {
      code: 'DEPTH_ZERO_SELF_SIGNED_CERT'
    }
    core/lts (master $% u=) % ./out/Release/node --tls-max-v1.2 ../imap.gmail.js 
    1.1.1b
    CONNECT
    

    However, running with --trace-tls I see something strange: SNI is not sent for TLS1.2 or TLS1.3 (by default), but only for TLS1.3 is the server returning the bogus self-signed cert with Subject = Issuer = "No SNI provided; please fix your client.", CN = invalid2.invalid. If I add SNI, it does fix the TLS1.3 connect, but why? Is the SNI extension required for TLS1.3? Well, no, but it is by google's servers: openssl/openssl#5362 (comment)

    So, this is confirmed as a gmail bug.

    Possibly, tls.connect() should default servername: to host: (in the case that host is a name and not an IP address) as http.request() does, but that would be a breaking change.

    Thoughts?

    More discussion: https://mta.openssl.org/pipermail/openssl-project/2018-April/000623.html

  11. bnoordhuis commented on Jun 13, 2019

    @bnoordhuis
    Member

    I suppose GMail is technically in the right because the spec says that a server MAY require SNI and imap.gmail.com does....

    ...although it's "interesting" that it doesn't actually care what you set the servername to: it happily accepts -servername panopticon.bigbro. Can I suggest we add a special case for imap.gmail.com and send that servername? ^^

    We could turn on SNI by default although that leaks the servername because the SNI payload is unencrypted (and it'll be a while before ESNI is a thing.)

  12. silverwind commented on Jun 13, 2019

    @silverwind
    Contributor

    I guess we have to default to sending a SNI (and mimic what browsers do). It is indeed a data leak, but I guess more services will work with it present than without.

    BTW, I don't expect ESNI in the current draft form to get any widespread adoption because of it's complexity.

  13. sam-github commented on Jun 13, 2019

    @sam-github
    Contributor

    @silverwind We already mimic what browsers do by defaulting to sending SNI for https (see Agent.prototype.addRequest), so it is only direct use of tls that doesn't set servername. I'll PR a default use of servername to tls.connect (unless someone else beats me to it).

  14. 12 remaining items

  15. edmorley commented on Jun 12, 2020

    @edmorley

    but it is spec-compliant imo

    I'm not saying that tls.connect is not spec compliant per se, but that the "out of the box defaults" make it easy to accidentally write a non-spec-compliant client.

    This is the part I'm missing. Make what exactly the default, i.e. what is "it"?

    To hopefully clarify:

    • tls.connect does not enable SNI by default (presumably a combination of "because it never has since SNI is newish" + the privacy reasons mentioned above)
    • for TLS 1.2 and older, this is not normally a problem, however the TLS 1.3 spec says that clients MUST enable SNI
    • whilst the end user is ultimately responsible for writing a client to correctly meet the spec, and tls.connect is ultimately a pretty low-level API, from an API user-experience point of view it still seems best to have the tls.connect defaults match the requirements of the spec
    • ie instead of documenting that users should enable SNI (by setting servername to the same value as host) manually, tls.connect could do so by default iff host is not an IP and the protocol is TLS 1.3

    Anyway happy to let others make the judgement call on this :-)

  16. mildsunrise commented on Jun 12, 2020

    @mildsunrise
    Contributor

    Oh, TLSv1.3 mandates SNI? If you're referring to the paragraph where it says «In the absence of an application profile standard specifying otherwise, a TLS-compliant application MUST implement» like you said it's the application who's responsible of following spec (but yes, I agree that this is a valid reason for us to enable SNI by default).

    If we want to enable SNI by default, I'd vote we do it on all connections... doing it only for TLSv1.3 could be confusing, IMHO.

    Edit: The potential for breakage is small by itself, but as @bnoordhuis said we'll be suddenly leaking data and this could break applications that run behind an SNI-based firewall, for instance.

  17. edmorley commented on Jun 12, 2020

    @edmorley

    I'd vote we do it on all connections... doing it only for TLSv1.3 could be confusing, IMHO.

    I agree, I only mentioned that as a way to mitigate the privacy concerns for pre -TLSv1.3 use-cases, but (a) it would be confusing, (b) in those cases users could always disable it explicitly if desired I suppose.

  18. bnoordhuis commented on Jun 13, 2020

    @bnoordhuis
    Member

    RFC 8446 lists SNI in the mandatory-to-implement extensions section but nowhere does it seem to say TLSv1.3 clients MUST use SNI. SHOULD yes, MUST no.

    https://tools.ietf.org/html/rfc8446#section-4.4.2.2:

       -  The "server_name" [RFC6066] and "certificate_authorities"
          extensions are used to guide certificate selection.  As servers
          MAY require the presence of the "server_name" extension, clients
          SHOULD send this extension, when applicable.
    

    https://tools.ietf.org/html/rfc8446#section-9.2:

       Additionally, all implementations MUST support the use of the
       "server_name" extension with applications capable of using it.
       Servers MAY require clients to send a valid "server_name" extension.
       Servers requiring this extension SHOULD respond to a ClientHello
       lacking a "server_name" extension by terminating the connection with
       a "missing_extension" alert.
    

    (server_name = SNI)

  19. mildsunrise commented on Jun 22, 2020

    @mildsunrise
    Contributor

    Warning added! On whether to enable SNI by default, I'd recommend to open a PR or separate issue to continue discussion there

  20. added a commit that references this issue on Jan 14, 2022
  21. added a commit that references this issue on Jan 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

    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