Class: NETSNMP::SecurityParameters
- Inherits:
-
Object
- Object
- NETSNMP::SecurityParameters
- Includes:
- Loggable
- 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
Constants included from Loggable
Loggable::DEBUG, Loggable::DEBUG_LEVEL
Instance Attribute Summary collapse
-
#auth_protocol ⇒ Object
readonly
Returns the value of attribute auth_protocol.
-
#engine_id ⇒ Object
Returns the value of attribute engine_id.
-
#security_level ⇒ Object
readonly
Returns the value of attribute security_level.
-
#username ⇒ Object
readonly
Returns the value of attribute username.
Instance Method Summary collapse
- #decode(der, salt:, engine_time:, engine_boots:, security_level: @security_level) ⇒ Object
-
#encode(pdu, salt:, engine_time:, engine_boots:) ⇒ 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).
-
#initialize(username:, engine_id: "", security_level: nil, auth_protocol: nil, auth_password: nil, priv_protocol: nil, priv_password: nil, **options) ⇒ SecurityParameters
constructor
A new instance of SecurityParameters.
- #must_revalidate? ⇒ Boolean
-
#sign(message) ⇒ String
The digest signature of the message payload.
- #verify(stream, salt, security_level: @security_level) ⇒ Object
Methods included from Loggable
Constructor Details
#initialize(username:, engine_id: "", security_level: nil, auth_protocol: nil, auth_password: nil, priv_protocol: nil, priv_password: nil, **options) ⇒ SecurityParameters
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.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/netsnmp/security_parameters.rb', line 40 def initialize( username:, engine_id: "", security_level: nil, auth_protocol: nil, auth_password: nil, priv_protocol: nil, priv_password: nil, ** ) @security_level = case security_level when /no_?auth/ then 0 when /auth_?no_?priv/ then 1 when /auth_?priv/ then 3 when Integer then security_level else 3 # rubocop:disable Lint/DuplicateBranch end @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? if @security_level.positive? @auth_protocol ||= :md5 # this is the default raise "security level requires an auth password" if auth_password.nil? raise "auth password must have between 8 to 32 characters" unless (8..32).cover?(auth_password.length) end if @security_level > 1 @priv_protocol ||= :des raise "security level requires a priv password" if priv_password.nil? raise "priv password must have between 8 to 32 characters" unless (8..32).cover?(priv_password.length) end @auth_pass_key = passkey(auth_password) if auth_password @priv_pass_key = passkey(priv_password) if priv_password initialize_logger(**) end |
Instance Attribute Details
#auth_protocol ⇒ Object (readonly)
Returns the value of attribute auth_protocol.
25 26 27 |
# File 'lib/netsnmp/security_parameters.rb', line 25 def auth_protocol @auth_protocol end |
#engine_id ⇒ Object
Returns the value of attribute engine_id.
25 26 27 |
# File 'lib/netsnmp/security_parameters.rb', line 25 def engine_id @engine_id end |
#security_level ⇒ Object (readonly)
Returns the value of attribute security_level.
25 26 27 |
# File 'lib/netsnmp/security_parameters.rb', line 25 def security_level @security_level end |
#username ⇒ Object (readonly)
Returns the value of attribute username.
25 26 27 |
# File 'lib/netsnmp/security_parameters.rb', line 25 def username @username end |
Instance Method Details
#decode(der, salt:, engine_time:, engine_boots:, security_level: @security_level) ⇒ Object
110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/netsnmp/security_parameters.rb', line 110 def decode(der, salt:, engine_time:, engine_boots:, security_level: @security_level) asn = OpenSSL::ASN1.decode(der) return asn if security_level < 3 encryptor = encryption return asn unless encryptor encrypted_pdu = asn.value pdu_der = encryptor.decrypt(encrypted_pdu, salt: salt, engine_time: engine_time, engine_boots: engine_boots) log(level: 2) { "message has been decrypted" } OpenSSL::ASN1.decode(pdu_der) 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).
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/netsnmp/security_parameters.rb', line 91 def encode(pdu, salt:, engine_time:, engine_boots:) encryptor = encryption if encryptor encrypted_pdu, salt = encryptor.encrypt(pdu.to_der, engine_boots: engine_boots, engine_time: engine_time) [ OpenSSL::ASN1::OctetString.new(encrypted_pdu).with_label(:encrypted_pdu), OpenSSL::ASN1::OctetString.new(salt).with_label(:salt) ] else [pdu.to_asn, salt] end end |
#must_revalidate? ⇒ Boolean
178 179 180 181 182 183 |
# File 'lib/netsnmp/security_parameters.rb', line 178 def must_revalidate? return @engine_id.empty? unless return true if @engine_id.empty? || @timeliness.nil? (Process.clock_gettime(Process::CLOCK_MONOTONIC, :second) - @timeliness) >= TIMELINESS_THRESHOLD end |
#sign(message) ⇒ String
this method is used in the process of authenticating a message
Returns the digest signature of the message payload.
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/netsnmp/security_parameters.rb', line 127 def sign() # don't sign unless you have to return unless @auth_protocol key = auth_key.dup case @auth_protocol when :sha224 return OpenSSL::HMAC.digest("SHA224", key, )[0, 16] when :sha384 return OpenSSL::HMAC.digest("SHA384", key, )[0, 32] when :sha256 # The 24 first octets of HMAC are taken as the computed MAC value # SHA256 => https://datatracker.ietf.org/doc/html/rfc7860#section-4.2.2 return OpenSSL::HMAC.digest("SHA256", key, )[0, 24] when :sha512 return OpenSSL::HMAC.digest("SHA512", key, )[0, 48] when :md5 # MD5 => https://datatracker.ietf.org/doc/html/rfc3414#section-6.3.2 key << ("\x00" * 48) when :sha, :sha1 # SHA1 => https://datatracker.ietf.org/doc/html/rfc3414#section-7.3.2 key << ("\x00" * 44) end k1 = key.xor(IPAD) k2 = key.xor(OPAD) digest.reset digest << (k1 + ) d1 = digest.digest digest.reset digest << (k2 + d1) # The 12 first octets of the digest are taken as the computed MAC value digest.digest[0, 12] end |
#verify(stream, salt, security_level: @security_level) ⇒ Object
169 170 171 172 173 174 175 176 |
# File 'lib/netsnmp/security_parameters.rb', line 169 def verify(stream, salt, security_level: @security_level) return if security_level.nil? || security_level < 1 verisalt = sign(stream) raise Error, "invalid message authentication salt" unless verisalt == salt log(level: 2) { "message has been verified" } end |