SnmpKit.SnmpLib.Security.USM (snmpkit v0.6.4)

User Security Model (USM) implementation for SNMPv3 - RFC 3414 compliant.

The User Security Model provides the foundation for SNMPv3 security by implementing:

  • User-based authentication with multiple protocols
  • Privacy (encryption) for message confidentiality
  • Time synchronization to prevent replay attacks
  • Engine discovery for secure agent communication
  • Security parameter validation and error handling

RFC 3414 Compliance

This implementation fully complies with RFC 3414 "User-based Security Model (USM) for version 3 of the Simple Network Management Protocol (SNMPv3)" including:

  • Message authentication using HMAC-MD5 and HMAC-SHA
  • Privacy using DES and AES encryption
  • Key derivation using password localization
  • Time window validation for message freshness
  • Engine ID discovery and management

Architecture

The USM coordinates with other security modules:

SnmpKit.SnmpLib.Security.USM
 Auth protocols (MD5, SHA variants)
 Priv protocols (DES, AES variants)
 Key derivation and management
 Engine and time management

Usage Examples

Engine Discovery

# Discover remote engine for secure communication
{:ok, engine_id} = SnmpKit.SnmpLib.Security.USM.discover_engine("192.168.1.1")

# Time synchronization
{:ok, {boots, time}} = SnmpKit.SnmpLib.Security.USM.synchronize_time("192.168.1.1", engine_id)

Message Processing

# Process outgoing secure message
{:ok, secure_message} = SnmpKit.SnmpLib.Security.USM.process_outgoing_message(
  user, message, security_level
)

# Process incoming secure message
{:ok, {plain_message, user}} = SnmpKit.SnmpLib.Security.USM.process_incoming_message(
  secure_message, user_database
)

Security Considerations

  • Engine boot counters must be persistent across restarts
  • Time synchronization is critical for security
  • Failed authentication attempts should be logged
  • Key material should never be logged or persisted in plain text

Summary

Functions

Discovers the engine ID of a remote SNMP agent.

Generates security error reports for invalid messages.

Calculates current engine time since boot.

Updates engine boot counter, handling rollover at maximum value.

Processes an incoming SNMP message with USM security.

Processes an outgoing SNMP message with USM security.

Synchronizes time with a remote SNMP agent.

Validates time-based security parameters to prevent replay attacks.

Types

engine_boots()

@type engine_boots() :: non_neg_integer()

engine_id()

@type engine_id() :: binary()

engine_time()

@type engine_time() :: non_neg_integer()

message_flags()

@type message_flags() :: %{
  auth_flag: boolean(),
  priv_flag: boolean(),
  reportable_flag: boolean()
}

security_level()

@type security_level() :: :no_auth_no_priv | :auth_no_priv | :auth_priv

security_name()

@type security_name() :: binary()

security_parameters()

@type security_parameters() :: %{
  authoritative_engine_id: engine_id(),
  authoritative_engine_boots: engine_boots(),
  authoritative_engine_time: engine_time(),
  user_name: security_name(),
  authentication_parameters: binary(),
  privacy_parameters: binary()
}

user_entry()

@type user_entry() :: %{
  security_name: security_name(),
  auth_protocol: atom(),
  priv_protocol: atom(),
  auth_key: binary(),
  priv_key: binary(),
  engine_id: engine_id()
}

Functions

discover_engine(host, opts \\ [])

@spec discover_engine(
  binary(),
  keyword()
) :: {:ok, engine_id()} | {:error, atom()}

Discovers the engine ID of a remote SNMP agent.

Engine discovery is the first step in establishing secure communication with a remote SNMPv3 agent. This function sends a discovery request and retrieves the agent's authoritative engine ID.

Parameters

  • host: Target agent IP address or hostname
  • opts: Discovery options including port, timeout, and community

Returns

  • {:ok, engine_id}: Successfully discovered engine ID
  • {:error, reason}: Discovery failed

Examples

{:ok, engine_id} = SnmpKit.SnmpLib.Security.USM.discover_engine("192.168.1.1")
{:ok, engine_id} = SnmpKit.SnmpLib.Security.USM.discover_engine("10.0.0.1", port: 1161, timeout: 5000)

generate_error_report(error_type, context)

@spec generate_error_report(atom(), map()) :: {:ok, binary()} | {:error, atom()}

Generates security error reports for invalid messages.

USM error reports are sent back to the originator to indicate security violations or configuration issues.

get_engine_time(boot_timestamp)

@spec get_engine_time(non_neg_integer()) :: engine_time()

Calculates current engine time since boot.

increment_engine_boots(current_boots)

@spec increment_engine_boots(engine_boots()) :: engine_boots()

Updates engine boot counter, handling rollover at maximum value.

process_incoming_message(secure_message, user_database)

@spec process_incoming_message(binary(), map()) ::
  {:ok, {binary(), user_entry()}} | {:error, atom()}

Processes an incoming SNMP message with USM security.

This function validates and decrypts an incoming secure message, returning the plain message content and validated user information.

process_outgoing_message(user, message, security_level)

@spec process_outgoing_message(user_entry(), binary(), security_level()) ::
  {:ok, binary()} | {:error, atom()}

Processes an outgoing SNMP message with USM security.

This function applies authentication and/or privacy protection to an outgoing message based on the user's security level configuration.

synchronize_time(host, engine_id, opts \\ [])

@spec synchronize_time(binary(), engine_id(), keyword()) ::
  {:ok, {engine_boots(), engine_time()}} | {:error, atom()}

Synchronizes time with a remote SNMP agent.

Time synchronization is required for authenticated communication to prevent replay attacks. This function retrieves the agent's current boot counter and engine time.

validate_time_window(local_boots, local_time, remote_boots, remote_time)

@spec validate_time_window(
  engine_boots(),
  engine_time(),
  engine_boots(),
  engine_time()
) ::
  :ok | {:error, atom()}

Validates time-based security parameters to prevent replay attacks.

Per RFC 3414, messages are considered fresh if:

  • Engine boots match (within 1)
  • Engine time is within 150 seconds