Class: NETSNMP::SecurityParameters

Inherits:
Object
  • Object
show all
Defined in:
lib/netsnmp/security_parameters.rb

Overview

This module encapsulates the public API for encrypting/decrypting and signing/verifying.

It doesn’t interact with other layers from the library, rather it is used and passed all the arguments (consisting mostly of primitive types). It also provides validation of the security options passed with a client is initialized in v3 mode.

Constant Summary collapse

IPAD =
"\x36" * 64
OPAD =
"\x5c" * 64
TIMELINESS_THRESHOLD =

Timeliness is part of SNMP V3 Security The topic is described very nice here www.snmpsharpnet.com/?page_id=28 www.ietf.org/rfc/rfc2574.txt 1.4.1 Timeliness The probe is outdated after 150 seconds which results in a PDU Error, therefore it should expire before that and be renewed The 150 Seconds is specified in www.ietf.org/rfc/rfc2574.txt 2.2.3

150

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(username:, engine_id: "", security_level: nil, auth_protocol: nil, auth_password: nil, priv_protocol: nil, priv_password: nil) ⇒ SecurityParameters

Note:

if security level is set to :no_auth_no_priv, all other parameters are optional; if :auth_no_priv, :auth_protocol will be coerced to :md5 (if not explicitly set), and :auth_password is mandatory; if :auth_priv, the sentence before applies, and :priv_protocol will be coerced to :des (if not explicitly set), and :priv_password becomes mandatory.

Returns a new instance of SecurityParameters.

Parameters:

  • username (String)

    the snmp v3 username

  • engine_id (String) (defaults to: "")

    the device engine id (initialized to ” for report)

  • security_level (Symbol, integer) (defaults to: nil)

    allowed snmp v3 security level (:auth_priv, :auth_no_priv, etc)

  • auth_protocol (Symbol, nil) (defaults to: nil)

    a supported authentication protocol (currently supported: :md5, :sha)

  • priv_protocol (Symbol, nil) (defaults to: nil)

    a supported privacy protocol (currently supported: :des, :aes)

  • auth_password (String, nil) (defaults to: nil)

    the authentication password

  • priv_password (String, nil) (defaults to: nil)

    the privacy password



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/netsnmp/security_parameters.rb', line 38

def initialize(
               username:,
               engine_id: "",
               security_level: nil,
               auth_protocol: nil,
               auth_password: nil,
               priv_protocol: nil,
               priv_password: nil
)
  @security_level = security_level
  @username = username
  @engine_id = engine_id
  @auth_protocol = auth_protocol.to_sym unless auth_protocol.nil?
  @priv_protocol = priv_protocol.to_sym unless priv_protocol.nil?
  @auth_password = auth_password
  @priv_password = priv_password
  check_parameters
  @auth_pass_key = passkey(@auth_password) unless @auth_password.nil?
  @priv_pass_key = passkey(@priv_password) unless @priv_password.nil?
end

Instance Attribute Details

#engine_idObject

Returns the value of attribute engine_id.



23
24
25
# File 'lib/netsnmp/security_parameters.rb', line 23

def engine_id
  @engine_id
end

#security_levelObject (readonly)

Returns the value of attribute security_level.



22
23
24
# File 'lib/netsnmp/security_parameters.rb', line 22

def security_level
  @security_level
end

#usernameObject (readonly)

Returns the value of attribute username.



22
23
24
# File 'lib/netsnmp/security_parameters.rb', line 22

def username
  @username
end

Instance Method Details

#decode(der, salt:, engine_time:, engine_boots:) ⇒ Object

Parameters:

  • der (String)

    the encoded der to be decoded

  • salt (String)

    the salt from the incoming der

  • engine_time (Integer)

    the reported engine time

  • engine_boots (Integer)

    the reported engine boots



85
86
87
88
89
90
91
92
93
94
# File 'lib/netsnmp/security_parameters.rb', line 85

def decode(der, salt:, engine_time:, engine_boots:)
  asn = OpenSSL::ASN1.decode(der)
  if encryption
    encrypted_pdu = asn.value
    pdu_der = encryption.decrypt(encrypted_pdu, salt: salt, engine_time: engine_time, engine_boots: engine_boots)
    OpenSSL::ASN1.decode(pdu_der)
  else
    asn
  end
end

#encode(pdu, salt:, engine_time:, engine_boots:) ⇒ Array

Returns a pair, where the first argument in the asn structure with the encoded pdu, and the second is the calculated salt (if it has been encrypted).

Parameters:

  • pdu (#to_asn, #to_der)

    the pdu to encode (must quack like a asn1 type)

  • salt (String)

    the salt to use

  • engine_time (Integer)

    the reported engine time

  • engine_boots (Integer)

    the reported boots time

Returns:

  • (Array)

    a pair, where the first argument in the asn structure with the encoded pdu, and the second is the calculated salt (if it has been encrypted)



71
72
73
74
75
76
77
78
79
# File 'lib/netsnmp/security_parameters.rb', line 71

def encode(pdu, salt:, engine_time:, engine_boots:)
  if encryption
    encrypted_pdu, salt = encryption.encrypt(pdu.to_der, engine_boots: engine_boots,
                                                         engine_time: engine_time)
    [OpenSSL::ASN1::OctetString.new(encrypted_pdu), OpenSSL::ASN1::OctetString.new(salt)]
  else
    [pdu.to_asn, salt]
  end
end

#must_revalidate?Boolean

Returns:

  • (Boolean)


129
130
131
132
133
# File 'lib/netsnmp/security_parameters.rb', line 129

def must_revalidate?
  return @engine_id.empty? unless authorizable?
  return true if @engine_id.empty? || @timeliness.nil?
  (Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) - @timeliness) >= TIMELINESS_THRESHOLD
end

#sign(message) ⇒ String

Note:

this method is used in the process of authenticating a message

Returns the digest signature of the message payload.

Parameters:

  • message (String)

    the already encoded snmp v3 message

Returns:

  • (String)

    the digest signature of the message payload



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/netsnmp/security_parameters.rb', line 100

def sign(message)
  # don't sign unless you have to
  return unless @auth_protocol

  key = auth_key.dup

  key << "\x00" * (@auth_protocol == :md5 ? 48 : 44)
  k1 = key.xor(IPAD)
  k2 = key.xor(OPAD)

  digest.reset
  digest << (k1 + message)
  d1 = digest.digest

  digest.reset
  digest << (k2 + d1)
  digest.digest[0, 12]
end

#verify(stream, salt) ⇒ Object

Parameters:

  • stream (String)

    the encoded incoming payload

  • salt (String)

    the incoming payload”s salt

Raises:

  • (NETSNMP::Error)

    if the message’s integration has been violated



123
124
125
126
127
# File 'lib/netsnmp/security_parameters.rb', line 123

def verify(stream, salt)
  return if @security_level < 1
  verisalt = sign(stream)
  raise Error, "invalid message authentication salt" unless verisalt == salt
end