From a714851dabbf314a531c381e1b69f27c1038ba20 Mon Sep 17 00:00:00 2001 From: John Yun <140559986+sfc-gh-ext-simba-jy@users.noreply.github.com> Date: Thu, 5 Dec 2024 09:29:53 -0800 Subject: [PATCH] SNOW-1825607 Initial OCSP deprecation plan steps (#973) --- index.d.ts | 6 +++--- lib/agent/check.js | 12 +++++++++++- lib/agent/socket_util.js | 9 ++------- lib/constants/error_messages.js | 2 +- lib/core.js | 12 ++++++------ lib/errors.js | 2 +- lib/global_config.js | 16 ++++++++-------- test/integration/testStructuredType.js | 4 ++-- test/unit/ocsp/test_unit_ocsp_mode.js | 4 ++-- test/unit/snowflake_config_test.js | 20 ++++++++++---------- 10 files changed, 46 insertions(+), 41 deletions(-) diff --git a/index.d.ts b/index.d.ts index 0d4e17bea..f687dbb02 100644 --- a/index.d.ts +++ b/index.d.ts @@ -25,7 +25,7 @@ declare module 'snowflake-sdk' { // 403001 ERR_GLOBAL_CONFIGURE_INVALID_LOG_LEVEL = 403001, - ERR_GLOBAL_CONFIGURE_INVALID_INSECURE_CONNECT = 403002, + ERR_GLOBAL_CONFIGURE_INVALID_DISABLE_OCSP_CHECKS = 403002, ERR_GLOBAL_CONFIGURE_INVALID_OCSP_MODE = 403003, ERR_GLOBAL_CONFIGURE_INVALID_JSON_PARSER = 403004, ERR_GLOBAL_CONFIGURE_INVALID_XML_PARSER = 403005, @@ -219,9 +219,9 @@ declare module 'snowflake-sdk' { additionalLogToConsole?: boolean | null; /** - * Check the ocsp checking is off. + * The option to turn off the OCSP check. */ - insecureConnect?: boolean; + disableOCSPChecks?: boolean; /** * The default value is true. diff --git a/lib/agent/check.js b/lib/agent/check.js index 0f1bdef83..bbc966e3f 100644 --- a/lib/agent/check.js +++ b/lib/agent/check.js @@ -115,7 +115,8 @@ function getResponse(uri, req, cb) { module.exports = function check(options, cb, mock) { let sync = true; - const maxNumRetries = GlobalConfig.getOcspMode() === GlobalConfig.ocspModes.FAIL_CLOSED ? 5 : 1; + const isFailClosed = GlobalConfig.getOcspMode() === GlobalConfig.ocspModes.FAIL_CLOSED; + const maxNumRetries = isFailClosed ? 2 : 1; function done(err, data) { if (sync) { @@ -190,6 +191,15 @@ module.exports = function check(options, cb, mock) { function ocspRequestCallback(err, uri) { if (err) { + //This error message is from @techteamer/ocsp (ocsp.utils.getAuthorityInfo) + if (err.message === 'AuthorityInfoAccess not found in extensions') { + if (!isFailClosed) { + Logger.getInstance().debug('OCSP Responder URL is missing from the certificate.'); + return done(null); + } else { + Logger.getInstance().error('OCSP Responder URL is missing from the certificate, so cannot verify with OCSP. Aborting connection attempt due to OCSP being set to FAIL_CLOSE https://docs.snowflake.com/en/user-guide/ocsp#fail-close'); + } + } return done(err); } diff --git a/lib/agent/socket_util.js b/lib/agent/socket_util.js index 215f42ff6..9f99ec182 100644 --- a/lib/agent/socket_util.js +++ b/lib/agent/socket_util.js @@ -13,11 +13,6 @@ const ErrorCodes = Errors.codes; const REGEX_SNOWFLAKE_ENDPOINT = /.snowflakecomputing./; -const ocspFailOpenWarning = - 'WARNING!!! using fail-open to connect. Driver is connecting to an HTTPS endpoint ' + - 'without OCSP based Certificated Revocation checking as it could not obtain a valid OCSP Response to use from ' + - 'the CA OCSP responder. Details: '; - const socketSecuredEvent = 'secureConnect'; const rawOcspFlag = @@ -120,7 +115,7 @@ exports.secureSocket = function (socket, host, agent, mock) { function isOcspValidationDisabled(host) { // ocsp is disabled if insecure-connect is enabled, or if we've disabled ocsp // for non-snowflake endpoints and the host is a non-snowflake endpoint - return GlobalConfig.isInsecureConnect() || + return GlobalConfig.isOCSPChecksDisabled() || (Parameters.getValue(Parameters.names.JS_DRIVER_DISABLE_OCSP_FOR_NON_SF_ENDPOINTS) && !REGEX_SNOWFLAKE_ENDPOINT.test(host)); } @@ -158,7 +153,7 @@ function canEarlyExitForOCSP(errors) { const err = errors[errorIndex]; if (err && !isValidOCSPError(err)) { // any of the errors is NOT good/revoked/unknown - Logger.getInstance().warn(ocspFailOpenWarning + err); + Logger.getInstance().debug(`OCSP responder didn't respond correctly. Assuming certificate is not revoked. Details: ${err}`); return null; } else if (err && err.code === ErrorCodes.ERR_OCSP_REVOKED) { anyRevoked = err; diff --git a/lib/constants/error_messages.js b/lib/constants/error_messages.js index 2effda456..b1bfff5e0 100644 --- a/lib/constants/error_messages.js +++ b/lib/constants/error_messages.js @@ -18,7 +18,7 @@ exports[402002] = 'Request to S3/Blob failed.'; // 403001 exports[403001] = 'Invalid logLevel. The specified value must be one of these five levels: error, warn, debug, info and trace.'; -exports[403002] = 'Invalid insecureConnect option. The specified value must be a boolean.'; +exports[403002] = 'Invalid disableOCSPChecks option. The specified value must be a boolean.'; exports[403003] = 'Invalid OCSP mode. The specified value must be FAIL_CLOSED, FAIL_OPEN, or INSECURE_MODE.'; exports[403004] = 'Invalid custom JSON parser. The specified value must be a function.'; exports[403005] = 'Invalid custom XML parser. The specified value must be a function.'; diff --git a/lib/core.js b/lib/core.js index 47f50e969..5f8b02a6f 100644 --- a/lib/core.js +++ b/lib/core.js @@ -196,14 +196,14 @@ function Core(options) { Logger.getInstance().info('Configuring logger with level: %s, filePath: %s, additionalLogToConsole: %s', logLevel, logFilePath, additionalLogToConsole); } - const insecureConnect = options.insecureConnect; - if (Util.exists(insecureConnect)) { + const disableOCSPChecks = options.disableOCSPChecks; + if (Util.exists(disableOCSPChecks)) { // check that the specified value is a boolean - Errors.checkArgumentValid(Util.isBoolean(insecureConnect), - ErrorCodes.ERR_GLOBAL_CONFIGURE_INVALID_INSECURE_CONNECT); + Errors.checkArgumentValid(Util.isBoolean(disableOCSPChecks), + ErrorCodes.ERR_GLOBAL_CONFIGURE_INVALID_DISABLE_OCSP_CHECKS); - GlobalConfig.setInsecureConnect(insecureConnect); - Logger.getInstance().debug('Setting insecureConnect to value from core options: %s', insecureConnect); + GlobalConfig.setDisableOCSPChecks(disableOCSPChecks); + Logger.getInstance().debug('Setting disableOCSPChecks to value from core options: %s', disableOCSPChecks); } const ocspFailOpen = options.ocspFailOpen; diff --git a/lib/errors.js b/lib/errors.js index 6a00ad982..4875c781d 100644 --- a/lib/errors.js +++ b/lib/errors.js @@ -23,7 +23,7 @@ codes.ERR_LARGE_RESULT_SET_RESPONSE_FAILURE = 402002; // 403001 codes.ERR_GLOBAL_CONFIGURE_INVALID_LOG_LEVEL = 403001; -codes.ERR_GLOBAL_CONFIGURE_INVALID_INSECURE_CONNECT = 403002; +codes.ERR_GLOBAL_CONFIGURE_INVALID_DISABLE_OCSP_CHECKS = 403002; codes.ERR_GLOBAL_CONFIGURE_INVALID_OCSP_MODE = 403003; codes.ERR_GLOBAL_CONFIGURE_INVALID_JSON_PARSER = 403004; codes.ERR_GLOBAL_CONFIGURE_INVALID_XML_PARSER = 403005; diff --git a/lib/global_config.js b/lib/global_config.js index 23cdd1c24..e47e30543 100644 --- a/lib/global_config.js +++ b/lib/global_config.js @@ -11,27 +11,27 @@ const Util = require('./util'); const Logger = require('./logger'); const { XMLParser, XMLValidator } = require('fast-xml-parser'); -let insecureConnect = false; +let disableOCSPChecks = false; /** - * Updates the value of the 'insecureConnect' parameter. + * Updates the value of the 'disableOCSPChecks' parameter. * * @param {boolean} value */ -exports.setInsecureConnect = function (value) { +exports.setDisableOCSPChecks = function (value) { // validate input Errors.assertInternal(Util.isBoolean(value)); - insecureConnect = value; + disableOCSPChecks = value; }; /** - * Returns the value of the 'insecureConnect' parameter. + * Returns the value of the 'disableOCSPChecks' parameter. * * @returns {boolean} */ -exports.isInsecureConnect = function () { - return insecureConnect; +exports.isOCSPChecksDisabled = function () { + return disableOCSPChecks; }; let ocspFailOpen = true; @@ -71,7 +71,7 @@ exports.ocspModes = ocspModes; * @returns {string} */ exports.getOcspMode = function () { - if (insecureConnect) { + if (disableOCSPChecks) { return ocspModes.INSECURE; } else if (!ocspFailOpen) { return ocspModes.FAIL_CLOSED; diff --git a/test/integration/testStructuredType.js b/test/integration/testStructuredType.js index e26b8d28c..22b776352 100644 --- a/test/integration/testStructuredType.js +++ b/test/integration/testStructuredType.js @@ -33,8 +33,8 @@ describe('Test Structured types', function () { connection = testUtil.createConnection(); async.series([ function (callback) { - // snowflake.configure({ 'insecureConnect': true }); - // GlobalConfig.setInsecureConnect(true); + // snowflake.configure({ 'disableOCSPChecks': true }); + // GlobalConfig.setDisableOCSPChecks(true); testUtil.connect(connection, callback); }, function (callback) { diff --git a/test/unit/ocsp/test_unit_ocsp_mode.js b/test/unit/ocsp/test_unit_ocsp_mode.js index 219aa63fe..a961b83cc 100644 --- a/test/unit/ocsp/test_unit_ocsp_mode.js +++ b/test/unit/ocsp/test_unit_ocsp_mode.js @@ -9,13 +9,13 @@ const assert = require('assert'); describe('OCSP mode', function () { it('getOcspMode', function (done) { // insecure mode - GlobalConfig.setInsecureConnect(true); + GlobalConfig.setDisableOCSPChecks(true); assert.equal(GlobalConfig.getOcspMode(), GlobalConfig.ocspModes.INSECURE); // insecure mode + Fail open GlobalConfig.setOcspFailOpen(true); assert.equal(GlobalConfig.getOcspMode(), GlobalConfig.ocspModes.INSECURE); - GlobalConfig.setInsecureConnect(false); + GlobalConfig.setDisableOCSPChecks(false); assert.equal(GlobalConfig.getOcspMode(), GlobalConfig.ocspModes.FAIL_OPEN); GlobalConfig.setOcspFailOpen(false); diff --git a/test/unit/snowflake_config_test.js b/test/unit/snowflake_config_test.js index 7cc9405af..1f10fe3c4 100644 --- a/test/unit/snowflake_config_test.js +++ b/test/unit/snowflake_config_test.js @@ -15,7 +15,7 @@ describe('Snowflake Configure Tests', function () { before(function () { originalConfig = { logLevel: Logger.getInstance().getLevelTag(), - insecureConnect: GlobalConfig.isInsecureConnect(), + disableOCSPChecks: GlobalConfig.isOCSPChecksDisabled(), ocspFailOpen: GlobalConfig.getOcspFailOpen(), keepAlive: GlobalConfig.getKeepAlive(), jsonColumnVariantParser: GlobalConfig.jsonColumnVariantParser, @@ -36,9 +36,9 @@ describe('Snowflake Configure Tests', function () { errorCode: ErrorCodes.ERR_GLOBAL_CONFIGURE_INVALID_LOG_LEVEL }, { - name: 'invalid insecureConnect', - options: { insecureConnect: 'unsupported' }, - errorCode: ErrorCodes.ERR_GLOBAL_CONFIGURE_INVALID_INSECURE_CONNECT + name: 'invalid disableOCSPChecks', + options: { disableOCSPChecks: 'unsupported' }, + errorCode: ErrorCodes.ERR_GLOBAL_CONFIGURE_INVALID_DISABLE_OCSP_CHECKS }, { name: 'invalid ocspMode', @@ -134,17 +134,17 @@ describe('Snowflake Configure Tests', function () { } }, { - name: 'insecureConnect false', + name: 'disableOCSPChecks false', options: { - insecureConnect: false + disableOCSPChecks: false } }, { - name: 'insecureConnect true', + name: 'disableOCSPChecks true', options: { - insecureConnect: true + disableOCSPChecks: true } }, { @@ -213,8 +213,8 @@ describe('Snowflake Configure Tests', function () { let val; if (key === 'logLevel') { val = Logger.getInstance().getLevelTag(); - } else if (key === 'insecureConnect') { - val = GlobalConfig.isInsecureConnect(); + } else if (key === 'disableOCSPChecks') { + val = GlobalConfig.isOCSPChecksDisabled(); } else if (key === 'ocspFailOpen') { val = GlobalConfig.getOcspFailOpen(); } else if (key === 'keepAlive') {