P11ex.Module (p11ex v0.1.1)

A module is a GenServer that manages a PKCS#11 module and its loading state. A PKCS#11 module is a shared library that implements a PKCS#11 provider. A module should be loaded only once per application or beam virtual machine. That is, you should only create one instance of P11ex.Module in your application and add it to your supervision tree. Operations on the module should be performed through the GenServer callbacks so that they are serialized.

Loading a module

To load a module, you can use the start_link/1 function. The argument is the path to the module file. The module will be loaded and initialized.

defmodule MyApp.Supervisor do
  use Supervisor

  def start_link(init_arg) do
    Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  def init(init_arg) do
    children = [
      {P11ex.Module, "/usr/lib/softhsm/libsofthsm2.so"}
    ]
    Supervisor.init(children, strategy: :one_for_one)
  end
end

Summary

Functions

Returns a specification to start this module under a supervisor.

Find the slot that contains a token with the given label.

List all mechanisms supported by the PKCS#11 module for a slot. This function has two variants

List all slots in the module. The token_present? argument is optional and defaults to true. If set to true, only slots with a token present are returned.

Check if a successful login has been registered for a token in the PKCS#11 slot managed by this instance of P11ex.Module. The return value is :user or :so (security officer) if a login has been registered, or nil if no login has been registered.

Get information about a mechanism for a given slot. The mechanism is specified as an atom or an integer. For example, the mechanism :ckm_aes_cbc can also be specified as the integer 0x00001082

Returns a reference to the handle of the PKCS#11 module. Usually, this is not needed by the application, but it can be useful if you need to perform operations on the module that are not otherwise provided by this library.

Register a successful login for a token in the PKCS#11 slot managed by this instance of P11ex.Module. User type is :user or :so (security officer). If set, subsequent operations on the token will be skipped. This is necessary to avoid login errors of value :ckr_user_already_logged_in. Can also be set to nil to unregister a login.

Start the P11ex.Module GenServer. The argument is the path to the PKCS#11 module file (shared library).

Get information about a token in a slot. This function has two variants

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

find_slot_by_tokenlabel(label)

@spec find_slot_by_tokenlabel(binary()) ::
  {:ok, P11ex.Lib.Slot.t()} | {:ok, nil} | {:error, atom()}

Find the slot that contains a token with the given label.

list_mechanisms(slot_id)

@spec list_mechanisms(non_neg_integer()) ::
  {:ok, [atom() | non_neg_integer()]} | {:error, atom()}
@spec list_mechanisms(P11ex.Lib.Slot.t()) ::
  {:ok, [atom() | non_neg_integer()]} | {:error, atom()}

List all mechanisms supported by the PKCS#11 module for a slot. This function has two variants:

  1. list_mechanisms(slot_id) - List mechanisms using a slot ID
  2. list_mechanisms(slot) - List mechanisms using a Slot struct

The mechanisms are returned as a list of atoms. If the mechanism is not known to P11ex (e.g. a vendor specific mechanism), it will be returned as an integer.

list_slots(token_present?)

@spec list_slots(boolean()) :: {:ok, [P11ex.Lib.Slot.t()]} | {:error, atom()}

List all slots in the module. The token_present? argument is optional and defaults to true. If set to true, only slots with a token present are returned.

login_type()

@spec login_type() :: atom() | nil

Check if a successful login has been registered for a token in the PKCS#11 slot managed by this instance of P11ex.Module. The return value is :user or :so (security officer) if a login has been registered, or nil if no login has been registered.

mechanism_info(slot, mechanism_type)

@spec mechanism_info(P11ex.Lib.Slot.t(), atom() | non_neg_integer()) ::
  {:ok, map()} | {:error, atom()}

Get information about a mechanism for a given slot. The mechanism is specified as an atom or an integer. For example, the mechanism :ckm_aes_cbc can also be specified as the integer 0x00001082:

{:ok, info} = P11ex.Module.mechanism_info(slot, :ckm_aes_cbc)
{:ok, info} = P11ex.Module.mechanism_info(slot, 0x00001082)

The return value is a map with the following keys:

  • flags - The flags of the mechanism (a list of atoms, see P11ex.Flags). This indicates for what operations the mechanism can be used, e.g. :encrypt, :decrypt, :sign, :verify, etc.
  • min_length - The minimum key length supported by the mechanism (an integer)
  • max_length - The maximum key length supported by the mechanism (an integer)

For example, for :ckm_aes_cbc a typical return value is:

%{flags: MapSet.new([:wrap, :encrypt, :decrypt]), min_length: 16, max_length: 32}

If the mechanism is not known, the return value is {:error, {:C_GetMechanismInfo, :ckr_mechanism_invalid}}.

module_handle()

@spec module_handle() :: reference()

Returns a reference to the handle of the PKCS#11 module. Usually, this is not needed by the application, but it can be useful if you need to perform operations on the module that are not otherwise provided by this library.

open_session(slot, flags)

register_login(user_type)

@spec register_login(atom() | nil) :: :ok

Register a successful login for a token in the PKCS#11 slot managed by this instance of P11ex.Module. User type is :user or :so (security officer). If set, subsequent operations on the token will be skipped. This is necessary to avoid login errors of value :ckr_user_already_logged_in. Can also be set to nil to unregister a login.

start_link(args)

@spec start_link(binary()) :: GenServer.on_start()

Start the P11ex.Module GenServer. The argument is the path to the PKCS#11 module file (shared library).

token_info(slot_id)

@spec token_info(non_neg_integer()) :: {:ok, map()} | {:error, atom()}
@spec token_info(P11ex.Lib.Slot.t()) :: {:ok, map()} | {:error, atom()}

Get information about a token in a slot. This function has two variants:

  1. token_info(slot_id) - Get token info using a slot ID
  2. token_info(slot) - Get token info using a Slot struct

The token information is based on the PKCS#11 structure CK_TOKEN_INFO and contains the following fields:

  • label - The label of the token (a string)
  • manufacturer_id - The manufacturer ID of the token (a string)
  • model - The model of the token (a string)
  • serial_number - The serial number of the token (a string)
  • flags - The flags of the token (a list of atoms, see P11ex.Flags)
  • max_session_count - The maximum number of sessions that can be opened for the token (an integer)
  • session_count - The number of sessions that are currently open for the token (an integer)
  • max_rw_session_count - The maximum number of read/write sessions that can be opened for the token (an integer)
  • rw_session_count - The number of read/write sessions that are currently open for the token (an integer)
  • max_pin_len - The maximum length of the PIN for the token (an integer)
  • min_pin_len - The minimum length of the PIN for the token (an integer)
  • total_public_memory - The total amount of public memory in the token (an integer)
  • free_public_memory - The amount of free public memory in the token (an integer)
  • total_private_memory - The total amount of private memory in the token (an integer)
  • free_private_memory - The amount of free private memory in the token (an integer)
  • hardware_version - The hardware version of the token (a tuple of integers)
  • firmware_version - The firmware version of the token (a tuple of integers)
  • utc_time - The UTC time of the token (a string)