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

feat(NODE-3777): set tls options per kms provider #235

Merged
merged 12 commits into from
Jan 20, 2022
8 changes: 7 additions & 1 deletion bindings/node/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,13 @@ export interface ClientEncryptionOptions {
/**
* TLS options for kms providers to use.
*/
tlsOptions?: ClientEncryptionTLSOptions;
tlsOptions?: {
Copy link
Member Author

Choose a reason for hiding this comment

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

TLS options to KMS providers are configured on a per KMS provider basis for future flexibility.

aws?: ClientEncryptionTLSOptions;
local?: ClientEncryptionTLSOptions;
azure?: ClientEncryptionTLSOptions;
gcp?: ClientEncryptionTLSOptions;
kmip?: ClientEncryptionTLSOptions;
}
durran marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
19 changes: 16 additions & 3 deletions bindings/node/lib/clientEncryption.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ module.exports = function(modules) {
this._client = client;
durran marked this conversation as resolved.
Show resolved Hide resolved
this._bson = options.bson || client.topology.bson;
this._proxyOptions = options.proxyOptions;
this._tlsOptions = options.tlsOptions;

if (options.keyVaultNamespace == null) {
throw new TypeError('Missing required option `keyVaultNamespace`');
Expand Down Expand Up @@ -199,7 +200,11 @@ module.exports = function(modules) {

const dataKeyBson = bson.serialize(dataKey);
const context = this._mongoCrypt.makeDataKeyContext(dataKeyBson, { keyAltNames });
const stateMachine = new StateMachine({ bson, proxyOptions: this._proxyOptions });
const stateMachine = new StateMachine({
bson,
proxyOptions: this._proxyOptions,
tlsOptions: this._tlsOptions
});

return promiseOrCallback(callback, cb => {
stateMachine.execute(this, context, (err, dataKey) => {
Expand Down Expand Up @@ -291,7 +296,11 @@ module.exports = function(modules) {
contextOptions.keyAltName = bson.serialize({ keyAltName });
}

const stateMachine = new StateMachine({ bson, proxyOptions: this._proxyOptions });
const stateMachine = new StateMachine({
bson,
proxyOptions: this._proxyOptions,
tlsOptions: this._tlsOptions
});
const context = this._mongoCrypt.makeExplicitEncryptionContext(valueBuffer, contextOptions);

return promiseOrCallback(callback, cb => {
Expand Down Expand Up @@ -336,7 +345,11 @@ module.exports = function(modules) {
const valueBuffer = bson.serialize({ v: value });
const context = this._mongoCrypt.makeExplicitDecryptionContext(valueBuffer);

const stateMachine = new StateMachine({ bson, proxyOptions: this._proxyOptions });
const stateMachine = new StateMachine({
bson,
proxyOptions: this._proxyOptions,
tlsOptions: this._tlsOptions
});

return promiseOrCallback(callback, cb => {
stateMachine.execute(this, context, (err, result) => {
Expand Down
24 changes: 24 additions & 0 deletions bindings/node/lib/stateMachine.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module.exports = function(modules) {
const tls = require('tls');
const net = require('net');
const { readFile } = require('fs/promises');
const { once } = require('events');
const { SocksClient } = require('socks');

Expand Down Expand Up @@ -283,6 +284,7 @@ module.exports = function(modules) {
}
}

await this.setTlsOptions(request.kmsProvider, options);
socket = tls.connect(options, () => {
socket.write(message);
});
Expand All @@ -305,6 +307,28 @@ module.exports = function(modules) {
});
}

/**
* @ignore
* Sets the Node TLS options if provided for the specific KMS provider.
*/
async setTlsOptions(kmsProvider, options) {
const tlsOptions = this.options.tlsOptions;
if (tlsOptions) {
const providerTlsOptions = tlsOptions[kmsProvider];
if (providerTlsOptions) {
if (providerTlsOptions.tlsCertificateKeyFile) {
options.cert = await readFile(providerTlsOptions.tlsCertificateKeyFile, { encoding: 'ascii' });
}
if (providerTlsOptions.tlsCAFile) {
options.ca = await readFile(providerTlsOptions.tlsCAFile, { encoding: 'ascii' });
}
durran marked this conversation as resolved.
Show resolved Hide resolved
if (providerTlsOptions.tlsCertificateKeyFilePassword) {
options.passphrase = providerTlsOptions.tlsCertificateKeyFilePassword;
}
}
}
}

/**
* @ignore
* Fetches collection info for a provided namespace, when libmongocrypt
Expand Down