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

tls: support changing credentials dynamically #23644

Merged
merged 1 commit into from
Oct 21, 2018

Conversation

cjihrig
Copy link
Contributor

@cjihrig cjihrig commented Oct 13, 2018

This commit adds a setSecureContext() method to TLS servers. In order to maintain backwards compatibility, the method takes the options needed to create a new SecureContext, rather than an instance of SecureContext.

Fixes: #4464
Refs: #10349
Refs: nodejs/help#603
Refs: #15115

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

Green CI: https://ci.nodejs.org/job/node-test-pull-request/17941/

@nodejs-github-bot nodejs-github-bot added the tls Issues and PRs related to the tls subsystem. label Oct 13, 2018
@vsemozhetbyt vsemozhetbyt added the semver-minor PRs that contain new features and should be released in the next minor version. label Oct 13, 2018
.update(process.argv.join(' '))
.digest('hex')
.slice(0, 32);
}
Copy link
Member

Choose a reason for hiding this comment

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

Can't you call this.setOptions(options)?

Copy link
Contributor Author

@cjihrig cjihrig Oct 15, 2018

Choose a reason for hiding this comment

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

I did that originally, but setOptions() doesn't unset values that might have been passed on the first call, but omitted on subsequent calls. I also didn't want to change the behavior of setOptions().

EDIT: I guess one option would be to call setOptions() to set the options, and leave the undefined assignments in this function to clear old values.
EDIT2: Actually, setOptions() sets values unrelated to the secure context (requestCert, rejectUnauthorized, etc.), so I think I'd prefer to not call it from setSecureContext().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bnoordhuis long term, I'd prefer to deprecate/remove setOptions() because it's undocumented and only used in the tls server constructor. The few fields that don't overlap with setSecureContext() could be inlined in the constructor.

this.ticketKeys = options.ticketKeys;
this.setTicketKeys(this.ticketKeys);
} else {
this.setTicketKeys(this.getTicketKeys());
Copy link
Member

Choose a reason for hiding this comment

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

For my understanding: that means there is no way to disable ticket keys using .setSecureContext() if they've been enabled before?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was trying to focus on maintaining any keys that were already set, and figured the {set,get}TicketKeys() APIs could be used for any additional configuration.

Copy link
Contributor

Choose a reason for hiding this comment

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

@cjihrig I'm somehow not understanding this code. get returns a buffer with the wrap->ticket_key_ data, and set copies its buffer argument into the wrap->ticket_key_ data... making this a no-op AFAICT. What am I missing? If the previous value of _sharedCreds (if any) had been saved, and that was used for the get, then I would understand @bnoordhuis's comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sam-github I think it is just a mistake on my part. I just ran the test suite locally with that line commented out and everything passed.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, thanks for looking into it. I'm doing some session/ticket work, I'll remove the code in that PR, unless you want to.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If you want to include it in #25713, I think that would be fine.

doc/api/tls.md Outdated
`ca`, etc).

The `server.setSecureContext()` method replaces the secure context of an
existing server.
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the effect on current connections? Will those that have completed handshaking continue to be valid?

Copy link
Contributor Author

@cjihrig cjihrig Oct 16, 2018

Choose a reason for hiding this comment

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

@sam-github existing connections should not be impacted. I've updated the docs to specify this, and updated the tests to validate it.

if (options.pfx)
this.pfx = options.pfx;
else
this.pfx = undefined;
Copy link
Member

@jasnell jasnell Oct 16, 2018

Choose a reason for hiding this comment

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

It could get a bit messy with so many options, but the following pattern may save a bit of boilerplate code in this method...

Server.prototype.setSecureContext = function({
  pfx = undefined,
  key = undefined,
  passphrase = undefined,
  cert = undefined,
  clientCertEngine = undefined,
  ca = undefined,
  secureProtocol = undefined,
  crl = undefined,
  ciphers = undefined,
  ecdhCurve = undefined,
  dhparam = undefined,
  honorCipherOrder = false,
  secureOptions,
  sessionIdContext
} = {}) {
  this.pfx = pfx;
  this.key = key;
  // ...
}

Not sure it's actually that much better tho ;-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jasnell I like that pattern, because I think it would be helpful for code coverage purposes. But I'm a little worried that it's just slightly different enough from the existing options handling (setOptions()) to cause problems. For example, right now falsy values get filtered out in most cases, but that would no longer be the case. The current structure also allows us to make the validation stricter, because right now it seems rather loose.

I already plan to follow this up with a deprecation PR for setOptions(). I'd like to also revisit the argument validation here, but that will be semver-major.

This commit adds a setSecureContext() method to TLS servers. In
order to maintain backwards compatibility, the method takes the
options needed to create a new SecureContext, rather than an
instance of SecureContext.

Fixes: nodejs#4464
Refs: nodejs#10349
Refs: nodejs/help#603
Refs: nodejs#15115
PR-URL: nodejs#23644
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@cjihrig cjihrig merged commit 96a986d into nodejs:master Oct 21, 2018
@cjihrig cjihrig deleted the swap-credentials branch October 21, 2018 13:37
@targos
Copy link
Member

targos commented Oct 21, 2018

It looks like the new test test-tls-set-secure-context is flaky (timeouts): https://ci.nodejs.org/job/node-test-pull-request/18030/

jasnell pushed a commit that referenced this pull request Oct 21, 2018
This commit adds a setSecureContext() method to TLS servers. In
order to maintain backwards compatibility, the method takes the
options needed to create a new SecureContext, rather than an
instance of SecureContext.

Fixes: #4464
Refs: #10349
Refs: nodejs/help#603
Refs: #15115
PR-URL: #23644
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
@coolaj86
Copy link
Contributor

coolaj86 commented Dec 22, 2018

Would it be reasonable to allow setSecureContext() to take an object created by createSecureContext()?

Either:

server.setSecureContext(secureContext);

Or:

server.setSecureContext({ secureContext: secureContext });

@sam-github
Copy link
Contributor

sam-github commented Apr 26, 2019

Backported in #27432, to reduce TLS1.3 conflicts. PTAL if I did it correctly.

EDIT: I had to add min/maxversion back into the options (I guess due to out-of-order landing of features), and to remove a semver-major SNICallback type check.

sam-github pushed a commit to sam-github/node that referenced this pull request Apr 29, 2019
This commit adds a setSecureContext() method to TLS servers. In
order to maintain backwards compatibility, the method takes the
options needed to create a new SecureContext, rather than an
instance of SecureContext.

Fixes: nodejs#4464
Refs: nodejs#10349
Refs: nodejs/help#603
Refs: nodejs#15115
PR-URL: nodejs#23644
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-minor PRs that contain new features and should be released in the next minor version. tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

https server should allow changing credentials dynamically
9 participants