Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update doc/api/cli.md, add cipher DEFAULT@SECLEVEL=0 for TLSv1 #49236

Closed
wants to merge 0 commits into from

Conversation

afanasy
Copy link
Contributor

@afanasy afanasy commented Aug 19, 2023

Updated docs: for TLSv1 server to work you need to pass both --tls-min-v1.0 and --tls-cipher-list=DEFAULT@SECLEVEL=0 (same for TLSv1.1).

@nodejs-github-bot nodejs-github-bot added cli Issues and PRs related to the Node.js command line interface. doc Issues and PRs related to the documentations. labels Aug 19, 2023
@aduh95
Copy link
Contributor

aduh95 commented May 12, 2024

/cc @nodejs/crypto for reviews

Copy link
Member

@pimterry pimterry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I understand it, yes this is indeed required for any kind of TLSv1 support with modern OpenSSL. This definitely makes sense in that context, and it's useful important info for people who need this.

That said, I don't think we should recommend this without a bit more context so people know what it means. Since setting SECLEVEL=0 reduces all sorts of other TLS constraints too. I'd suggest we:

  • Briefly explain the consequences of this directly: basically it lowers the OpenSSL security level to 0, which can be useful for compatibility but allows also sorts of ciphers, small key sizes and other configurations that may be insecure in a modern environment.
  • Link to https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_security_level.html for more information.
  • Include this same info in the main TLS docs somewhere too.

I'd suggest we put that main explanation in the TLS docs somewhere, and then just link to that from here ("This may significantly reduce TLS security - see ... for more information").

Assuming that setting the same option at runtime with TLS APIs directly also works (i.e. using ciphers: ... as a context option), we should also probably recommend doing that instead where possible. For most applications it's significantly safer to lower the security level only for the specific operations that need it, rather than lowering it globally.

@afanasy
Copy link
Contributor Author

afanasy commented May 13, 2024

@pimterry Thanks for the detailed review! I agree that --tls-cipher-list=DEFAULT@SECLEVEL=0 looks like an overkill, but I haven't found the way to do it with just ciphers: ... or any other js calls options.

@pimterry
Copy link
Member

I agree that --tls-cipher-list=DEFAULT@SECLEVEL=0 looks like an overkill, but I haven't found the way to do it with just ciphers: ... or any other js calls options.

I've done a quick bit of testing, this seems to work correctly:

tls.connect({
  host: 'tls-v1-0.badssl.com',
  port: 1010,
  ciphers: 'DEFAULT@SECLEVEL=0',
  minVersion: 'TLSv1'
}).on('error', (e) => console.log(e.message))

The ciphers option effectively the same as the CLI option you suggest, but on a per-context basis rather than modifying the global default.

Testing in Node v20.11.1 on my machine, without the cipher & minVersion option this fails with unsupported protocol and/or signature algorithm errors, but with those options it works (prints 'certificate is expired' annoyingly, because this test server is not well maintained, but I think that's unrelated). Can you test that in your setup? Assuming that does work, I think we should probably nudge people in this direction as a first solution, rather than reducing the process-wide security level.

@afanasy
Copy link
Contributor Author

afanasy commented May 16, 2024

@pimterry Thank you for the code sample! I see you are trying to tune tsl.connect, however it is the server part that is broken, not the client. Check this:

// Node.js v20.11.1
// seems like adding '--tls-min-v1.0' doesn't affect anything

var execSync = require('child_process').execSync
var fs = require('fs')
var tls = require('tls')
var port = 8000
var minVersion = 'TLSv1'
var maxVersion = 'TLSv1' // doesn't work
// var maxVersion = 'TLSv1.2' // works
// var maxVersion = 'TLSv1.3' // works

execSync('openssl req -x509 -newkey rsa:1024 -keyout key -out cert -nodes -subj "/C=US/CN=localhost"')

var key = fs.readFileSync('key')
var cert = fs.readFileSync('cert')

tls.createServer({key, cert, ciphers: 'DEFAULT@SECLEVEL=0', minVersion}, function (socket) {
  console.log('it works!', socket.getProtocol())
  socket.end()
  this.close()
}).
listen(port, () => {
  tls.connect(port, {ca: [cert], minVersion, maxVersion})
})

@pimterry
Copy link
Member

I see you are trying to tune tsl.connect, however it is the server part that is broken, not the client.

Yes, the same does apply to the server side, but both can use the same runtime-option solution.

In your example, you've used the ciphers option to change the seclevel on the server, but not the client. In cases like this, both are required (as both client & server are using OpenSSL v3 for TLS, and will both independently reject use of TLSv1 unless their security level is lowered). The --tls-min-v1.0 and --tls-cipher-list options are just setting the default minVersion and ciphers options everywhere, and the reason they work here in your example is because they are applied to both server & client connections automatically.

To fix this, if you add the ciphers: 'DEFAULT@SECLEVEL=0' option to the tls.connect options in your code as well, it'll print "it works! TLSv1" without any command line arguments required.

Does that make sense?

@afanasy
Copy link
Contributor Author

afanasy commented May 16, 2024

@pimterry Now it all makes sense, thanks! I didn't know tls.connect is restricted by the same ciphers option.
This works:

// Node.js v20.11.1

var execSync = require('child_process').execSync
var fs = require('fs')
var tls = require('tls')
var port = 8000
var minVersion = 'TLSv1'
var maxVersion = 'TLSv1'

execSync('openssl req -x509 -newkey rsa:1024 -keyout key -out cert -nodes -subj "/C=US/CN=localhost"')

var key = fs.readFileSync('key')
var cert = fs.readFileSync('cert')

tls.createServer({key, cert, ciphers: 'DEFAULT@SECLEVEL=0', minVersion}, function (socket) {
  console.log('it works!', socket.getProtocol())
  socket.end()
  this.close()
}).
listen(port, () => {
  tls.connect(port, {ca: [cert], ciphers: 'DEFAULT@SECLEVEL=0', minVersion, maxVersion})
})

At this point I think the best would be to mention ciphers: 'DEFAULT@SECLEVEL=0' somewhere in the main TLS docs, probably where the TLSv1 is mentioned, so it is more clear how to enable TLSv1 support. I don't think it makes sense to amend cli option docs then. What do you think?

@pimterry
Copy link
Member

At this point I think the best would be to mention ciphers: 'DEFAULT@SECLEVEL=0' somewhere in the main TLS docs, probably where the TLSv1 is mentioned, so it is more clear how to enable TLSv1 support. I don't think it makes sense to amend cli option docs then. What do you think?

Yes that sounds great. How about:

  • Creating a general section somewhere near the top of the TLS docs for "OpenSSL Security Level", which:
    • Links to https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_security_level.html#DEFAULT-CALLBACK-BEHAVIOUR for context
    • Explains that you'll need SECLEVEL=0 to use some legacy features like TLSv1 etc
    • Explains that including @SECLEVEL=X within a cipher string sets the level, and that DEFAULT@SECLEVEL=X can do this while also using the default OpenSSL ciphers list.
    • Links to the existing "Modifying the default TLS cipher suite" section for how to actually do that, but recommends only downgrading security level for individual contexts with ciphers where possible, rather than doing it globally.
  • Referencing (just something like versions before TLSv1.2 may require [downgrading the OpenSSL security level](link)) anywhere we directly mention ways to lower the minimum level - I think that's the minVersion in the TLS context options, tls.DEFAULT_MIN_VERSION, and --tls-min-version. Anywhere else you can see would be good too though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cli Issues and PRs related to the Node.js command line interface. doc Issues and PRs related to the documentations.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants