123456789_123456789_123456789_123456789_123456789_

Class: Mongo::Crypt::Handle Private

Do not use. This class is for internal use only.
Relationships & Source Files
Inherits: Object
Defined in: lib/mongo/crypt/handle.rb

Overview

A handle to the libmongocrypt library that wraps a mongocrypt_t object, allowing clients to set options on that object or perform operations such as encryption and decryption

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Instance Attribute Details

#crypt_shared_lib_available?Boolean (readonly)

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 136

def crypt_shared_lib_available?
  crypt_shared_lib_version != 0
end

#kms_providers (readonly)

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 32

attr_reader :kms_providers

Instance Method Details

#crypt_shared_lib_version

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 132

def crypt_shared_lib_version
  Binding.crypt_shared_lib_version(self)
end

#do_aes(key_binary_p, iv_binary_p, input_binary_p, output_binary_p, response_length_p, status_p, decrypt: false, mode: :CBC) (private)

Perform AES encryption or decryption and write the output to the provided mongocrypt_binary_t object.

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 244

def do_aes(key_binary_p, iv_binary_p, input_binary_p, output_binary_p,
  response_length_p, status_p, decrypt: false, mode: :CBC)
  key = Binary.from_pointer(key_binary_p).to_s
  iv = Binary.from_pointer(iv_binary_p).to_s
  input = Binary.from_pointer(input_binary_p).to_s

  write_binary_string_and_set_status(output_binary_p, status_p) do
    output = Hooks.aes(key, iv, input, decrypt: decrypt, mode: mode)
    response_length_p.write_int(output.bytesize)

    output
  end
end

#do_hmac_sha(digest_name, key_binary_p, input_binary_p, output_binary_p, status_p) (private)

Perform HMAC SHA encryption and write the output to the provided mongocrypt_binary_t object.

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 260

def do_hmac_sha(digest_name, key_binary_p, input_binary_p,
  output_binary_p, status_p)
  key = Binary.from_pointer(key_binary_p).to_s
  input = Binary.from_pointer(input_binary_p).to_s

  write_binary_string_and_set_status(output_binary_p, status_p) do
    Hooks.hmac_sha(digest_name, key, input)
  end
end

#do_rsaes_pkcs_signature(key_binary_p, input_binary_p, output_binary_p, status_p) (private)

Perform signing using RSASSA-PKCS1-v1_5 with SHA256 hash and write the output to the provided mongocrypt_binary_t object.

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 272

def do_rsaes_pkcs_signature(key_binary_p, input_binary_p,
  output_binary_p, status_p)
  key = Binary.from_pointer(key_binary_p).to_s
  input = Binary.from_pointer(input_binary_p).to_s

  write_binary_string_and_set_status(output_binary_p, status_p) do
    Hooks.rsaes_pkcs_signature(key, input)
  end
end

#handle_error(status_p) ⇒ true | false (private)

Yields to the provided block and rescues exceptions raised by the block. If an exception was raised, sets the specified status to the exception message and returns false. If no exceptions were raised, does not modify the status and returns true.

This method is meant to be used with libmongocrypt callbacks and follows the API defined by libmongocrypt.

Parameters:

  • status_p (FFI::Pointer)

    A pointer to libmongocrypt status object

Returns:

  • (true | false)

    Whether block executed without raising exceptions.

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 209

def handle_error(status_p)
  begin
    yield

    true
  rescue => e
    status = Status.from_pointer(status_p)
    status.update(:error_client, 1, "#{e.class}: #{e}")
    false
  end
end

#initialize_mongocrypt (private)

Initialize the underlying mongocrypt_t object and raise an error if the operation fails

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 394

def initialize_mongocrypt
  Binding.init(self)
  # There is currently no test for the error(?) code path
end

#kms_tls_options(provider) ⇒ Hash

Return TLS options for KMS provider. If there are no TLS options set, empty hash is returned.

Parameters:

  • provider (String)

    KSM provider name.

Returns:

  • (Hash)

    TLS options to connect to KMS provider.

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 128

def kms_tls_options(provider)
  @kms_tls_options.fetch(provider, {})
end

#maybe_set_schema_map(options) (private)

Set the schema map option on the underlying mongocrypt_t object

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 143

def maybe_set_schema_map(options)
  if !options[:schema_map] && !options[:schema_map_path]
    @schema_map = nil
  elsif options[:schema_map] && options[:schema_map_path]
    raise ArgumentError.new(
      "Cannot set both schema_map and schema_map_path options."
    )
  elsif options[:schema_map]
    unless options[:schema_map].is_a?(Hash)
      raise ArgumentError.new(
        "#{@schema_map} is an invalid schema_map; schema_map must be a Hash or nil."
      )
    end
    @schema_map = options[:schema_map]
    Binding.setopt_schema_map(self, @schema_map)
  elsif options[:schema_map_path]
    @schema_map = BSON::ExtJSON.parse(File.read(options[:schema_map_path]))
    Binding.setopt_schema_map(self, @schema_map)
  end
rescue Errno::ENOENT
  raise ArgumentError.new(
    "#{@schema_map_path} is an invalid path to a file contains schema_map."
  )
end

#refFFI::Pointer

Return the reference to the underlying @mongocrypt object

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 118

def ref
  @mongocrypt
end

#set_bypass_query_analysis (private)

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 178

