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

Proposed extension to https.request to allow using a custom OpenSSL client certificate engine. #6145

Closed
joelostrowski opened this issue Apr 11, 2016 · 14 comments
Labels
feature request Issues that request new features to be added to Node.js. openssl Issues and PRs related to the OpenSSL dependency. tls Issues and PRs related to the tls subsystem.

Comments

@joelostrowski
Copy link
Contributor

  • Version: 6.0.0
  • Platform: All
  • Subsystem: HTTPS

I am lacking a way to access the SSL_CTX_set_client_cert_engine function in OpenSSL when doing https requests. I think this functionality would be useful to others which is why I am posting here as a feature request?

Perhaps the interface could look something like this:

var options =
{
    host: 'www.host.com',
    port: 443,
    method: 'GET',
    path: '/sensitive/data.action',
    clientCertEngine: 'credsmgr',       // my custom SSL client certificate engine
    agent: false,
    headers: {}
};
https.request(options, function(c) {/*etc*/});

It shouldn't be a big thing to incorporate - I can provide a patch if needed? Obviously there would need to be some kind of consensus on the extension... is "clientCertEngine" the right name for instance?

Thanks in advance for the consideration!

@mscdex mscdex added tls Issues and PRs related to the tls subsystem. feature request Issues that request new features to be added to Node.js. openssl Issues and PRs related to the OpenSSL dependency. labels Apr 11, 2016
@bnoordhuis
Copy link
Member

Providing glue for SSL_CTX_set_client_cert_engine() sounds reasonable to me but I think the approach would need to be lower level. Currently, when you call https.request(), this happens:

  1. https.request(options) calls tls.connect(options)
  2. tls.connect(options) calls tls.createSecureContext(options)
  3. tls.createSecureContext(options) calls new binding.NativeSecureContext() which ends up calling SecureContext::New() in src/node_crypto.cc.

I would suggest adding a new option to tls.createSecureContext() that configures the client certificate engine.

There is a gotcha: https.request() uses https.globalAgent unless instructed otherwise. The agent maintains a connection pool. You probably need to extend https.Agent#getName() to include the engine, if specified.

@joelostrowski
Copy link
Contributor Author

Got it!... so the https.js file needs to add the options.clientCertEngine value in getName(). And createSecureContext in _tls_common.js needs to add the clientCertEngine option and call some function on the context which should be implemented in node_crypto.cc (something like void SecureContext::SetClientCertEngine).

I am totally new to Node contributing - what to do next to realize this?

Thanks.

@bnoordhuis
Copy link
Member

You can find the steps in https://github.com/nodejs/node/blob/master/CONTRIBUTING.md - in a nutshell, make changes, add tests, run make test, open PR when everything passes. The commit log is important, too.

@joelostrowski
Copy link
Contributor Author

I have been looking into this a bit... I cannot find another test which actually builds something on the side (I would need to build a test engine as a .so/.dll file). I didn't see a test for crypto.setEngine either?
I can test here with the actual engine but it is not something that I can share.
Some advice on how to proceed would be appreciated?
p.s. Noordhuis - are you Dutch?

@bnoordhuis
Copy link
Member

You can probably jury-rig a new test in test/addons, one with two targets in its binding.gyp - one for the add-on and one for building the shared object ('type': 'shared_object'). Let me know if you want me to walk you through that.

And yes, I'm Dutch. =)

@joelostrowski
Copy link
Contributor Author

Ok so I am almost there. Did the changes, created a test in addons which builds a .so test engine and some js to test it. However I am not able to build a dll on windows - it builds a .exp and a .lib file. Suggestions for a way forward?

Thought the name sounded Dutch :-) My gf is Dutch but living with me in Denmark - we are going for King's day of course though!

@joelostrowski
Copy link
Contributor Author

I probably also need some 'if (common.isWindows)' in my test to use .dll as extension rather than .so. Alternatively load by name instead of absolute .so path and set the openssl load path environment var - however that has platform specific conventions so on linux I would need to create the file as "libtestengine.so" and "testengine.dll" on windows. I actually tried that but first of all setting 'target_name': 'libtestengine' did not do what I would expect - and at the end of the day that would have to switch on platform. Unless the build system would take care of these differences in conventions?

@joelostrowski
Copy link
Contributor Author

joelostrowski commented Apr 18, 2016

I was not getting a DLL because of build errors that I did not spot.
@bnoordhuis it would be much appreciated with a bit of support on building. I cannot really build the DLL on windows. I probably just got lucky when building the .so on Linux because I just added the openssl include path using 'include_dirs'. I changed to using 'dependencies' instead so my .gyp looks like this:
{ 'targets': [ { 'target_name': 'testengine', 'type': 'shared_library', 'sources': [ 'testengine.cc' ], 'dependencies': [ '../../../deps/openssl/openssl.gyp:openssl', ], }, ] }
It now tries to build openssl.dll first - which fails because of missing winsock library functions - perhaps it works for node.exe because it also depends on openssl-cli which adds '-lws2_32.lib' to 'openssl_cli_libraries_win'. I added the library to 'openssl_default_libraries_win' to move past the first link issues. Then openssl.dll then builds. But my testengine.dll does not build because of missing openssl symbols. I think it may have to do with that the openssl symbols are not exported?

@joelostrowski
Copy link
Contributor Author

Should be convenient if I could choose that openssl should be built as a static library while building my engine as a shared library.

@bnoordhuis
Copy link
Member

bnoordhuis commented Apr 19, 2016

You shouldn't need to build openssl yourself; node re-exports its symbols. The headers should automatically get picked up when you build the add-on, node-gyp knows where to look for them.

I filed #6274 so we have a weathervane for knowing that linking to openssl still works. Let's see how well it works on the Windows buildbots.

EDIT: I'm going to back-peddle on the headers statement; I suspect that only works with release tarballs.

@joelostrowski
Copy link
Contributor Author

So the initial way of just adding the openssl include path should have been ok? (given that the addon test-engine presumably links with node?). But that did not work on Windows. My fingers are crossed for you finding a solution!

@Trott
Copy link
Member

Trott commented Jul 7, 2017

This issue has been inactive for sufficiently long that it seems like perhaps it should be closed. Feel free to re-open (or leave a comment requesting that it be re-opened) if you disagree. I'm just tidying up and not acting on a super-strong opinion or anything like that.

And, of course, a pull request implementing the feature would be welcome.

@Trott Trott closed this as completed Jul 7, 2017
@bnoordhuis
Copy link
Member

Seems it was never back-linked but there is an (unfortunately stalled) pull request here: #6569

@pavanravuri
Copy link

Can you share changes you made in _tls_common.js to specify loading your .so engine ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Issues that request new features to be added to Node.js. openssl Issues and PRs related to the OpenSSL dependency. tls Issues and PRs related to the tls subsystem.
Projects
None yet
Development

No branches or pull requests

5 participants