diff options
author | joelostrowski <jo@craftwork.dk> | 2016-04-15 16:49:36 +0200 |
---|---|---|
committer | Rich Trott <rtrott@gmail.com> | 2017-11-11 13:35:23 -0800 |
commit | 6ee985f311de14621c440377f76d0391b6b23320 (patch) | |
tree | 59f867c0c20454201dba81344aab16bff5c72a48 /test | |
parent | f7436ba1358f6af30d7d9baffdbef8754573f0e5 (diff) | |
download | android-node-v8-6ee985f311de14621c440377f76d0391b6b23320.tar.gz android-node-v8-6ee985f311de14621c440377f76d0391b6b23320.tar.bz2 android-node-v8-6ee985f311de14621c440377f76d0391b6b23320.zip |
tls: implement clientCertEngine option
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.
Diffstat (limited to 'test')
-rw-r--r-- | test/addons/openssl-client-cert-engine/binding.gyp | 24 | ||||
-rw-r--r-- | test/addons/openssl-client-cert-engine/test.js | 62 | ||||
-rw-r--r-- | test/addons/openssl-client-cert-engine/testengine.cc | 100 | ||||
-rw-r--r-- | test/parallel/test-https-agent-getname.js | 4 |
4 files changed, 188 insertions, 2 deletions
diff --git a/test/addons/openssl-client-cert-engine/binding.gyp b/test/addons/openssl-client-cert-engine/binding.gyp new file mode 100644 index 0000000000..b069e43429 --- /dev/null +++ b/test/addons/openssl-client-cert-engine/binding.gyp @@ -0,0 +1,24 @@ +{ + 'targets': [ + { + 'target_name': 'testengine', + 'type': 'none', + 'conditions': [ + ['OS=="mac" and ' + 'node_use_openssl=="true" and ' + 'node_shared=="false" and ' + 'node_shared_openssl=="false"', { + 'type': 'shared_library', + 'sources': [ 'testengine.cc' ], + 'product_extension': 'engine', + 'include_dirs': ['../../../deps/openssl/openssl/include'], + 'link_settings': { + 'libraries': [ + '../../../../out/<(PRODUCT_DIR)/<(OPENSSL_PRODUCT)' + ] + }, + }] + ] + } + ] +} diff --git a/test/addons/openssl-client-cert-engine/test.js b/test/addons/openssl-client-cert-engine/test.js new file mode 100644 index 0000000000..d07b9c6a1c --- /dev/null +++ b/test/addons/openssl-client-cert-engine/test.js @@ -0,0 +1,62 @@ +'use strict'; +const common = require('../../common'); +const fixture = require('../../common/fixtures'); + +if (!common.hasCrypto) + common.skip('missing crypto'); + +const fs = require('fs'); +const path = require('path'); + +const engine = path.join(__dirname, + `/build/${common.buildType}/testengine.engine`); + +if (!fs.existsSync(engine)) + common.skip('no client cert engine'); + +const assert = require('assert'); +const https = require('https'); + +const agentKey = fs.readFileSync(fixture.path('/keys/agent1-key.pem')); +const agentCert = fs.readFileSync(fixture.path('/keys/agent1-cert.pem')); +const agentCa = fs.readFileSync(fixture.path('/keys/ca1-cert.pem')); + +const port = common.PORT; + +const serverOptions = { + key: agentKey, + cert: agentCert, + ca: agentCa, + requestCert: true, + rejectUnauthorized: true +}; + +const server = https.createServer(serverOptions, (req, res) => { + res.writeHead(200); + res.end('hello world'); +}).listen(port, common.localhostIPv4, () => { + const clientOptions = { + method: 'GET', + host: common.localhostIPv4, + port: port, + path: '/test', + clientCertEngine: engine, // engine will provide key+cert + rejectUnauthorized: false, // prevent failing on self-signed certificates + headers: {} + }; + + const req = https.request(clientOptions, common.mustCall(function(response) { + let body = ''; + response.setEncoding('utf8'); + response.on('data', function(chunk) { + body += chunk; + }); + + response.on('end', common.mustCall(function() { + assert.strictEqual(body, 'hello world'); + server.close(); + })); + })); + + req.end(); +}); diff --git a/test/addons/openssl-client-cert-engine/testengine.cc b/test/addons/openssl-client-cert-engine/testengine.cc new file mode 100644 index 0000000000..078695a056 --- /dev/null +++ b/test/addons/openssl-client-cert-engine/testengine.cc @@ -0,0 +1,100 @@ +#include <assert.h> +#include <string.h> +#include <stdlib.h> + +#include <openssl/engine.h> +#include <openssl/pem.h> + +#include <fstream> +#include <iterator> +#include <string> + +#ifndef ENGINE_CMD_BASE +# error did not get engine.h +#endif + +#define TEST_ENGINE_ID "testengine" +#define TEST_ENGINE_NAME "dummy test engine" + +#define AGENT_KEY "test/fixtures/keys/agent1-key.pem" +#define AGENT_CERT "test/fixtures/keys/agent1-cert.pem" + +namespace { + +int EngineInit(ENGINE* engine) { + return 1; +} + +int EngineFinish(ENGINE* engine) { + return 1; +} + +int EngineDestroy(ENGINE* engine) { + return 1; +} + +std::string LoadFile(const char* filename) { + std::ifstream file(filename); + return std::string(std::istreambuf_iterator<char>(file), + std::istreambuf_iterator<char>()); +} + + +int EngineLoadSSLClientCert(ENGINE* engine, + SSL* ssl, + STACK_OF(X509_NAME)* ca_dn, + X509** ppcert, + EVP_PKEY** ppkey, + STACK_OF(X509)** pother, + UI_METHOD* ui_method, + void* callback_data) { + if (ppcert != nullptr) { + std::string cert = LoadFile(AGENT_CERT); + if (cert.empty()) { + return 0; + } + + BIO* bio = BIO_new_mem_buf(cert.data(), cert.size()); + *ppcert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); + BIO_vfree(bio); + if (*ppcert == nullptr) { + printf("Could not read certificate\n"); + return 0; + } + } + + if (ppkey != nullptr) { + std::string key = LoadFile(AGENT_KEY); + if (key.empty()) { + return 0; + } + + BIO* bio = BIO_new_mem_buf(key.data(), key.size()); + *ppkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr); + BIO_vfree(bio); + if (*ppkey == nullptr) { + printf("Could not read private key\n"); + return 0; + } + } + + return 1; +} + +int bind_fn(ENGINE* engine, const char* id) { + ENGINE_set_id(engine, TEST_ENGINE_ID); + ENGINE_set_name(engine, TEST_ENGINE_NAME); + ENGINE_set_init_function(engine, EngineInit); + ENGINE_set_finish_function(engine, EngineFinish); + ENGINE_set_destroy_function(engine, EngineDestroy); + ENGINE_set_load_ssl_client_cert_function(engine, EngineLoadSSLClientCert); + + return 1; +} + +extern "C" { + IMPLEMENT_DYNAMIC_CHECK_FN(); + IMPLEMENT_DYNAMIC_BIND_FN(bind_fn); +} + +} // anonymous namespace diff --git a/test/parallel/test-https-agent-getname.js b/test/parallel/test-https-agent-getname.js index 0986f8472d..0cdc9568d8 100644 --- a/test/parallel/test-https-agent-getname.js +++ b/test/parallel/test-https-agent-getname.js @@ -12,7 +12,7 @@ const agent = new https.Agent(); // empty options assert.strictEqual( agent.getName({}), - 'localhost::::::::::' + 'localhost:::::::::::' ); // pass all options arguments @@ -31,5 +31,5 @@ const options = { assert.strictEqual( agent.getName(options), - '0.0.0.0:443:192.168.1.1:ca:cert:ciphers:key:pfx:false:localhost:' + '0.0.0.0:443:192.168.1.1:ca:cert::ciphers:key:pfx:false:localhost:' ); |