def set_bypass_query_analysis
  unless [true, false].include?(@bypass_query_analysis)
    raise ArgumentError.new(
      "#{@bypass_query_analysis} is an invalid bypass_query_analysis value; must be a Boolean or nil"
    )
  end

  Binding.setopt_bypass_query_analysis(self) if @bypass_query_analysis
end

#set_crypto_hooks (private)

We are building libmongocrypt without crypto functions to remove the external dependency on OpenSSL. This method binds native Ruby crypto methods to the underlying mongocrypt_t object so that libmongocrypt can still perform cryptography.

Every crypto binding ignores its first argument, which is an option mongocrypt_ctx_t object and is not required to use crypto hooks.

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 289

def set_crypto_hooks
  @aes_encrypt = Proc.new do |_, key_binary_p, iv_binary_p, input_binary_p,
    output_binary_p, response_length_p, status_p|
    do_aes(
      key_binary_p,
      iv_binary_p,
      input_binary_p,
      output_binary_p,
      response_length_p,
      status_p
    )
  end

  @aes_decrypt = Proc.new do |_, key_binary_p, iv_binary_p, input_binary_p,
    output_binary_p, response_length_p, status_p|
    do_aes(
      key_binary_p,
      iv_binary_p,
      input_binary_p,
      output_binary_p,
      response_length_p,
      status_p,
      decrypt: true
    )
  end

  @random = Proc.new do |_, output_binary_p, num_bytes, status_p|
    write_binary_string_and_set_status(output_binary_p, status_p) do
      Hooks.random(num_bytes)
    end
  end

  @hmac_sha_512 = Proc.new do |_, key_binary_p, input_binary_p,
    output_binary_p, status_p|
    do_hmac_sha('SHA512', key_binary_p, input_binary_p, output_binary_p, status_p)
  end

  @hmac_sha_256 = Proc.new do |_, key_binary_p, input_binary_p,
    output_binary_p, status_p|
    do_hmac_sha('SHA256', key_binary_p, input_binary_p, output_binary_p, status_p)
  end

  @hmac_hash = Proc.new do |_, input_binary_p, output_binary_p, status_p|
    input = Binary.from_pointer(input_binary_p).to_s

    write_binary_string_and_set_status(output_binary_p, status_p) do
      Hooks.hash_sha256(input)
    end
  end

  Binding.setopt_crypto_hooks(
    self,
    @aes_encrypt,
    @aes_decrypt,
    @random,
    @hmac_sha_512,
    @hmac_sha_256,
    @hmac_hash,
  )

  @aes_ctr_encrypt = Proc.new do |_, key_binary_p, iv_binary_p, input_binary_p,
    output_binary_p, response_length_p, status_p|
    do_aes(
      key_binary_p,
      iv_binary_p,
      input_binary_p,
      output_binary_p,
      response_length_p,
      status_p,
      mode: :CTR,
    )
  end

  @aes_ctr_decrypt = Proc.new do |_, key_binary_p, iv_binary_p, input_binary_p,
    output_binary_p, response_length_p, status_p|
    do_aes(
      key_binary_p,
      iv_binary_p,
      input_binary_p,
      output_binary_p,
      response_length_p,
      status_p,
      decrypt: true,
      mode: :CTR,
    )
  end

  Binding.setopt_aes_256_ctr(
    self,
    @aes_ctr_encrypt,
    @aes_ctr_decrypt,
  )

  @rsaes_pkcs_signature_cb = Proc.new do |_, key_binary_p, input_binary_p,
    output_binary_p, status_p|
    do_rsaes_pkcs_signature(key_binary_p, input_binary_p, output_binary_p, status_p)
  end

  Binding.setopt_crypto_hook_sign_rsaes_pkcs1_v1_5(
    self,
    @rsaes_pkcs_signature_cb
  )
end

#set_encrypted_fields_map (private)

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 168

def set_encrypted_fields_map
  unless @encrypted_fields_map.is_a?(Hash)
    raise ArgumentError.new(
      "#{@encrypted_fields_map} is an invalid encrypted_fields_map: must be a Hash or nil"
    )
  end

  Binding.setopt_encrypted_field_config_map(self, @encrypted_fields_map)
end

#set_logger_callback (private)

Send the logs from libmongocrypt to the ::Mongo::Logger

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 189

def set_logger_callback
  @log_callback = Proc.new do |level, msg|
    @logger.send(level, msg)
  end

  Binding.setopt_log_handler(@mongocrypt, @log_callback)
end

#write_binary_string_and_set_status(output_binary_p, status_p) ⇒ true | false (private)

Yields to the provided block and writes the return value of block to the specified mongocrypt_binary_t object. If an exception is raised during execution of the block, writes the exception message to the specified status object and returns false. If no exception is raised, does not modify status and returns true. message to the mongocrypt_status_t object.

Parameters:

  • output_binary_p (FFI::Pointer)

    A pointer to libmongocrypt Binary object to receive the result of block’s execution

  • status_p (FFI::Pointer)

    A pointer to libmongocrypt status object

Returns:

  • (true | false)

    Whether block executed without raising exceptions.

[ GitHub ]

  
# File 'lib/mongo/crypt/handle.rb', line 234

def write_binary_string_and_set_status(output_binary_p, status_p)
  handle_error(status_p) do
    output = yield

    Binary.from_pointer(output_binary_p).write(output)
  end
end