# frozen_string_literal: true # encoding: utf-8 # Copyright (C) 2019-2020 MongoDB Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. unless ENV['LIBMONGOCRYPT_PATH'] begin require 'libmongocrypt_helper' rescue LoadError => e # It seems that MRI maintains autoload configuration for a module until # that module is defined, but JRuby removes autoload configuration as soon # as the referenced file is attempted to be loaded, even if the module # never ends up being defined. if BSON::Environment.jruby? module Mongo module Crypt autoload :Binding, 'mongo/crypt/binding' end end end # JRuby 9.3.2.0 replaces a LoadError with our custom message with a # generic NameError, when this load is attempted as part of autoloading # process. JRuby 9.2.20.0 propagates LoadError as expected. raise LoadError, "Cannot load Mongo::Crypt::Binding because there is no path " + "to libmongocrypt specified in the LIBMONGOCRYPT_PATH environment variable " + "and libmongocrypt-helper is not installed: #{e.class}: #{e}" end end require 'ffi' module Mongo module Crypt # @api private def reset_autoload remove_const(:Binding) autoload(:Binding, 'mongo/crypt/binding') end module_function :reset_autoload # A Ruby binding for the libmongocrypt C library # # @api private class Binding extend FFI::Library if ENV['LIBMONGOCRYPT_PATH'] begin ffi_lib ENV['LIBMONGOCRYPT_PATH'] rescue LoadError => e Crypt.reset_autoload raise LoadError, "Cannot load Mongo::Crypt::Binding because the path to " + "libmongocrypt specified in the LIBMONGOCRYPT_PATH environment variable " + "is invalid: #{ENV['LIBMONGOCRYPT_PATH']}\n\n#{e.class}: #{e.message}" end else begin ffi_lib LibmongocryptHelper.libmongocrypt_path rescue LoadError => e Crypt.reset_autoload raise LoadError, "Cannot load Mongo::Crypt::Binding because the path to " + "libmongocrypt specified in libmongocrypt-helper " + "is invalid: #{LibmongocryptHelper.libmongocrypt_path}\n\n#{e.class}: #{e.message}" end end # Minimum version of libmongocrypt required by this version of the driver. # An attempt to use the driver with any previous version of libmongocrypt # will cause a `LoadError`. # # @api private MIN_LIBMONGOCRYPT_VERSION = Gem::Version.new("1.5.2") # @!method self.mongocrypt_version(len) # @api private # # Returns the version string of the libmongocrypt library. # @param [ FFI::Pointer | nil ] len (out param) An optional pointer to a # uint8 that will reference the length of the returned string. # @return [ String ] A version string for libmongocrypt. attach_function :mongocrypt_version, [:pointer], :string # Validates if provided version of libmongocrypt is valid, i.e. equal or # greater than minimum required version. Raises a LoadError if not. # # @param [ String ] lmc_version String representing libmongocrypt version. # # @raise [ LoadError ] if given version is lesser than minimum required version. # # @api private def self.validate_version(lmc_version) if (actual_version = Gem::Version.new(lmc_version)) < MIN_LIBMONGOCRYPT_VERSION raise LoadError, "libmongocrypt version #{MIN_LIBMONGOCRYPT_VERSION} or above is required, " + "but version #{actual_version} was found." end rescue ArgumentError => e # Some lmc versions cannot be parsed with Gem::Version class, # so we fall back to regex. match = lmc_version.match(/\A(?\d+)\.(?\d+)\.(?\d+)?(-[A-Za-z\+\d]+)?\z/) if match.nil? raise ArgumentError.new("Malformed version number string #{lmc_version}") end actual_version = Gem::Version.new( [ match[:major], match[:minor], match[:patch] ].join('.') ) if actual_version < MIN_LIBMONGOCRYPT_VERSION raise LoadError, "libmongocrypt version #{MIN_LIBMONGOCRYPT_VERSION} or above is required, " + "but version #{actual_version} was found." end end validate_version(mongocrypt_version(nil)) # @!method self.mongocrypt_binary_new # @api private # # Creates a new mongocrypt_binary_t object (a non-owning view of a byte # array). # @return [ FFI::Pointer ] A pointer to the newly-created # mongocrypt_binary_t object. attach_function :mongocrypt_binary_new, [], :pointer # @!method self.mongocrypt_binary_new_from_data(data, len) # @api private # # Create a new mongocrypt_binary_t object that maintains a pointer to # the specified byte array. # @param [ FFI::Pointer ] data A pointer to an array of bytes; the data # is not copied and must outlive the mongocrypt_binary_t object. # @param [ Integer ] len The length of the array argument. # @return [ FFI::Pointer ] A pointer to the newly-created # mongocrypt_binary_t object. attach_function( :mongocrypt_binary_new_from_data, [:pointer, :int], :pointer ) # @!method self.mongocrypt_binary_data(binary) # @api private # # Get the pointer to the underlying data for the mongocrypt_binary_t. # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t object. # @return [ FFI::Pointer ] A pointer to the data array. attach_function :mongocrypt_binary_data, [:pointer], :pointer # @!method self.mongocrypt_binary_len(binary) # @api private # # Get the length of the underlying data array. # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t object. # @return [ Integer ] The length of the data array. attach_function :mongocrypt_binary_len, [:pointer], :int # @!method self.mongocrypt_binary_destroy(binary) # @api private # # Destroy the mongocrypt_binary_t object. # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t object. # @return [ nil ] Always nil. attach_function :mongocrypt_binary_destroy, [:pointer], :void # Enum labeling different status types enum :status_type, [ :ok, 0, :error_client, 1, :error_kms, 2, ] # @!method self.mongocrypt_status_new # @api private # # Create a new mongocrypt_status_t object. # @return [ FFI::Pointer ] A pointer to the new mongocrypt_status_ts. attach_function :mongocrypt_status_new, [], :pointer # @!method self.mongocrypt_status_set(status, type, code, message, len) # @api private # # Set a message, type, and code on an existing status. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t. # @param [ Symbol ] type The status type; possible values are defined # by the status_type enum. # @param [ Integer ] code The status code. # @param [ String ] message The status message. # @param [ Integer ] len The length of the message argument (or -1 for a # null-terminated string). # @return [ nil ] Always nil. attach_function( :mongocrypt_status_set, [:pointer, :status_type, :int, :string, :int], :void ) # @!method self.mongocrypt_status_type(status) # @api private # # Indicates the status type. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t. # @return [ Symbol ] The status type (as defined by the status_type enum). attach_function :mongocrypt_status_type, [:pointer], :status_type # @!method self.mongocrypt_status_code(status) # @api private # # Return the status error code. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t. # @return [ Integer ] The status code. attach_function :mongocrypt_status_code, [:pointer], :int # @!method self.mongocrypt_status_message(status, len=nil) # @api private # # Returns the status message. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t. # @param [ FFI::Pointer | nil ] len (out param) An optional pointer to a # uint32, where the length of the retun string will be written. # @return [ String ] The status message. attach_function :mongocrypt_status_message, [:pointer, :pointer], :string # @!method self.mongocrypt_status_ok(status) # @api private # # Returns whether the status is ok or an error. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t. # @return [ Boolean ] Whether the status is ok. attach_function :mongocrypt_status_ok, [:pointer], :bool # @!method self.mongocrypt_status_destroy(status) # @api private # # Destroys the reference to the mongocrypt_status_t object. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t. # @return [ nil ] Always nil. attach_function :mongocrypt_status_destroy, [:pointer], :void # Enum labeling the various log levels enum :log_level, [ :fatal, 0, :error, 1, :warn, 2, :info, 3, :debug, 4, ] # @!method mongocrypt_log_fn_t(level, message, len, ctx) # @api private # # A callback to the mongocrypt log function. Set a custom log callback # with the mongocrypt_setopt_log_handler method # @param [ Symbol ] level The log level; possible values defined by the # log_level enum # @param [ String ] message The log message # @param [ Integer ] len The length of the message param, or -1 if the # string is null terminated # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context # object when this callback was set # @return [ nil ] Always nil. # # @note This defines a method signature for an FFI callback; it is not # an instance method on the Binding class. callback :mongocrypt_log_fn_t, [:log_level, :string, :int, :pointer], :void # @!method self.ongocrypt_new # @api private # # Creates a new mongocrypt_t object. # @return [ FFI::Pointer ] A pointer to a new mongocrypt_t object. attach_function :mongocrypt_new, [], :pointer # @!method self.mongocrypt_setopt_log_handler(crypt, log_fn, log_ctx=nil) # @api private # # Set the handler on the mongocrypt_t object to be called every time # libmongocrypt logs a message. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ Method ] log_fn A logging callback method. # @param [ FFI::Pointer | nil ] log_ctx An optional pointer to a context # to be passed into the log callback on every invocation. # @return [ Boolean ] Whether setting the callback was successful. attach_function( :mongocrypt_setopt_log_handler, [:pointer, :mongocrypt_log_fn_t, :pointer], :bool ) # Set the logger callback function on the Mongo::Crypt::Handle object # # @param [ Mongo::Crypt::Handle ] handle # @param [ Method ] log_callback # # @raise [ Mongo::Error::CryptError ] If the callback is not set successfully def self.setopt_log_handler(handle, log_callback) check_status(handle) do mongocrypt_setopt_log_handler(handle, log_callback, nil) end end # @!method self.mongocrypt_setopt_kms_providers(crypt, kms_providers) # @api private # # Configure KMS providers with a BSON document. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ FFI::Pointer ] kms_providers A pointer to a # mongocrypt_binary_t object that references a BSON document mapping # the KMS provider names to credentials. # @note Do not initialize ctx before calling this method. # # @returns [ true | false ] Returns whether the options was set successfully. attach_function( :mongocrypt_setopt_kms_providers, [:pointer, :pointer], :bool ) # Set KMS providers options on the Mongo::Crypt::Handle object # # @param [ Mongo::Crypt::Handle ] handle # @param [ BSON::Document ] kms_providers BSON document mapping # the KMS provider names to credentials. # # @raise [ Mongo::Error::CryptError ] If the option is not set successfully def self.setopt_kms_providers(handle, kms_providers) validate_document(kms_providers) data = kms_providers.to_bson.to_s Binary.wrap_string(data) do |data_p| check_status(handle) do mongocrypt_setopt_kms_providers(handle.ref, data_p) end end end # @!method self.mongocrypt_setopt_schema_map(crypt, schema_map) # @api private # # Sets a local schema map for encryption. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ FFI::Pointer ] schema_map A pointer to a mongocrypt_binary_t. # object that references the schema map as a BSON binary string. # @return [ Boolean ] Returns whether the option was set successfully. attach_function :mongocrypt_setopt_schema_map, [:pointer, :pointer], :bool # Set schema map on the Mongo::Crypt::Handle object # # @param [ Mongo::Crypt::Handle ] handle # @param [ BSON::Document ] schema_map_doc The schema map as a # BSON::Document object # # @raise [ Mongo::Error::CryptError ] If the schema map is not set successfully def self.setopt_schema_map(handle, schema_map_doc) validate_document(schema_map_doc) data = schema_map_doc.to_bson.to_s Binary.wrap_string(data) do |data_p| check_status(handle) do mongocrypt_setopt_schema_map(handle.ref, data_p) end end end # @!method self.mongocrypt_init(crypt) # @api private # # Initialize the mongocrypt_t object. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @return [ Boolean ] Returns whether the crypt was initialized successfully. attach_function :mongocrypt_init, [:pointer], :bool # Initialize the Mongo::Crypt::Handle object # # @param [ Mongo::Crypt::Handle ] handle # # @raise [ Mongo::Error::CryptError ] If initialization fails def self.init(handle) check_status(handle) do mongocrypt_init(handle.ref) end end # @!method self.mongocrypt_status(crypt, status) # @api private # # Set the status information from the mongocrypt_t object on the # mongocrypt_status_t object. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t object. # @return [ Boolean ] Whether the status was successfully set. attach_function :mongocrypt_status, [:pointer, :pointer], :bool # @!method self.mongocrypt_destroy(crypt) # @api private # # Destroy the reference the mongocrypt_t object. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @return [ nil ] Always nil. attach_function :mongocrypt_destroy, [:pointer], :void # @!method self.mongocrypt_ctx_new(crypt) # @api private # # Create a new mongocrypt_ctx_t object (a wrapper for the libmongocrypt # state machine). # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @return [ FFI::Pointer ] A new mongocrypt_ctx_t object. attach_function :mongocrypt_ctx_new, [:pointer], :pointer # @!method self.mongocrypt_ctx_status(ctx, status) # @api private # # Set the status information from the mongocrypt_ctx_t object on the # mongocrypt_status_t object. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t object. # @return [ Boolean ] Whether the status was successfully set. attach_function :mongocrypt_ctx_status, [:pointer, :pointer], :bool # @!method self.mongocrypt_ctx_setopt_key_id(ctx, key_id) # @api private # # Set the key id used for explicit encryption. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] key_id A pointer to a mongocrypt_binary_t object # that references the 16-byte key-id. # @note Do not initialize ctx before calling this method. # @return [ Boolean ] Whether the option was successfully set. attach_function :mongocrypt_ctx_setopt_key_id, [:pointer, :pointer], :bool # Sets the key id option on an explicit encryption context. # # @param [ Mongo::Crypt::Context ] context Explicit encryption context # @param [ String ] key_id The key id # # @raise [ Mongo::Error::CryptError ] If the operation failed def self.ctx_setopt_key_id(context, key_id) Binary.wrap_string(key_id) do |key_id_p| check_ctx_status(context) do mongocrypt_ctx_setopt_key_id(context.ctx_p, key_id_p) end end end # @!method self.mongocrypt_ctx_setopt_key_alt_name(ctx, binary) # @api private # # When creating a data key, set an alternate name on that key. When # performing explicit encryption, specifying which data key to use for # encryption based on its keyAltName field. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t # object that references a BSON document in the format # { "keyAltName": }. # @return [ Boolean ] Whether the alternative name was successfully set. # @note Do not initialize ctx before calling this method. attach_function( :mongocrypt_ctx_setopt_key_alt_name, [:pointer, :pointer], :bool ) # Set multiple alternate key names on data key creation # # @param [ Mongo::Crypt::Context ] context A DataKeyContext # @param [ Array ] key_alt_names An array of alternate key names as strings # # @raise [ Mongo::Error::CryptError ] If any of the alternate names are # not valid UTF8 strings def self.ctx_setopt_key_alt_names(context, key_alt_names) key_alt_names.each do |key_alt_name| key_alt_name_bson = { :keyAltName => key_alt_name }.to_bson.to_s Binary.wrap_string(key_alt_name_bson) do |key_alt_name_p| check_ctx_status(context) do mongocrypt_ctx_setopt_key_alt_name(context.ctx_p, key_alt_name_p) end end end end # @!method self.mongocrypt_ctx_setopt_key_material(ctx, binary) # @api private # # When creating a data key, set a custom key material to use for # encrypting data. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] binary A pointer to a mongocrypt_binary_t # object that references the data encryption key to use. # @return [ Boolean ] Whether the custom key material was successfully set. # @note Do not initialize ctx before calling this method. attach_function( :mongocrypt_ctx_setopt_key_material, [:pointer, :pointer], :bool ) # Set set a custom key material to use for # encrypting data. # # @param [ Mongo::Crypt::Context ] context A DataKeyContext # @param [ BSON::Binary ] key_material 96 bytes of custom key material # # @raise [ Mongo::Error::CryptError ] If the key material is not 96 bytes. def self.ctx_setopt_key_material(context, key_material) data = {'keyMaterial' => key_material}.to_bson.to_s Binary.wrap_string(data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_setopt_key_material(context.ctx_p, data_p) end end end # @!method self.mongocrypt_ctx_setopt_algorithm(ctx, algorithm, len) # @api private # # Set the algorithm used for explicit encryption. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ String ] algorithm The algorithm name. Valid values are: # - "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" # - "AEAD_AES_256_CBC_HMAC_SHA_512-Random" # @param [ Integer ] len The length of the algorithm string. # @note Do not initialize ctx before calling this method. # @return [ Boolean ] Whether the option was successfully set. attach_function( :mongocrypt_ctx_setopt_algorithm, [:pointer, :string, :int], :bool ) # Set the algorithm on the context # # @param [ Mongo::Crypt::Context ] context # @param [ String ] name The algorithm name. Valid values are: # - "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" # - "AEAD_AES_256_CBC_HMAC_SHA_512-Random" # # @raise [ Mongo::Error::CryptError ] If the operation failed def self.ctx_setopt_algorithm(context, name) check_ctx_status(context) do mongocrypt_ctx_setopt_algorithm(context.ctx_p, name, -1) end end # @!method self.mongocrypt_ctx_setopt_key_encryption_key(ctx) # @api private # # Set key encryption key document for creating a data key. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] bin A pointer to a mongocrypt_binary_t # object that references a BSON document representing the key # encryption key document with an additional "provider" field. # @note Do not initialize ctx before calling this method. # @return [ Boolean ] Whether the option was successfully set. attach_function( :mongocrypt_ctx_setopt_key_encryption_key, [:pointer, :pointer], :bool ) # Set key encryption key document for creating a data key. # # @param [ Mongo::Crypt::Context ] context # @param [ BSON::Document ] key_document BSON document representing the key # encryption key document with an additional "provider" field. # # @raise [ Mongo::Error::CryptError ] If the operation failed def self.ctx_setopt_key_encryption_key(context, key_document) validate_document(key_document) data = key_document.to_bson.to_s Binary.wrap_string(data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_setopt_key_encryption_key(context.ctx_p, data_p) end end end # @!method self.mongocrypt_ctx_datakey_init(ctx) # @api private # # Initializes the ctx to create a data key. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @note Before calling this method, master key options must be set. # Set AWS master key by calling mongocrypt_ctx_setopt_masterkey_aws # and mongocrypt_ctx_setopt_masterkey_aws_endpoint. Set local master # key by calling mongocrypt_ctx_setopt_masterkey_local. # @return [ Boolean ] Whether the initialization was successful. attach_function :mongocrypt_ctx_datakey_init, [:pointer], :bool # Initialize the Context to create a data key # # @param [ Mongo::Crypt::Context ] context # # @raise [ Mongo::Error::CryptError ] If initialization fails def self.ctx_datakey_init(context) check_ctx_status(context) do mongocrypt_ctx_datakey_init(context.ctx_p) end end # @!method self.mongocrypt_ctx_datakey_init(ctx, filter) # @api private # # Initialize a context to rewrap datakeys. # # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] filter A pointer to a mongocrypt_binary_t object # that represents filter to use for the find command on the key vault # collection to retrieve datakeys to rewrap. # # @return [ Boolean ] Whether the initialization was successful. attach_function( :mongocrypt_ctx_rewrap_many_datakey_init, [:pointer, :pointer], :bool ) # Initialize a context to rewrap datakeys. # # @param [ Mongo::Crypt::Context ] context # @param [ BSON::Document ] filter BSON Document # that represents filter to use for the find command on the key vault # collection to retrieve datakeys to rewrap. # # @return [ Boolean ] Whether the initialization was successful. def self.ctx_rewrap_many_datakey_init(context, filter) filter_data = filter.to_bson.to_s Binary.wrap_string(filter_data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_rewrap_many_datakey_init(context.ctx_p, data_p) end end end # @!method self.mongocrypt_ctx_encrypt_init(ctx, db, db_len, cmd) # @api private # # Initializes the ctx for auto-encryption. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ String ] db The database name. # @param [ Integer ] db_len The length of the database name argument # (or -1 for a null-terminated string). # @param [ FFI::Pointer ] cmd A pointer to a mongocrypt_binary_t object # that references the database command as a binary string. # @note This method expects the passed-in BSON to be in the format: # { "v": BSON value to decrypt }. # @return [ Boolean ] Whether the initialization was successful. attach_function( :mongocrypt_ctx_encrypt_init, [:pointer, :string, :int, :pointer], :bool ) # Initialize the Context for auto-encryption # # @param [ Mongo::Crypt::Context ] context # @param [ String ] db_name The name of the database against which the # encrypted command is being performed # @param [ Hash ] command The command to be encrypted # # @raise [ Mongo::Error::CryptError ] If initialization fails def self.ctx_encrypt_init(context, db_name, command) validate_document(command) data = command.to_bson.to_s Binary.wrap_string(data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_encrypt_init(context.ctx_p, db_name, -1, data_p) end end end # @!method self.mongocrypt_ctx_explicit_encrypt_init(ctx, msg) # @api private # # Initializes the ctx for explicit encryption. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] msg A pointer to a mongocrypt_binary_t object # that references the message to be encrypted as a binary string. # @note Before calling this method, set a key_id, key_alt_name (optional), # and encryption algorithm using the following methods: # mongocrypt_ctx_setopt_key_id, mongocrypt_ctx_setopt_key_alt_name, # and mongocrypt_ctx_setopt_algorithm. # @return [ Boolean ] Whether the initialization was successful. attach_function( :mongocrypt_ctx_explicit_encrypt_init, [:pointer, :pointer], :bool ) # Initialize the Context for explicit encryption # # @param [ Mongo::Crypt::Context ] context # @param [ Hash ] doc A BSON document to encrypt # # @raise [ Mongo::Error::CryptError ] If initialization fails def self.ctx_explicit_encrypt_init(context, doc) validate_document(doc) data = doc.to_bson.to_s Binary.wrap_string(data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_explicit_encrypt_init(context.ctx_p, data_p) end end end # @!method self.mongocrypt_ctx_decrypt_init(ctx, doc) # @api private # # Initializes the ctx for auto-decryption. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] doc A pointer to a mongocrypt_binary_t object # that references the document to be decrypted as a BSON binary string. # @return [ Boolean ] Whether the initialization was successful. attach_function :mongocrypt_ctx_decrypt_init, [:pointer, :pointer], :bool # Initialize the Context for auto-decryption # # @param [ Mongo::Crypt::Context ] context # @param [ BSON::Document ] command A BSON document to decrypt # # @raise [ Mongo::Error::CryptError ] If initialization fails def self.ctx_decrypt_init(context, command) validate_document(command) data = command.to_bson.to_s Binary.wrap_string(data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_decrypt_init(context.ctx_p, data_p) end end end # @!method self.mongocrypt_ctx_explicit_decrypt_init(ctx, msg) # @api private # # Initializes the ctx for explicit decryption. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] msg A pointer to a mongocrypt_binary_t object # that references the message to be decrypted as a BSON binary string. # @return [ Boolean ] Whether the initialization was successful. attach_function( :mongocrypt_ctx_explicit_decrypt_init, [:pointer, :pointer], :bool ) # Initialize the Context for explicit decryption # # @param [ Mongo::Crypt::Context ] context # @param [ Hash ] doc A BSON document to decrypt # # @raise [ Mongo::Error::CryptError ] If initialization fails def self.ctx_explicit_decrypt_init(context, doc) validate_document(doc) data = doc.to_bson.to_s Binary.wrap_string(data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_explicit_decrypt_init(context.ctx_p, data_p) end end end # An enum labeling different libmognocrypt state machine states enum :mongocrypt_ctx_state, [ :error, 0, :need_mongo_collinfo, 1, :need_mongo_markings, 2, :need_mongo_keys, 3, :need_kms, 4, :ready, 5, :done, 6, ] # @!method self.mongocrypt_ctx_state(ctx) # @api private # # Get the current state of the ctx. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @return [ Symbol ] The current state, will be one of the values defined # by the mongocrypt_ctx_state enum. attach_function :mongocrypt_ctx_state, [:pointer], :mongocrypt_ctx_state # @!method self.mongocrypt_ctx_mongo_op(ctx, op_bson) # @api private # # Get a BSON operation for the driver to run against the MongoDB # collection, the key vault database, or mongocryptd. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] op_bson (out param) A pointer to a # mongocrypt_binary_t object that will have a reference to the # BSON operation written to it by libmongocrypt. # @return [ Boolean ] A boolean indicating the success of the operation. attach_function :mongocrypt_ctx_mongo_op, [:pointer, :pointer], :bool # Returns a BSON::Document representing an operation that the # driver must perform on behalf of libmongocrypt to get the # information it needs in order to continue with # encryption/decryption (for example, a filter for a key vault query). # # @param [ Mongo::Crypt::Context ] context # # @raise [ Mongo::Crypt ] If there is an error getting the operation # @return [ BSON::Document ] The operation that the driver must perform def self.ctx_mongo_op(context) binary = Binary.new check_ctx_status(context) do mongocrypt_ctx_mongo_op(context.ctx_p, binary.ref) end # TODO since the binary references a C pointer, and ByteBuffer is # written in C in MRI, we could omit a copy of the data by making # ByteBuffer reference the string that is owned by libmongocrypt. BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: :bson) end # @!method self.mongocrypt_ctx_mongo_feed(ctx, reply) # @api private # # Feed a BSON reply to libmongocrypt. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] reply A mongocrypt_binary_t object that # references the BSON reply to feed to libmongocrypt. # @return [ Boolean ] A boolean indicating the success of the operation. attach_function :mongocrypt_ctx_mongo_feed, [:pointer, :pointer], :bool # Feed a response from the driver back to libmongocrypt # # @param [ Mongo::Crypt::Context ] context # @param [ BSON::Document ] doc The document representing the response # # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully def self.ctx_mongo_feed(context, doc) validate_document(doc) data = doc.to_bson.to_s Binary.wrap_string(data) do |data_p| check_ctx_status(context) do mongocrypt_ctx_mongo_feed(context.ctx_p, data_p) end end end # @!method self.mongocrypt_ctx_mongo_done(ctx) # @api private # # Indicate to libmongocrypt that the driver is done feeding replies. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @return [ Boolean ] A boolean indicating the success of the operation. attach_function :mongocrypt_ctx_mongo_done, [:pointer], :bool # @!method self.mongocrypt_ctx_mongo_next_kms_ctx(ctx) # @api private # # Return a pointer to a mongocrypt_kms_ctx_t object or NULL. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @return [ FFI::Pointer ] A pointer to a mongocrypt_kms_ctx_t object. attach_function :mongocrypt_ctx_next_kms_ctx, [:pointer], :pointer # Return a new KmsContext object needed by a Context object. # # @param [ Mongo::Crypt::Context ] context # # @return [ Mongo::Crypt::KmsContext | nil ] The KmsContext needed to # fetch an AWS master key or nil, if no KmsContext is needed def self.ctx_next_kms_ctx(context) kms_ctx_p = mongocrypt_ctx_next_kms_ctx(context.ctx_p) if kms_ctx_p.null? nil else KmsContext.new(kms_ctx_p) end end # @!method self.mongocrypt_kms_ctx_get_kms_provider(crypt, kms_providers) # @api private # # Get the KMS provider identifier associated with this KMS request. # # This is used to conditionally configure TLS connections based on the KMS # request. It is useful for KMIP, which authenticates with a client # certificate. # # @param [ FFI::Pointer ] kms Pointer mongocrypt_kms_ctx_t object. # @param [ FFI::Pointer ] len (outparam) Receives the length of the # returned string. It may be NULL. If it is not NULL, it is set to # the length of the returned string without the NULL terminator. # # @returns [ FFI::Pointer ] One of the NULL terminated static strings: "aws", "azure", "gcp", or # "kmip". attach_function( :mongocrypt_kms_ctx_get_kms_provider, [:pointer, :pointer], :pointer ) # Get the KMS provider identifier associated with this KMS request. # # This is used to conditionally configure TLS connections based on the KMS # request. It is useful for KMIP, which authenticates with a client # certificate. # # @param [ FFI::Pointer ] kms Pointer mongocrypt_kms_ctx_t object. # # @returns [ Symbol | nil ] KMS provider identifier. def self.kms_ctx_get_kms_provider(kms_context) len_ptr = FFI::MemoryPointer.new(:uint32, 1) provider = mongocrypt_kms_ctx_get_kms_provider( kms_context.kms_ctx_p, len_ptr ) if len_ptr.nil? nil else len = if BSON::Environment.jruby? # JRuby FFI implementation does not have `read(type)` method, but it # has this `get_uint32`. len_ptr.get_uint32 else # For MRI we use a documented `read` method - https://www.rubydoc.info/github/ffi/ffi/FFI%2FPointer:read len_ptr.read(:uint32) end provider.read_string(len).to_sym end end # @!method self.mongocrypt_kms_ctx_message(kms, msg) # @api private # # Get the message needed to fetch the AWS KMS master key. # @param [ FFI::Pointer ] kms Pointer to the mongocrypt_kms_ctx_t object # @param [ FFI::Pointer ] msg (outparam) Pointer to a mongocrypt_binary_t # object that will have the location of the message written to it by # libmongocrypt. # @return [ Boolean ] Whether the operation is successful. attach_function :mongocrypt_kms_ctx_message, [:pointer, :pointer], :bool # Get the HTTP message needed to fetch the AWS KMS master key from a # KmsContext object. # # @param [ Mongo::Crypt::KmsContext ] kms_context # # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully # # @return [ String ] The HTTP message def self.kms_ctx_message(kms_context) binary = Binary.new check_kms_ctx_status(kms_context) do mongocrypt_kms_ctx_message(kms_context.kms_ctx_p, binary.ref) end return binary.to_s end # @!method self.mongocrypt_kms_ctx_endpoint(kms, endpoint) # @api private # # Get the hostname with which to connect over TLS to get information about # the AWS master key. # @param [ FFI::Pointer ] kms A pointer to a mongocrypt_kms_ctx_t object. # @param [ FFI::Pointer ] endpoint (out param) A pointer to which the # endpoint string will be written by libmongocrypt. # @return [ Boolean ] Whether the operation was successful. attach_function :mongocrypt_kms_ctx_endpoint, [:pointer, :pointer], :bool # Get the hostname with which to connect over TLS to get information # about the AWS master key. # # @param [ Mongo::Crypt::KmsContext ] kms_context # # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully # # @return [ String | nil ] The hostname, or nil if none exists def self.kms_ctx_endpoint(kms_context) ptr = FFI::MemoryPointer.new(:pointer, 1) check_kms_ctx_status(kms_context) do mongocrypt_kms_ctx_endpoint(kms_context.kms_ctx_p, ptr) end str_ptr = ptr.read_pointer str_ptr.null? ? nil : str_ptr.read_string.force_encoding('UTF-8') end # @!method self.mongocrypt_kms_ctx_bytes_needed(kms) # @api private # # Get the number of bytes needed by the KMS context. # @param [ FFI::Pointer ] kms The mongocrypt_kms_ctx_t object. # @return [ Integer ] The number of bytes needed. attach_function :mongocrypt_kms_ctx_bytes_needed, [:pointer], :int # Get the number of bytes needed by the KmsContext. # # @param [ Mongo::Crypt::KmsContext ] kms_context # # @return [ Integer ] The number of bytes needed def self.kms_ctx_bytes_needed(kms_context) mongocrypt_kms_ctx_bytes_needed(kms_context.kms_ctx_p) end # @!method self.mongocrypt_kms_ctx_feed(kms, bytes) # @api private # # Feed replies from the KMS back to libmongocrypt. # @param [ FFI::Pointer ] kms A pointer to the mongocrypt_kms_ctx_t object. # @param [ FFI::Pointer ] bytes A pointer to a mongocrypt_binary_t # object that references the response from the KMS. # @return [ Boolean ] Whether the operation was successful. attach_function :mongocrypt_kms_ctx_feed, [:pointer, :pointer], :bool # Feed replies from the KMS back to libmongocrypt. # # @param [ Mongo::Crypt::KmsContext ] kms_context # @param [ String ] bytes The data to feed to libmongocrypt # # @raise [ Mongo::Error::CryptError ] If the response is not fed successfully def self.kms_ctx_feed(kms_context, bytes) check_kms_ctx_status(kms_context) do Binary.wrap_string(bytes) do |bytes_p| mongocrypt_kms_ctx_feed(kms_context.kms_ctx_p, bytes_p) end end end # @!method self.mongocrypt_kms_ctx_status(kms, status) # @api private # # Write status information about the mongocrypt_kms_ctx_t object # to the mongocrypt_status_t object. # @param [ FFI::Pointer ] kms A pointer to the mongocrypt_kms_ctx_t object. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t object. # @return [ Boolean ] Whether the operation was successful. attach_function :mongocrypt_kms_ctx_status, [:pointer, :pointer], :bool # If the provided block returns false, raise a CryptError with the # status information from the provided KmsContext object. # # @param [ Mongo::Crypt::KmsContext ] kms_context # # @raise [ Mongo::Error::CryptError ] If the provided block returns false def self.check_kms_ctx_status(kms_context) unless yield status = Status.new mongocrypt_kms_ctx_status(kms_context.kms_ctx_p, status.ref) status.raise_crypt_error(kms: true) end end # @!method self.mongocrypt_kms_ctx_done(ctx) # @api private # # Indicate to libmongocrypt that it will receive no more replies from # mongocrypt_kms_ctx_t objects. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @return [ Boolean ] Whether the operation was successful. attach_function :mongocrypt_ctx_kms_done, [:pointer], :bool # Indicate to libmongocrypt that it will receive no more KMS replies. # # @param [ Mongo::Crypt::Context ] context # # @raise [ Mongo::Error::CryptError ] If the operation is unsuccessful def self.ctx_kms_done(context) check_ctx_status(context) do mongocrypt_ctx_kms_done(context.ctx_p) end end # @!method self.mongocrypt_ctx_finalize(ctx, op_bson) # @api private # # Perform the final encryption or decryption and return a BSON document. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ FFI::Pointer ] op_bson (out param) A pointer to a # mongocrypt_binary_t object that will have a reference to the # final encrypted BSON document. # @return [ Boolean ] A boolean indicating the success of the operation. attach_function :mongocrypt_ctx_finalize, [:pointer, :pointer], :void # Finalize the state machine represented by the Context # # @param [ Mongo::Crypt::Context ] context # # @raise [ Mongo::Error::CryptError ] If the state machine is not successfully # finalized def self.ctx_finalize(context) binary = Binary.new check_ctx_status(context) do mongocrypt_ctx_finalize(context.ctx_p, binary.ref) end # TODO since the binary references a C pointer, and ByteBuffer is # written in C in MRI, we could omit a copy of the data by making # ByteBuffer reference the string that is owned by libmongocrypt. BSON::Document.from_bson(BSON::ByteBuffer.new(binary.to_s), mode: :bson) end # @!method self.mongocrypt_ctx_destroy(ctx) # @api private # # Destroy the reference to the mongocrypt_ctx_t object. # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @return [ nil ] Always nil. attach_function :mongocrypt_ctx_destroy, [:pointer], :void # @!method mongocrypt_crypto_fn(ctx, key, iv, input, output, status) # @api private # # A callback to a function that performs AES encryption or decryption. # @param [ FFI::Pointer | nil] ctx An optional pointer to a context object # that may have been set when hooks were enabled. # @param [ FFI::Pointer ] key A pointer to a mongocrypt_binary_t object # that references the 32-byte AES encryption key. # @param [ FFI::Pointer ] iv A pointer to a mongocrypt_binary_t object # that references the 16-byte AES IV. # @param [ FFI::Pointer ] input A pointer to a mongocrypt_binary_t object # that references the value to be encrypted/decrypted. # @param [ FFI::Pointer ] output (out param) A pointer to a # mongocrypt_binary_t object will have a reference to the encrypted/ # decrypted value written to it by libmongocrypt. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t # object to which an error message will be written if encryption fails. # @return [ Bool ] Whether encryption/decryption was successful. # # @note This defines a method signature for an FFI callback; it is not # an instance method on the Binding class. callback( :mongocrypt_crypto_fn, [:pointer, :pointer, :pointer, :pointer, :pointer, :pointer, :pointer], :bool ) # @!method mongocrypt_hmac_fn(ctx, key, input, output, status) # @api private # # A callback to a function that performs HMAC SHA-512 or SHA-256. # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object # that may have been set when hooks were enabled. # @param [ FFI::Pointer ] key A pointer to a mongocrypt_binary_t object # that references the 32-byte HMAC SHA encryption key. # @param [ FFI::Pointer ] input A pointer to a mongocrypt_binary_t object # that references the input value. # @param [ FFI::Pointer ] output (out param) A pointer to a # mongocrypt_binary_t object will have a reference to the output value # written to it by libmongocrypt. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t # object to which an error message will be written if encryption fails. # @return [ Bool ] Whether HMAC-SHA was successful. # # @note This defines a method signature for an FFI callback; it is not # an instance method on the Binding class. callback( :mongocrypt_hmac_fn, [:pointer, :pointer, :pointer, :pointer, :pointer], :bool ) # @!method mongocrypt_hash_fn(ctx, input, output, status) # @api private # # A callback to a SHA-256 hash function. # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object # that may have been set when hooks were enabled. # @param [ FFI::Pointer ] input A pointer to a mongocrypt_binary_t object # that references the value to be hashed. # @param [ FFI::Pointer ] output (out param) A pointer to a # mongocrypt_binary_t object will have a reference to the output value # written to it by libmongocrypt. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t # object to which an error message will be written if encryption fails. # @return [ Bool ] Whether hashing was successful. # # @note This defines a method signature for an FFI callback; it is not # an instance method on the Binding class. callback :mongocrypt_hash_fn, [:pointer, :pointer, :pointer, :pointer], :bool # @!method mongocrypt_random_fn(ctx, output, count, status) # @api private # # A callback to a crypto secure random function. # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object # that may have been set when hooks were enabled. # @param [ FFI::Pointer ] output (out param) A pointer to a # mongocrypt_binary_t object will have a reference to the output value # written to it by libmongocrypt. # @param [ Integer ] count The number of random bytes to return. # @param [ FFI::Pointer ] status A pointer to a mongocrypt_status_t # object to which an error message will be written if encryption fails. # @return [ Bool ] Whether hashing was successful. # # @note This defines a method signature for an FFI callback; it is not # an instance method on the Binding class. callback :mongocrypt_random_fn, [:pointer, :pointer, :int, :pointer], :bool # @!method self.mongocrypt_setopt_crypto_hooks(crypt, aes_enc_fn, aes_dec_fn, random_fn, sha_512_fn, sha_256_fn, hash_fn, ctx=nil) # @api private # # Set crypto hooks on the provided mongocrypt object. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ Proc ] aes_enc_fn An AES encryption method. # @param [ Proc ] aes_dec_fn An AES decryption method. # @param [ Proc ] random_fn A random method. # @param [ Proc ] sha_512_fn A HMAC SHA-512 method. # @param [ Proc ] sha_256_fn A HMAC SHA-256 method. # @param [ Proc ] hash_fn A SHA-256 hash method. # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object # that may have been set when hooks were enabled. # @return [ Boolean ] Whether setting this option succeeded. attach_function( :mongocrypt_setopt_crypto_hooks, [ :pointer, :mongocrypt_crypto_fn, :mongocrypt_crypto_fn, :mongocrypt_random_fn, :mongocrypt_hmac_fn, :mongocrypt_hmac_fn, :mongocrypt_hash_fn, :pointer ], :bool ) # Set crypto callbacks on the Handle # # @param [ Mongo::Crypt::Handle ] handle # @param [ Method ] aes_encrypt_cb An AES encryption method # @param [ Method ] aes_decrypt_cb A AES decryption method # @param [ Method ] random_cb A method that returns a string of random bytes # @param [ Method ] hmac_sha_512_cb A HMAC SHA-512 method # @param [ Method ] hmac_sha_256_cb A HMAC SHA-256 method # @param [ Method ] hmac_hash_cb A SHA-256 hash method # # @raise [ Mongo::Error::CryptError ] If the callbacks aren't set successfully def self.setopt_crypto_hooks(handle, aes_encrypt_cb, aes_decrypt_cb, random_cb, hmac_sha_512_cb, hmac_sha_256_cb, hmac_hash_cb ) check_status(handle) do mongocrypt_setopt_crypto_hooks(handle.ref, aes_encrypt_cb, aes_decrypt_cb, random_cb, hmac_sha_512_cb, hmac_sha_256_cb, hmac_hash_cb, nil ) end end # @!method self.mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(crypt, sign_rsaes_pkcs1_v1_5, ctx=nil) # @api private # # Set a crypto hook for the RSASSA-PKCS1-v1_5 algorithm with a SHA-256 hash. # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ Proc ] sign_rsaes_pkcs1_v1_5 A RSASSA-PKCS1-v1_5 signing method. # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object # that may have been set when hooks were enabled. # @return [ Boolean ] Whether setting this option succeeded. attach_function( :mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5, [ :pointer, :mongocrypt_hmac_fn, :pointer ], :bool ) # Set a crypto hook for the RSASSA-PKCS1-v1_5 algorithm with # a SHA-256 hash oh the Handle. # # @param [ Mongo::Crypt::Handle ] handle # @param [ Method ] rsaes_pkcs_signature_cb A RSASSA-PKCS1-v1_5 signing method. # # @raise [ Mongo::Error::CryptError ] If the callbacks aren't set successfully def self.setopt_crypto_hook_sign_rsaes_pkcs1_v1_5( handle, rsaes_pkcs_signature_cb ) check_status(handle) do mongocrypt_setopt_crypto_hook_sign_rsaes_pkcs1_v1_5( handle.ref, rsaes_pkcs_signature_cb, nil ) end end # @!method self.mongocrypt_setopt_encrypted_field_config_map(crypt, efc_map) # @api private # # Set a local EncryptedFieldConfigMap for encryption. # # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ FFI::Pointer ] efc_map A pointer to mongocrypt_binary_t object that # references a BSON document representing the EncryptedFieldConfigMap # supplied by the user. The keys are collection namespaces and values are # EncryptedFieldConfigMap documents. # # @return [ Boolean ] Whether the operation succeeded. attach_function( :mongocrypt_setopt_encrypted_field_config_map, [ :pointer, :pointer ], :bool ) # Set a local EncryptedFieldConfigMap for encryption. # # @param [ Mongo::Crypt::Handle ] handle # @param [ BSON::Document ] efc_map A BSON document representing # the EncryptedFieldConfigMap supplied by the user. # The keys are collection namespaces and values are # EncryptedFieldConfigMap documents. # # @raise [ Mongo::Error::CryptError ] If the operation failed. def self.setopt_encrypted_field_config_map(handle, efc_map) validate_document(efc_map) data = efc_map.to_bson.to_s Binary.wrap_string(data) do |data_p| check_status(handle) do mongocrypt_setopt_encrypted_field_config_map( handle.ref, data_p ) end end end # @!method self.mongocrypt_setopt_bypass_query_analysis(crypt) # @api private # # Opt into skipping query analysis. # # If opted in: # - The csfle shared library will not attempt to be loaded. # - A mongocrypt_ctx_t will never enter the MONGOCRYPT_CTX_NEED_MARKINGS state. # # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. attach_function(:mongocrypt_setopt_bypass_query_analysis, [:pointer], :void) # Opt-into skipping query analysis. # # If opted in: # - The csfle shared library will not attempt to be loaded. # - A mongocrypt_ctx_t will never enter the MONGOCRYPT_CTX_NEED_MARKINGS state. # # @param [ Mongo::Crypt::Handle ] handle def self.setopt_bypass_query_analysis(handle) mongocrypt_setopt_bypass_query_analysis(handle.ref) end # @!method self.mongocrypt_setopt_aes_256_ctr(crypt, aes_256_ctr_encrypt, aes_256_ctr_decrypt, ctx) # @api private # # Set a crypto hook for the AES256-CTR operations. # # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ Proc ] aes_enc_fn An AES-CTR encryption method. # @param [ Proc ] aes_dec_fn An AES-CTR decryption method. # @param [ FFI::Pointer | nil ] ctx An optional pointer to a context object # that may have been set when hooks were enabled. # @return [ Boolean ] Whether setting this option succeeded. attach_function( :mongocrypt_setopt_aes_256_ctr, [ :pointer, :mongocrypt_crypto_fn, :mongocrypt_crypto_fn, :pointer ], :bool ) # Set a crypto hook for the AES256-CTR operations. # # @param [ Mongo::Crypt::Handle ] handle # @param [ Method ] aes_encrypt_cb An AES-CTR encryption method # @param [ Method ] aes_decrypt_cb A AES-CTR decryption method # # @raise [ Mongo::Error::CryptError ] If the callbacks aren't set successfully def self.setopt_aes_256_ctr(handle, aes_ctr_encrypt_cb, aes_ctr_decrypt_cb) check_status(handle) do mongocrypt_setopt_aes_256_ctr(handle.ref, aes_ctr_encrypt_cb, aes_ctr_decrypt_cb, nil ) end end # @!method self.mongocrypt_setopt_append_crypt_shared_lib_search_path(crypt, path) # @api private # # Append an additional search directory to the search path for loading # the crypt_shared dynamic library. # # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ String ] path A path to search for the crypt shared library. If the leading element of # the path is the literal string "$ORIGIN", that substring will be replaced # with the directory path containing the executable libmongocrypt module. If # the path string is literal "$SYSTEM", then libmongocrypt will defer to the # system's library resolution mechanism to find the crypt_shared library. attach_function( :mongocrypt_setopt_append_crypt_shared_lib_search_path, [ :pointer, :string, ], :void ) # Append an additional search directory to the search path for loading # the crypt_shared dynamic library. # # @param [ Mongo::Crypt::Handle ] handle # @param [ String ] path A search path for the crypt shared library. def self.setopt_append_crypt_shared_lib_search_path(handle, path) check_status(handle) do mongocrypt_setopt_append_crypt_shared_lib_search_path(handle.ref, path) end end # @!method self.mongocrypt_setopt_set_crypt_shared_lib_path_override(crypt, path) # @api private # # Set a single override path for loading the crypt shared library. # # @param [ FFI::Pointer ] crypt A pointer to a mongocrypt_t object. # @param [ String ] path A path to crypt shared library file. If the leading element of # the path is the literal string "$ORIGIN", that substring will be replaced # with the directory path containing the executable libmongocrypt module. attach_function( :mongocrypt_setopt_set_crypt_shared_lib_path_override, [ :pointer, :string, ], :void ) # Set a single override path for loading the crypt shared library. # # @param [ Mongo::Crypt::Handle ] handle # @param [ String ] path A path to crypt shared library file. def self.setopt_set_crypt_shared_lib_path_override(handle, path) check_status(handle) do mongocrypt_setopt_set_crypt_shared_lib_path_override(handle.ref, path) end end # MONGOCRYPT_EXPORT # uint64_t # mongocrypt_crypt_shared_lib_version (const mongocrypt_t *crypt); attach_function( :mongocrypt_crypt_shared_lib_version, [ :pointer ], :uint64 ) def self.crypt_shared_lib_version(handle) mongocrypt_crypt_shared_lib_version(handle.ref) end # @!method self.mongocrypt_ctx_setopt_query_type(ctx, mongocrypt_query_type) # @api private # # Set the query type to use for FLE 2 explicit encryption. # The query type is only used for indexed FLE 2 encryption. # # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ String ] query_type Type of the query. # @param [ Integer ] len The length of the query type string. # # @return [ Boolean ] Whether setting this option succeeded. attach_function( :mongocrypt_ctx_setopt_query_type, [ :pointer, :string, :int ], :bool ) # Set the query type to use for FLE 2 explicit encryption. # The query type is only used for indexed FLE 2 encryption. # # @param [ Mongo::Crypt::Context ] context Explicit encryption context. # @param [ String ] :mongocrypt_query_type query_type Type of the query. # # @raise [ Mongo::Error::CryptError ] If the operation failed. def self.ctx_setopt_query_type(context, query_type) check_ctx_status(context) do mongocrypt_ctx_setopt_query_type(context.ctx_p, query_type, -1) end end # @!method self.mongocrypt_ctx_setopt_contention_factor(ctx, contention_factor) # @api private # # Set the contention factor used for explicit encryption. # The contention factor is only used for indexed FLE 2 encryption. # # @param [ FFI::Pointer ] ctx A pointer to a mongocrypt_ctx_t object. # @param [ int64 ] contention_factor # # @return [ Boolean ] Whether setting this option succeeded. attach_function( :mongocrypt_ctx_setopt_contention_factor, [ :pointer, :int64 ], :bool ) # Set the contention factor used for explicit encryption. # The contention factor is only used for indexed FLE 2 encryption. # # @param [ Mongo::Crypt::Context ] context Explicit encryption context. # @param [ Integer ] factor Contention factor used for explicit encryption. # # @raise [ Mongo::Error::CryptError ] If the operation failed. def self.ctx_setopt_contention_factor(context, factor) check_ctx_status(context) do mongocrypt_ctx_setopt_contention_factor(context.ctx_p, factor) end end # Raise a Mongo::Error::CryptError based on the status of the underlying # mongocrypt_t object. # # @return [ nil ] Always nil. def self.check_status(handle) unless yield status = Status.new mongocrypt_status(handle.ref, status.ref) status.raise_crypt_error end end # Raise a Mongo::Error::CryptError based on the status of the underlying # mongocrypt_ctx_t object. # # @return [ nil ] Always nil. def self.check_ctx_status(context) if block_given? do_raise = !yield else do_raise = true end if do_raise status = Status.new mongocrypt_ctx_status(context.ctx_p, status.ref) status.raise_crypt_error end end # Checks that the specified data is a Hash before serializing # it to BSON to prevent errors from libmongocrypt # # @note All BSON::Document instances are also Hash instances # # @param [ Object ] data The data to be passed to libmongocrypt # # @raise [ Mongo::Error::CryptError ] If the data is not a Hash def self.validate_document(data) return if data.is_a?(Hash) if data.nil? message = "Attempted to pass nil data to libmongocrypt. " + "Data must be a Hash" else message = "Attempted to pass invalid data to libmongocrypt: #{data} " + "Data must be a Hash" end raise Error::CryptError.new(message) end end end end