-
Notifications
You must be signed in to change notification settings - Fork 29.9k
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
Openssl clientcertengine support2 #14903
Conversation
'conditions': [ | ||
['node_use_openssl=="true"', { | ||
'type': 'shared_library', | ||
'sources': [ 'testengine.cc' ], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should get indented like JS objects
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
lib/_tls_common.js
Outdated
@@ -162,6 +162,13 @@ exports.createSecureContext = function createSecureContext(options, context) { | |||
c.context.setFreeListLength(0); | |||
} | |||
|
|||
if (options.clientCertEngine) { | |||
if (c.context.setClientCertEngine) | |||
c.context.setClientCertEngine(options.clientCertEngine); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should typcheck that options.clientCertEngine
is a string
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@addaleax Fixed (hopefully in a way that is acceptable). Thanks.
0b3a4a8
to
4b829ff
Compare
I did a CI run to see if it would have the same compilation issues I ran into. The only platform that seems to have the problem is MacOS, which is what my local development environment is. /ping @nodejs/platform-macos I guess. https://ci.nodejs.org/job/node-test-commit-osx/11890/nodes=osx1010/console: gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build', '--jobs', 2 ]
CXX(target) Release/obj.target/testengine/testengine.o
SOLINK(target) Release/testengine.engine
Undefined symbols for architecture x86_64:
"_BIO_new_mem_buf", referenced from:
EngineLoadSSLClientCert(engine_st*, ssl_st*, stack_st_X509_NAME*, x509_st**, evp_pkey_st**, stack_st_X509**, ui_method_st*, void*) in testengine.o
"_BIO_vfree", referenced from:
EngineLoadSSLClientCert(engine_st*, ssl_st*, stack_st_X509_NAME*, x509_st**, evp_pkey_st**, stack_st_X509**, ui_method_st*, void*) in testengine.o
"_CRYPTO_set_add_lock_callback", referenced from:
_bind_engine in testengine.o
"_CRYPTO_set_dynlock_create_callback", referenced from:
_bind_engine in testengine.o
"_CRYPTO_set_dynlock_destroy_callback", referenced from:
_bind_engine in testengine.o
"_CRYPTO_set_dynlock_lock_callback", referenced from:
_bind_engine in testengine.o
"_CRYPTO_set_ex_data_implementation", referenced from:
_bind_engine in testengine.o
"_CRYPTO_set_locking_callback", referenced from:
_bind_engine in testengine.o
"_CRYPTO_set_mem_functions", referenced from:
_bind_engine in testengine.o
"_ENGINE_get_static_state", referenced from:
_bind_engine in testengine.o
"_ENGINE_set_destroy_function", referenced from:
_bind_engine in testengine.o
"_ENGINE_set_finish_function", referenced from:
_bind_engine in testengine.o
"_ENGINE_set_id", referenced from:
_bind_engine in testengine.o
"_ENGINE_set_init_function", referenced from:
_bind_engine in testengine.o
"_ENGINE_set_load_ssl_client_cert_function", referenced from:
_bind_engine in testengine.o
"_ENGINE_set_name", referenced from:
_bind_engine in testengine.o
"_ERR_set_implementation", referenced from:
_bind_engine in testengine.o
"_PEM_read_bio_PrivateKey", referenced from:
EngineLoadSSLClientCert(engine_st*, ssl_st*, stack_st_X509_NAME*, x509_st**, evp_pkey_st**, stack_st_X509**, ui_method_st*, void*) in testengine.o
"_PEM_read_bio_X509", referenced from:
EngineLoadSSLClientCert(engine_st*, ssl_st*, stack_st_X509_NAME*, x509_st**, evp_pkey_st**, stack_st_X509**, ui_method_st*, void*) in testengine.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [Release/testengine.engine] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/Users/iojs/build/workspace/node-test-commit-osx/nodes/osx1010/deps/npm/node_modules/node-gyp/lib/build.js:258:23)
gyp ERR! stack at emitTwo (events.js:125:13)
gyp ERR! stack at ChildProcess.emit (events.js:213:7)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:201:12)
gyp ERR! System Darwin 14.5.0
gyp ERR! command "/Users/iojs/build/workspace/node-test-commit-osx/nodes/osx1010/out/Release/node" "/Users/iojs/build/workspace/node-test-commit-osx/nodes/osx1010/deps/npm/node_modules/node-gyp/bin/node-gyp" "--loglevel=info" "rebuild" "--python=/usr/bin/python" "--directory=/Users/iojs/build/workspace/node-test-commit-osx/nodes/osx1010/test/addons/openssl-client-cert-engine/" "--nodedir=/Users/iojs/build/workspace/node-test-commit-osx/nodes/osx1010"
gyp ERR! cwd /Users/iojs/build/workspace/node-test-commit-osx/nodes/osx1010/test/addons/openssl-client-cert-engine
gyp ERR! node -v v9.0.0-pre
gyp ERR! node-gyp -v v3.6.2
gyp ERR! not ok
make[1]: *** [test/addons/.buildstamp] Error 1
make: *** [run-ci] Error 2
Build step 'Execute shell' marked build as failure
Run condition [Always] enabling perform for step [[]]
TAP Reports Processing: START
Looking for TAP results report in workspace using pattern: *.tap
Did not find any matching files. Setting build result to FAILURE.
Checking ^not ok
Jenkins Text Finder: File set '*.tap' is empty
Notifying upstream projects of job completion
Finished: FAILURE |
@@ -0,0 +1,55 @@ | |||
'use strict'; | |||
const common = require('../../common'); | |||
const assert = require('assert'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A hasCrypto
check should be added (before require('https')) to enable it to pass when --without-ssl
is specified:
if (!common.hasCrypto)
common.skip('missing crypto');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed, thanks!
'target_name': 'testengine', | ||
'conditions': [ | ||
['node_use_openssl=="true"', { | ||
'type': 'shared_library', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: indentation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed (I think).
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
const engine = path.join(__dirname, '/build/Release/testengine.engine'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this needs to use:
`./build/${common.buildType}/testengine.engine`);
to be able to support debug and release build types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh, good, thanks, fixed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I'd split re-ordering of options in documentation into a separate commit. It was pretty hard to review because of this.
@Trott Not sure if this helps or not, but I was able to get this to link using:
This allowed me to run the build successfully. But this does not take into account the case if openssl is configured as shared (and perhaps others cases). |
4b829ff
to
bf5ef60
Compare
@danbev Cool, I incorporated your gyp file changes and stuff works. Hooray! Guess I need to build a debug instance, a shared lib instance, and a no-ssl instance to check that it works under those situations. Here we go....
|
3eeb978
to
d6fee40
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good as far as I can tell!
@sam-github FYI |
I compiled with shared OpenSSL Predictably, the addon test failed. I used:
Haven't looked much at fixing it, but did want to document what I did so far for when I come back to it later (or, even better, if someone else wants to pick it up and come up with the solution). |
@Trott I think a condition for
|
doc/api/tls.md
Outdated
@@ -1067,18 +1076,19 @@ changes: | |||
When the server receives both NPN and ALPN extensions from the client, | |||
ALPN takes precedence over NPN and the server does not send an NPN | |||
extension to the client. | |||
* `NPNProtocols` {string[]|Buffer[]|Uint8Array[]|Buffer|Uint8Array} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea to alphabetize - don't capitals come before lower case in ANSI/C/ASCII locales?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To simplify the diff and to avoid discussion about whether or not it makes sense to take case into consideration (probably for machines, probably not for humans, etc.), I'm backing out this alphabetization. There are options objects all over the docs where the options are not alphabetized.
The way forward on this IMO would be to add a guideline about it to the style guide, let people bikeshed over it, and land it. Then we can apply it to all the options
objects in the docs.
lib/_tls_common.js
Outdated
c.context.setClientCertEngine(options.clientCertEngine); | ||
else | ||
throw new Error('Custom engines not supported by this OpenSSL'); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null
and undefined
should be allowed (and ignored), but perhaps any other type should be rejected as invalid usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, done. (Still have to add a test, but since this has to be moved to the new error system anyway, I've made a note-to-self to add a test then.)
My guess, from having worked with hardward based sec devices, is that if you (somehow?) have a ossl engine that stores your private key in hardward, that the client cert engine can be used to do the client-side cryptographic operations to prove its identity to the server side. I can't really tell from the docs whether my guess is right. I even googled for "openssl client cert engine", but didn't see anything obvious. So, I think the docs are not so complete, but I guess that can be patched up later. |
f55f5a8
to
5c1c0e4
Compare
@danbev Since the root
That seems to work with both the default and with shared libs. Looks good to you? |
Argh, typo in the ifndef. Fixing....
|
474fb50
to
085a847
Compare
Landed in 6ee985f, de917f8, and 829d8f1. Congratulations, @joelostrowski! 🎉 Sorry it took so long. |
Amazing stuff @Trott :-) |
@Trott you missed the meta data on this one 😢 |
The PR number included for this api addition was originally incorrect. Refs: nodejs#14903
The PR number included for this api addition was originally incorrect. PR-URL: nodejs#17630 Refs: nodejs#14903 Reviewed-By: Vse Mozhet Byt <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Jon Moss <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Rich Trott <[email protected]>
Add an option 'clientCertEngine' to `tls.createSecureContext()` which gets wired up to OpenSSL function `SSL_CTX_set_client_cert_engine`. The option is passed through from `https.request()` as well. This allows using a custom OpenSSL engine to provide the client certificate.
Added `clientCertEngine` option to `https` and `tls` docs.
The PR number included for this api addition was originally incorrect. PR-URL: #17630 Refs: #14903 Reviewed-By: Vse Mozhet Byt <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Jon Moss <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Rich Trott <[email protected]>
The PR number included for this api addition was originally incorrect. PR-URL: #17630 Refs: #14903 Reviewed-By: Vse Mozhet Byt <[email protected]> Reviewed-By: Evan Lucas <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Jon Moss <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Rich Trott <[email protected]>
Add an option 'clientCertEngine' to `tls.createSecureContext()` which gets wired up to OpenSSL function `SSL_CTX_set_client_cert_engine`. The option is passed through from `https.request()` as well. This allows using a custom OpenSSL engine to provide the client certificate.
Added `clientCertEngine` option to `https` and `tls` docs.
We have an upcoming Semver-Minor release on v8.x |
I'm not sure what the criteria are, but I'd say "no" unless it happens to cherry-pick cleanly, which would surprise me. |
Not convinced this needs to be backported to 8.x |
This is an attempt to finish #6569 which stalled. First commit is a squashed commit mostly of work done by @joelostrowski with their authorship preserved.
Original PR description:
PTAL @bnoordhuis @indutny
PTAL @sam-github at the doc changes and anything else you want
@danbev If you have time to look to make sure there aren't any "NOOOOO, this will fail if compiled without OpenSSL!!!!" problems that are super-obvious, that would be great. The stuff in
test/addons/openssl-client-cert-engine
seems like it needs acommon.hasCrypto()
check, no? Anything else anywhere in the code that looks like it might be problematic?Marking as
in progress
because I can't get the test addon to compile on MacOS. Can someone help me make sense of this output frommake test-addons
?Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
tls http crypto