Linux premium180.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
LiteSpeed
: 162.0.209.168 | : 216.73.216.187
Cant Read [ /etc/named.conf ]
8.3.30
nortrmdp
www.github.com/MadExploits
Terminal
AUTO ROOT
Adminer
Backdoor Destroyer
Linux Exploit
Lock Shell
Lock File
Create User
CREATE RDP
PHP Mailer
BACKCONNECT
UNLOCK SHELL
HASH IDENTIFIER
CPANEL RESET
CREATE WP USER
BLACK DEFEND!
README
+ Create Folder
+ Create File
/
usr /
share /
perl5 /
vendor_perl /
Net /
SNMP /
Security /
[ HOME SHELL ]
Name
Size
Permission
Action
Community.pm
4.33
KB
-rw-r--r--
USM.pm
50.79
KB
-rw-r--r--
Delete
Unzip
Zip
${this.title}
Close
Code Editor : USM.pm
# -*- mode: perl -*- # ============================================================================ package Net::SNMP::Security::USM; # $Id: USM.pm,v 4.1 2010/09/10 00:01:22 dtown Rel $ # Object that implements the SNMPv3 User-based Security Model. # Copyright (c) 2001-2010 David M. Town <dtown@cpan.org> # All rights reserved. # This program is free software; you may redistribute it and/or modify it # under the same terms as the Perl 5 programming language system itself. # ============================================================================ use strict; use Net::SNMP::Security qw( :ALL ); use Net::SNMP::Message qw( :msgFlags asn1_itoa OCTET_STRING SEQUENCE INTEGER SNMP_VERSION_3 TRUE FALSE ); use Crypt::DES(); use Digest::MD5(); use Digest::SHA1(); use Digest::HMAC(); ## Version of the Net::SNMP::Security::USM module our $VERSION = v4.0.1; ## Handle importing/exporting of symbols use base qw( Net::SNMP::Security ); our @EXPORT_OK; our %EXPORT_TAGS = ( authprotos => [ qw( AUTH_PROTOCOL_NONE AUTH_PROTOCOL_HMACMD5 AUTH_PROTOCOL_HMACSHA ) ], levels => [ qw( SECURITY_LEVEL_NOAUTHNOPRIV SECURITY_LEVEL_AUTHNOPRIV SECURITY_LEVEL_AUTHPRIV ) ], models => [ qw( SECURITY_MODEL_ANY SECURITY_MODEL_SNMPV1 SECURITY_MODEL_SNMPV2C SECURITY_MODEL_USM ) ], privprotos => [ qw( PRIV_PROTOCOL_NONE PRIV_PROTOCOL_DES PRIV_PROTOCOL_AESCFB128 PRIV_PROTOCOL_DRAFT_3DESEDE PRIV_PROTOCOL_DRAFT_AESCFB128 PRIV_PROTOCOL_DRAFT_AESCFB192 PRIV_PROTOCOL_DRAFT_AESCFB256 ) ], ); Exporter::export_ok_tags( qw( authprotos levels models privprotos ) ); $EXPORT_TAGS{ALL} = [ @EXPORT_OK ]; ## RCC 3414 - Authentication protocols sub AUTH_PROTOCOL_NONE { '1.3.6.1.6.3.10.1.1.1' } # usmNoAuthProtocol sub AUTH_PROTOCOL_HMACMD5 { '1.3.6.1.6.3.10.1.1.2' } # usmHMACMD5AuthProtocol sub AUTH_PROTOCOL_HMACSHA { '1.3.6.1.6.3.10.1.1.3' } # usmHMACSHAAuthProtocol ## RFC 3414 - Privacy protocols sub PRIV_PROTOCOL_NONE { '1.3.6.1.6.3.10.1.2.1' } # usmNoPrivProtocol sub PRIV_PROTOCOL_DES { '1.3.6.1.6.3.10.1.2.2' } # usmDESPrivProtocol ## RFC 3826 - The AES Cipher Algorithm in the SNMP USM # usmAesCfb128Protocol sub PRIV_PROTOCOL_AESCFB128 { '1.3.6.1.6.3.10.1.2.4' } # The privacy protocols below have been implemented using the draft # specifications intended to extend the User-based Security Model # defined in RFC 3414. Since the object definitions have not been # standardized, they have been based on the Extended Security Options # Consortium MIB found at http://www.snmp.com/eso/esoConsortiumMIB.txt. # Extension to Support Triple-DES EDE <draft-reeder-snmpv3-usm-3desede-00.txt> # Reeder and Gudmunsson; October 1999, expired April 2000 # usm3DESPrivProtocol sub PRIV_PROTOCOL_DRAFT_3DESEDE { '1.3.6.1.4.1.14832.1.1' } # AES Cipher Algorithm in the USM <draft-blumenthal-aes-usm-04.txt> # Blumenthal, Maino, and McCloghrie; October 2002, expired April 2003 # usmAESCfb128PrivProtocol sub PRIV_PROTOCOL_DRAFT_AESCFB128 { '1.3.6.1.4.1.14832.1.2' } # usmAESCfb192PrivProtocol sub PRIV_PROTOCOL_DRAFT_AESCFB192 { '1.3.6.1.4.1.14832.1.3' } # usmAESCfb256PrivProtocol sub PRIV_PROTOCOL_DRAFT_AESCFB256 { '1.3.6.1.4.1.14832.1.4' } ## Package variables our $ENGINE_ID; # Our authoritative snmpEngineID # [public methods] ----------------------------------------------------------- sub new { my ($class, %argv) = @_; # Create a new data structure for the object my $this = bless { '_error' => undef, # Error message '_version' => SNMP_VERSION_3, # version '_authoritative' => FALSE, # Authoritative flag '_discovered' => FALSE, # Engine discovery flag '_synchronized' => FALSE, # Synchronization flag '_engine_id' => q{}, # snmpEngineID '_engine_boots' => 0, # snmpEngineBoots '_engine_time' => 0, # snmpEngineTime '_latest_engine_time' => 0, # latestReceivedEngineTime '_time_epoc' => time(), # snmpEngineBoots epoc '_user_name' => q{}, # securityName '_auth_data' => undef, # Authentication data '_auth_key' => undef, # authKey '_auth_password' => undef, # Authentication password '_auth_protocol' => AUTH_PROTOCOL_HMACMD5, # authProtocol '_priv_data' => undef, # Privacy data '_priv_key' => undef, # privKey '_priv_password' => undef, # Privacy password '_priv_protocol' => PRIV_PROTOCOL_DES, # privProtocol '_security_level' => SECURITY_LEVEL_NOAUTHNOPRIV }, $class; # We first need to find out if we are an authoritative SNMP # engine and set the authProtocol and privProtocol if they # have been provided. foreach (keys %argv) { if (/^-?authoritative$/i) { $this->{_authoritative} = (delete $argv{$_}) ? TRUE : FALSE; } elsif (/^-?authprotocol$/i) { $this->_auth_protocol(delete $argv{$_}); } elsif (/^-?privprotocol$/i) { $this->_priv_protocol(delete $argv{$_}); } if (defined $this->{_error}) { return wantarray ? (undef, $this->{_error}) : undef; } } # Now validate the rest of the passed arguments for (keys %argv) { if (/^-?version$/i) { $this->_version($argv{$_}); } elsif (/^-?debug$/i) { $this->debug($argv{$_}); } elsif ((/^-?engineid$/i) && ($this->{_authoritative})) { $this->_engine_id($argv{$_}); } elsif (/^-?username$/i) { $this->_user_name($argv{$_}); } elsif (/^-?authkey$/i) { $this->_auth_key($argv{$_}); } elsif (/^-?authpassword$/i) { $this->_auth_password($argv{$_}); } elsif (/^-?privkey$/i) { $this->_priv_key($argv{$_}); } elsif (/^-?privpassword$/i) { $this->_priv_password($argv{$_}); } else { $this->_error('The argument "%s" is unknown', $_); } if (defined $this->{_error}) { return wantarray ? (undef, $this->{_error}) : undef; } } # Generate a snmpEngineID and populate the object accordingly # if we are an authoritative snmpEngine. if ($this->{_authoritative}) { $this->_snmp_engine_init(); } # Define the securityParameters if (!defined $this->_security_params()) { return wantarray ? (undef, $this->{_error}) : undef; } # Return the object and an empty error message (in list context) return wantarray ? ($this, q{}) : $this; } sub generate_request_msg { my ($this, $pdu, $msg) = @_; # Clear any previous errors $this->_error_clear(); if (@_ < 3) { return $this->_error('The required PDU and/or Message object is missing'); } # Validate the SNMP version of the PDU if ($pdu->version() != $this->{_version}) { return $this->_error( 'The SNMP version %d was expected, but %d was found', $this->{_version}, $pdu->version() ); } # Validate the securityLevel of the PDU if ($pdu->security_level() > $this->{_security_level}) { return $this->_error( 'The PDU securityLevel %d is greater than the configured value %d', $pdu->security_level(), $this->{_security_level} ); } # Validate PDU type with snmpEngine type if ($pdu->expect_response()) { if ($this->{_authoritative}) { return $this->_error( 'Must be a non-authoritative SNMP engine to generate a %s', asn1_itoa($pdu->pdu_type()) ); } } else { if (!$this->{_authoritative}) { return $this->_error( 'Must be an authoritative SNMP engine to generate a %s', asn1_itoa($pdu->pdu_type()) ); } } # Extract the msgGlobalData out of the message my $msg_global_data = $msg->clear(); # AES in the USM Section 3.1.2.1 - "The 128-bit IV is obtained as # the concatenation of the... ...snmpEngineBoots, ...snmpEngineTime, # and a local 64-bit integer. We store the current snmpEngineBoots # and snmpEngineTime before encrypting the PDU so that the computed # IV matches the transmitted msgAuthoritativeEngineBoots and # msgAuthoritativeEngineTime. my $msg_engine_time = $this->_engine_time(); my $msg_engine_boots = $this->_engine_boots(); # Copy the PDU into a "plain text" buffer my $pdu_buffer = $pdu->copy(); my $priv_params = q{}; # encryptedPDU::=OCTET STRING if ($pdu->security_level() > SECURITY_LEVEL_AUTHNOPRIV) { if (!defined $this->_encrypt_data($msg, $priv_params, $pdu_buffer)) { return $this->_error(); } } # msgPrivacyParameters::=OCTET STRING if (!defined $msg->prepare(OCTET_STRING, $priv_params)) { return $this->_error($msg->error()); } # msgAuthenticationParameters::=OCTET STRING my $auth_params = q{}; my $auth_location = 0; if ($pdu->security_level() > SECURITY_LEVEL_NOAUTHNOPRIV) { # Save the location to fill in msgAuthenticationParameters later $auth_location = $msg->length() + 12 + length $pdu_buffer; # Set the msgAuthenticationParameters to all zeros $auth_params = pack 'x12'; } if (!defined $msg->prepare(OCTET_STRING, $auth_params)) { return $this->_error($msg->error()); } # msgUserName::=OCTET STRING if (!defined $msg->prepare(OCTET_STRING, $pdu->security_name())) { return $this->_error($msg->error()); } # msgAuthoritativeEngineTime::=INTEGER if (!defined $msg->prepare(INTEGER, $msg_engine_time)) { return $this->_error($msg->error()); } # msgAuthoritativeEngineBoots::=INTEGER if (!defined $msg->prepare(INTEGER, $msg_engine_boots)) { return $this->_error($msg->error()); } # msgAuthoritativeEngineID if (!defined $msg->prepare(OCTET_STRING, $this->_engine_id())) { return $this->_error($msg->error()); } # UsmSecurityParameters::= SEQUENCE if (!defined $msg->prepare(SEQUENCE)) { return $this->_error($msg->error()); } # msgSecurityParameters::=OCTET STRING if (!defined $msg->prepare(OCTET_STRING, $msg->clear())) { return $this->_error($msg->error()); } # Append the PDU if (!defined $msg->append($pdu_buffer)) { return $this->_error($msg->error()); } # Prepend the msgGlobalData if (!defined $msg->prepend($msg_global_data)) { return $this->_error($msg->error()); } # version::=INTEGER if (!defined $msg->prepare(INTEGER, $this->{_version})) { return $this->_error($msg->error()); } # message::=SEQUENCE if (!defined $msg->prepare(SEQUENCE)) { return $this->_error($msg->error()); } # Apply authentication if ($pdu->security_level() > SECURITY_LEVEL_NOAUTHNOPRIV) { if (!defined $this->_authenticate_outgoing_msg($msg, $auth_location)) { return $this->_error($msg->error()); } } # Return the Message return $msg; } sub process_incoming_msg { my ($this, $msg) = @_; # Clear any previous errors $this->_error_clear(); return $this->_error('The required Message object is missing') if (@_ < 2); # msgSecurityParameters::=OCTET STRING my $msg_params = $msg->process(OCTET_STRING); return $this->_error($msg->error()) if !defined $msg_params; # Need to move the buffer index back to the begining of the data # portion of the OCTET STRING that contains the msgSecurityParameters. $msg->index($msg->index() - length $msg_params); # UsmSecurityParameters::=SEQUENCE return $this->_error($msg->error()) if !defined $msg->process(SEQUENCE); # msgAuthoritativeEngineID::=OCTET STRING my $msg_engine_id; if (!defined($msg_engine_id = $msg->process(OCTET_STRING))) { return $this->_error($msg->error()); } # msgAuthoritativeEngineBoots::=INTEGER (0..2147483647) my $msg_engine_boots; if (!defined ($msg_engine_boots = $msg->process(INTEGER))) { return $this->_error($msg->error()); } if (($msg_engine_boots < 0) || ($msg_engine_boots > 2147483647)) { return $this->_error( 'The msgAuthoritativeEngineBoots value %d is out of range ' . '(0..2147483647)', $msg_engine_boots ); } # msgAuthoritativeEngineTime::=INTEGER (0..2147483647) my $msg_engine_time; if (!defined ($msg_engine_time = $msg->process(INTEGER))) { return $this->_error($msg->error()); } if (($msg_engine_time < 0) || ($msg_engine_time > 2147483647)) { return $this->_error( 'The msgAuthoritativeEngineTime value %d is out of range ' . '(0..2147483647)', $msg_engine_time ); } # msgUserName::=OCTET STRING (SIZE(0..32)) if (!defined $msg->security_name($msg->process(OCTET_STRING))) { return $this->_error($msg->error()); } # msgAuthenticationParameters::=OCTET STRING my $auth_params; if (!defined ($auth_params = $msg->process(OCTET_STRING))) { return $this->_error($msg->error()); } # We need to zero out the msgAuthenticationParameters in order # to compute the HMAC properly. if (my $len = length $auth_params) { if ($len != 12) { return $this->_error( 'The msgAuthenticationParameters length of %d is invalid', $len ); } substr ${$msg->reference}, ($msg->index() - 12), 12, pack 'x12'; } # msgPrivacyParameters::=OCTET STRING my $priv_params; if (!defined ($priv_params = $msg->process(OCTET_STRING))) { return $this->_error($msg->error()); } # Validate the msgAuthoritativeEngineID and msgUserName if ($this->{_discovered}) { if ($msg_engine_id ne $this->_engine_id()) { return $this->_error( 'The msgAuthoritativeEngineID "%s" was expected, but "%s" was ' . 'found', unpack('H*', $this->_engine_id()), unpack 'H*', $msg_engine_id ); } if ($msg->security_name() ne $this->_user_name()) { return $this->_error( 'The msgUserName "%s" was expected, but "%s" was found', $this->_user_name(), $msg->security_name() ); } } else { # Handle authoritativeEngineID discovery if (!defined $this->_engine_id_discovery($msg_engine_id)) { return $this->_error(); } } # Validate the incoming securityLevel my $security_level = $msg->security_level(); if ($security_level > $this->{_security_level}) { return $this->_error( 'The message securityLevel %d is greater than the configured ' . 'value %d', $security_level, $this->{_security_level} ); } if ($security_level > SECURITY_LEVEL_NOAUTHNOPRIV) { # Authenticate the message if (!defined $this->_authenticate_incoming_msg($msg, $auth_params)) { return $this->_error(); } # Synchronize the time if (!$this->_synchronize($msg_engine_boots, $msg_engine_time)) { return $this->_error(); } # Check for timeliness if (!defined $this->_timeliness($msg_engine_boots, $msg_engine_time)) { return $this->_error(); } if ($security_level > SECURITY_LEVEL_AUTHNOPRIV) { # Validate the msgPrivacyParameters length. if (length($priv_params) != 8) { return $this->_error( 'The msgPrivacyParameters length of %d is invalid', length $priv_params ); } # AES in the USM Section 3.1.2.1 - "The 128-bit IV is # obtained as the concatenation of the... ...snmpEngineBoots, # ...snmpEngineTime, and a local 64-bit integer. ...The # 64-bit integer must be placed in the msgPrivacyParameters # field..." We must prepend the snmpEngineBoots and # snmpEngineTime as received in order to compute the IV. if (($this->{_priv_protocol} eq PRIV_PROTOCOL_AESCFB128) || ($this->{_priv_protocol} eq PRIV_PROTOCOL_DRAFT_AESCFB192) || ($this->{_priv_protocol} eq PRIV_PROTOCOL_DRAFT_AESCFB256)) { substr $priv_params, 0, 0, pack 'NN', $msg_engine_boots, $msg_engine_time; } # encryptedPDU::=OCTET STRING return $this->_decrypt_data($msg, $priv_params, $msg->process(OCTET_STRING)); } } return TRUE; } sub user_name { return $_[0]->{_user_name}; } sub auth_protocol { my ($this) = @_; if ($this->{_security_level} > SECURITY_LEVEL_NOAUTHNOPRIV) { return $this->{_auth_protocol}; } return AUTH_PROTOCOL_NONE; } sub auth_key { return $_[0]->{_auth_key}; } sub priv_protocol { my ($this) = @_; if ($this->{_security_level} > SECURITY_LEVEL_AUTHNOPRIV) { return $this->{_priv_protocol}; } return PRIV_PROTOCOL_NONE; } sub priv_key { return $_[0]->{_priv_key}; } sub engine_id { return $_[0]->{_engine_id}; } sub engine_boots { goto _engine_boots; } sub engine_time { goto &_engine_time; } sub security_level { return $_[0]->{_security_level}; } sub security_model { # RFC 3411 - SnmpSecurityModel::=TEXTUAL-CONVENTION return SECURITY_MODEL_USM; } sub security_name { goto &_user_name; } sub discovered { my ($this) = @_; if ($this->{_security_level} > SECURITY_LEVEL_NOAUTHNOPRIV) { return ($this->{_discovered} && $this->{_synchronized}); } return $this->{_discovered}; } # [private methods] ---------------------------------------------------------- sub _version { my ($this, $version) = @_; if ($version != SNMP_VERSION_3) { return $this->_error('The SNMP version %s is not supported', $version); } return $this->{_version} = $version; } sub _engine_id { my ($this, $engine_id) = @_; if (@_ < 2) { return $this->{_engine_id}; } if ($engine_id =~ m/^(?:0x)?([A-F0-9]+)$/i) { my $eid = pack 'H*', length($1) % 2 ? '0'.$1 : $1; my $len = length $eid; if ($len < 5 || $len > 32) { return $this->_error( 'The authoritativeEngineID length of %d is out of range (5..32)', $len ); } $this->{_engine_id} = $eid; } else { return $this->_error( 'The authoritativeEngineID "%s" is expected in hexadecimal format', $engine_id ); } return $this->{_engine_id}; } sub _user_name { my ($this, $user_name) = @_; if (@_ == 2) { if ($user_name eq q{}) { return $this->_error('An empty userName was specified'); } elsif (length($user_name) > 32) { return $this->_error( 'The userName length of %d is out of range (1..32)', length $user_name ); } $this->{_user_name} = $user_name; } # RFC 3414 Section 4 - "Discovery... ...msgUserName of zero-length..." return ($this->{_discovered}) ? $this->{_user_name} : q{}; } sub _snmp_engine_init { my ($this) = @_; if ($this->{_engine_id} eq q{}) { # Initialize our snmpEngineID using the algorithm described # in RFC 3411 - SnmpEngineID::=TEXTUAL-CONVENTION. # The first bit is set to one to indicate that the RFC 3411 # algorithm is being used. The first fours bytes are to be # the agent's SNMP management private enterprise number, but # they are set to all zeros. The fifth byte is set to one to # indicate that the final four bytes are an IPv4 address. if (!defined $ENGINE_ID) { $ENGINE_ID = eval { require Sys::Hostname; pack('H10', '8000000001') . gethostbyname Sys::Hostname::hostname(); }; # Fallback in case gethostbyname() or hostname() fail if ($@) { $ENGINE_ID = pack 'x11H2', '01'; } } $this->{_engine_id} = $ENGINE_ID; } $this->{_engine_boots} = 1; $this->{_time_epoc} = $^T; $this->{_synchronized} = TRUE; $this->{_discovered} = TRUE; return TRUE; } sub _auth_key { my ($this, $auth_key) = @_; if (@_ == 2) { if ($auth_key =~ m/^(?:0x)?([A-F0-9]+)$/i) { $this->{_auth_key} = pack 'H*', length($1) % 2 ? '0'.$1 : $1; if (!defined $this->_auth_key_validate()) { return $this->_error(); } } else { return $this->_error( 'The authKey "%s" is expected in hexadecimal format', $auth_key ); } } return $this->{_auth_key}; } sub _auth_password { my ($this, $auth_password) = @_; if (@_ == 2) { if ($auth_password eq q{}) { return $this->_error('An empty authentication password was specified'); } $this->{_auth_password} = $auth_password; } return $this->{_auth_password}; } { my $protocols = { '(?:hmac-)?md5(?:-96)?', AUTH_PROTOCOL_HMACMD5, quotemeta AUTH_PROTOCOL_HMACMD5, AUTH_PROTOCOL_HMACMD5, '(?:hmac-)?sha(?:-?1|-96)?', AUTH_PROTOCOL_HMACSHA, quotemeta AUTH_PROTOCOL_HMACSHA, AUTH_PROTOCOL_HMACSHA, }; sub _auth_protocol { my ($this, $proto) = @_; if (@_ < 2) { return $this->{_auth_protocol}; } if ($proto eq q{}) { return $this->_error('An empty authProtocol was specified'); } for (keys %{$protocols}) { if ($proto =~ /^$_$/i) { return $this->{_auth_protocol} = $protocols->{$_}; } } return $this->_error('The authProtocol "%s" is unknown', $proto); } } sub _priv_key { my ($this, $priv_key) = @_; if (@_ == 2) { if ($priv_key =~ m/^(?:0x)?([A-F0-9]+)$/i) { $this->{_priv_key} = pack 'H*', length($1) % 2 ? '0'.$1 : $1; if (!defined $this->_priv_key_validate()) { return $this->_error(); } } else { return $this->_error( 'The privKey "%s" is expected in hexadecimal format', $priv_key ); } } return $this->{_priv_key}; } sub _priv_password { my ($this, $priv_password) = @_; if (@_ == 2) { if ($priv_password eq q{}) { return $this->_error('An empty privacy password was specified'); } $this->{_priv_password} = $priv_password; } return $this->{_priv_password}; } { my $protocols = { '(?:cbc-)?des', PRIV_PROTOCOL_DES, quotemeta PRIV_PROTOCOL_DES, PRIV_PROTOCOL_DES, '(?:cbc-)?(?:3|triple-)des(?:-?ede)?', PRIV_PROTOCOL_DRAFT_3DESEDE, quotemeta PRIV_PROTOCOL_DRAFT_3DESEDE, PRIV_PROTOCOL_DRAFT_3DESEDE, '(?:(?:cfb)?128-?)?aes(?:-?128)?', PRIV_PROTOCOL_AESCFB128, quotemeta PRIV_PROTOCOL_AESCFB128, PRIV_PROTOCOL_AESCFB128, quotemeta PRIV_PROTOCOL_DRAFT_AESCFB128, PRIV_PROTOCOL_AESCFB128, '(?:(?:cfb)?192-?)aes(?:-?128)?', PRIV_PROTOCOL_DRAFT_AESCFB192, quotemeta PRIV_PROTOCOL_DRAFT_AESCFB192, PRIV_PROTOCOL_DRAFT_AESCFB192, '(?:(?:cfb)?256-?)aes(?:-?128)?', PRIV_PROTOCOL_DRAFT_AESCFB256, quotemeta PRIV_PROTOCOL_DRAFT_AESCFB256, PRIV_PROTOCOL_DRAFT_AESCFB256, }; sub _priv_protocol { my ($this, $proto) = @_; if (@_ < 2) { return $this->{_priv_protocol}; } if ($proto eq q{}) { return $this->_error('An empty privProtocol was specified'); } my $priv_proto; for (keys %{$protocols}) { if ($proto =~ /^$_$/i) { $priv_proto = $protocols->{$_}; last; } } if (!defined $priv_proto) { return $this->_error('The privProtocol "%s" is unknown', $proto); } # Validate the support of the AES cipher algorithm. Attempt to # load the Crypt::Rijndael module. If this module is not found, # do not provide support for the AES Cipher Algorithm. if (($priv_proto eq PRIV_PROTOCOL_AESCFB128) || ($priv_proto eq PRIV_PROTOCOL_DRAFT_AESCFB192) || ($priv_proto eq PRIV_PROTOCOL_DRAFT_AESCFB256)) { if (defined (my $error = load_module('Crypt::Rijndael'))) { return $this->_error( 'Support for privProtocol "%s" is unavailable %s', $proto, $error ); } } return $this->{_priv_protocol} = $priv_proto; } } sub _engine_boots { return ($_[0]->{_synchronized}) ? $_[0]->{_engine_boots} : 0; } sub _engine_time { my ($this) = @_; return 0 if (!$this->{_synchronized}); $this->{_engine_time} = time() - $this->{_time_epoc}; if ($this->{_engine_time} > 2147483647) { DEBUG_INFO('snmpEngineTime rollover'); if (++$this->{_engine_boots} == 2147483647) { die 'FATAL: Unable to handle snmpEngineBoots value'; } $this->{_engine_time} -= 2147483647; $this->{_time_epoc} = time() - $this->{_engine_time}; if (!$this->{_authoritative}) { $this->{_synchronized} = FALSE; return $this->{_latest_engine_time} = 0; } } if ($this->{_engine_time} < 0) { die 'FATAL: Unable to handle negative snmpEngineTime value'; } return $this->{_engine_time}; } sub _security_params { my ($this) = @_; # Clear any previous error messages $this->_error_clear(); # We must have an usmUserName if ($this->{_user_name} eq q{}) { return $this->_error('The required userName was not specified'); } # Define the authentication parameters if ((defined $this->{_auth_password}) && ($this->{_discovered})) { if (!defined $this->{_auth_key}) { return $this->_error() if !defined $this->_auth_key_generate(); } $this->{_auth_password} = undef; } if (defined $this->{_auth_key}) { # Validate the key based on the protocol if (!defined $this->_auth_key_validate()) { return $this->_error('The authKey is invalid'); } # Initialize the authentication data if (!defined $this->_auth_data_init()) { return $this->_error('Failed to initialize the authentication data'); } if ($this->{_discovered}) { $this->{_security_level} = SECURITY_LEVEL_AUTHNOPRIV; } } # You must have authentication to have privacy if (!defined ($this->{_auth_key}) && !defined $this->{_auth_password}) { if (defined ($this->{_priv_key}) || defined $this->{_priv_password}) { return $this->_error( 'The securityLevel is unsupported (privacy requires authentication)' ); } } # Define the privacy parameters if ((defined $this->{_priv_password}) && ($this->{_discovered})) { if (!defined $this->{_priv_key}) { return $this->_error() if !defined $this->_priv_key_generate(); } $this->{_priv_password} = undef; } if (defined $this->{_priv_key}) { # Validate the key based on the protocol if (!defined $this->_priv_key_validate()) { return $this->_error('The privKey is invalid'); } # Initialize the privacy data if (!defined $this->_priv_data_init()) { return $this->_error('Failed to initialize the privacy data'); } if ($this->{_discovered}) { $this->{_security_level} = SECURITY_LEVEL_AUTHPRIV; } } DEBUG_INFO('securityLevel = %d', $this->{_security_level}); return $this->{_security_level}; } sub _engine_id_discovery { my ($this, $engine_id) = @_; return TRUE if ($this->{_authoritative}); DEBUG_INFO('engineID = 0x%s', unpack 'H*', $engine_id || q{}); if (length($engine_id) < 5 || length($engine_id) > 32) { return $this->_error( 'The msgAuthoritativeEngineID length of %d is out of range (5..32)', length $engine_id ); } $this->{_engine_id} = $engine_id; $this->{_discovered} = TRUE; if (!defined $this->_security_params()) { $this->{_discovered} = FALSE; return $this->_error(); } return TRUE; } sub _synchronize { my ($this, $msg_boots, $msg_time) = @_; return TRUE if ($this->{_authoritative}); return TRUE if ($this->{_security_level} < SECURITY_LEVEL_AUTHNOPRIV); if (($msg_boots > $this->_engine_boots()) || (($msg_boots == $this->_engine_boots()) && ($msg_time > $this->{_latest_engine_time}))) { DEBUG_INFO( 'update: engineBoots = %d, engineTime = %d', $msg_boots, $msg_time ); $this->{_engine_boots} = $msg_boots; $this->{_latest_engine_time} = $this->{_engine_time} = $msg_time; $this->{_time_epoc} = time() - $this->{_engine_time}; if (!$this->{_synchronized}) { $this->{_synchronized} = TRUE; if (!defined $this->_security_params()) { return ($this->{_synchronized} = FALSE); } } return TRUE; } DEBUG_INFO( 'no update: engineBoots = %d, msgBoots = %d; ' . 'latestTime = %d, msgTime = %d', $this->_engine_boots(), $msg_boots, $this->{_latest_engine_time}, $msg_time ); return TRUE; } sub _timeliness { my ($this, $msg_boots, $msg_time) = @_; return TRUE if ($this->{_security_level} < SECURITY_LEVEL_AUTHNOPRIV); # Retrieve a local copy of our snmpEngineBoots and snmpEngineTime # to avoid the possibilty of using different values in each of # the comparisons. my $engine_time = $this->_engine_time(); my $engine_boots = $this->_engine_boots(); if ($engine_boots == 2147483647) { $this->{_synchronized} = FALSE; return $this->_error('The system is not in the time window'); } if (!$this->{_authoritative}) { if ($msg_boots < $engine_boots) { return $this->_error('The message is not in the time window'); } if (($msg_boots == $engine_boots) && ($msg_time < ($engine_time - 150))) { return $this->_error('The message is not in the time window'); } } else { if ($msg_boots != $engine_boots) { return $this->_error('The message is not in the time window'); } if (($msg_time < ($engine_time - 150)) || ($msg_time > ($engine_time + 150))) { return $this->_error('The message is not in the time window'); } } return TRUE; } sub _authenticate_outgoing_msg { my ($this, $msg, $auth_location) = @_; if (!$auth_location) { return $this->_error( 'Authentication failure (Unable to set msgAuthenticationParameters)' ); } # Set the msgAuthenticationParameters substr ${$msg->reference}, -$auth_location, 12, $this->_auth_hmac($msg); return TRUE; } sub _authenticate_incoming_msg { my ($this, $msg, $auth_params) = @_; # Authenticate the message if ($auth_params ne $this->_auth_hmac($msg)) { return $this->_error('Authentication failure'); } DEBUG_INFO('authentication passed'); return TRUE; } sub _auth_hmac { my ($this, $msg) = @_; return q{} if (!defined($this->{_auth_data}) || !defined $msg); return substr $this->{_auth_data}->reset()->add(${$msg->reference()})->digest(), 0, 12; } sub _auth_data_init { my ($this) = @_; if (!defined $this->{_auth_key}) { return $this->_error('The required authKey is not defined'); } return TRUE if defined $this->{_auth_data}; if ($this->{_auth_protocol} eq AUTH_PROTOCOL_HMACMD5) { $this->{_auth_data} = Digest::HMAC->new($this->{_auth_key}, 'Digest::MD5'); } elsif ($this->{_auth_protocol} eq AUTH_PROTOCOL_HMACSHA) { $this->{_auth_data} = Digest::HMAC->new($this->{_auth_key}, 'Digest::SHA1'); } else { return $this->_error( 'The authProtocol "%s" is unknown', $this->{_auth_protocol} ); } return TRUE; } { my $encrypt = { PRIV_PROTOCOL_DES, \&_priv_encrypt_des, PRIV_PROTOCOL_DRAFT_3DESEDE, \&_priv_encrypt_3desede, PRIV_PROTOCOL_AESCFB128, \&_priv_encrypt_aescfbxxx, PRIV_PROTOCOL_DRAFT_AESCFB192, \&_priv_encrypt_aescfbxxx, PRIV_PROTOCOL_DRAFT_AESCFB256, \&_priv_encrypt_aescfbxxx }; sub _encrypt_data { # my ($this, $msg, $priv_params, $plain) = @_; if (!exists $encrypt->{$_[0]->{_priv_protocol}}) { return $_[0]->_error('Encryption error (Unknown protocol)'); } if (!defined $_[1]->prepare( OCTET_STRING, $_[0]->${\$encrypt->{$_[0]->{_priv_protocol}}}($_[2], $_[3]) ) ) { return $_[0]->_error('Encryption error'); } # Set the PDU buffer equal to the encryptedPDU return $_[3] = $_[1]->clear(); } } { my $decrypt = { PRIV_PROTOCOL_DES, \&_priv_decrypt_des, PRIV_PROTOCOL_DRAFT_3DESEDE, \&_priv_decrypt_3desede, PRIV_PROTOCOL_AESCFB128, \&_priv_decrypt_aescfbxxx, PRIV_PROTOCOL_DRAFT_AESCFB192, \&_priv_decrypt_aescfbxxx, PRIV_PROTOCOL_DRAFT_AESCFB256, \&_priv_decrypt_aescfbxxx }; sub _decrypt_data { # my ($this, $msg, $priv_params, $cipher) = @_; # Make sure there is data to decrypt. if (!defined $_[3]) { return $_[0]->_error($_[1]->error() || 'Decryption error (No data)'); } if (!exists $decrypt->{$_[0]->{_priv_protocol}}) { return $_[0]->_error('Decryption error (Unknown protocol)'); } # Clear the Message buffer $_[1]->clear(); # Put the decrypted data back into the Message buffer if (!defined $_[1]->prepend( $_[0]->${\$decrypt->{$_[0]->{_priv_protocol}}}($_[2], $_[3]) ) ) { return $_[0]->_error($_[1]->error()); } return $_[0]->_error($_[1]->error()) if (!$_[1]->length()); # See if the decrypted data starts with a SEQUENCE # and has a reasonable length. my $msglen = $_[1]->process(SEQUENCE); if ((!defined $msglen) || ($msglen > $_[1]->length())) { return $_[0]->_error('Decryption error'); } $_[1]->index(0); # Reset the index DEBUG_INFO('privacy passed'); return TRUE; } } sub _priv_data_init { my ($this) = @_; if (!defined $this->{_priv_key}) { return $this->_error('The required privKey is not defined'); } return TRUE if defined $this->{_priv_data}; my $init = { PRIV_PROTOCOL_DES, \&_priv_data_init_des, PRIV_PROTOCOL_DRAFT_3DESEDE, \&_priv_data_init_3desede, PRIV_PROTOCOL_AESCFB128, \&_priv_data_init_aescfbxxx, PRIV_PROTOCOL_DRAFT_AESCFB192, \&_priv_data_init_aescfbxxx, PRIV_PROTOCOL_DRAFT_AESCFB256, \&_priv_data_init_aescfbxxx }; if (!exists $init->{$this->{_priv_protocol}}) { return $this->_error( 'The privProtocol "%s" is unknown', $this->{_priv_protocol} ); } return $this->${\$init->{$this->{_priv_protocol}}}(); } sub _priv_data_init_des { my ($this) = @_; if (!defined $this->{_priv_key}) { return $this->_error('The required privKey is not defined'); } # Create the DES object $this->{_priv_data}->{des} = Crypt::DES->new(substr $this->{_priv_key}, 0, 8); # Extract the pre-IV $this->{_priv_data}->{pre_iv} = substr $this->{_priv_key}, 8, 8; # Initialize the salt $this->{_priv_data}->{salt} = int rand ~0; return TRUE; } sub _priv_encrypt_des { # my ($this, $priv_params, $plain) = @_; if (!defined $_[0]->{_priv_data}) { return $_[0]->_error('The required privacy data is not defined'); } # Always pad the plain text data. "The actual pad value is # irrelevant..." according RFC 3414 Section 8.1.1.2. However, # there are some agents out there that expect "standard block # padding" where each of the padding byte(s) are set to the size # of the padding (even for data that is a multiple of block size). my $pad = 8 - (length($_[2]) % 8); $_[2] .= pack('C', $pad) x $pad; # Create and set the salt if ($_[0]->{_priv_data}->{salt}++ == ~0) { $_[0]->{_priv_data}->{salt} = 0; } $_[1] = pack 'NN', $_[0]->{_engine_boots}, $_[0]->{_priv_data}->{salt}; # Create the initial vector (IV) my $iv = $_[0]->{_priv_data}->{pre_iv} ^ $_[1]; my $cipher = q{}; # Perform Cipher Block Chaining (CBC) while ($_[2] =~ /(.{8})/gs) { $cipher .= $iv = $_[0]->{_priv_data}->{des}->encrypt($1 ^ $iv); } return $cipher; } sub _priv_decrypt_des { # my ($this, $priv_params, $cipher) = @_; if (!defined $_[0]->{_priv_data}) { return $_[0]->_error('The required privacy data is not defined'); } if (length($_[1]) != 8) { return $_[0]->_error( 'The msgPrivParameters length of %d is invalid', length $_[1] ); } if (length($_[2]) % 8) { return $_[0]->_error( 'The DES cipher length is not a multiple of the block size' ); } # Create the initial vector (IV) my $iv = $_[0]->{_priv_data}->{pre_iv} ^ $_[1]; my $plain = q{}; # Perform Cipher Block Chaining (CBC) while ($_[2] =~ /(.{8})/gs) { $plain .= $iv ^ $_[0]->{_priv_data}->{des}->decrypt($1); $iv = $1; } return $plain; } sub _priv_data_init_3desede { my ($this) = @_; if (!defined $this->{_priv_key}) { return $this->_error('The required privKey is not defined'); } # Create the 3 DES objects $this->{_priv_data}->{des1} = Crypt::DES->new(substr $this->{_priv_key}, 0, 8); $this->{_priv_data}->{des2} = Crypt::DES->new(substr $this->{_priv_key}, 8, 8); $this->{_priv_data}->{des3} = Crypt::DES->new(substr $this->{_priv_key}, 16, 8); # Extract the pre-IV $this->{_priv_data}->{pre_iv} = substr $this->{_priv_key}, 24, 8; # Initialize the salt $this->{_priv_data}->{salt} = int rand ~0; # Assign a hash algorithm to "bit spread" the salt if ($this->{_auth_protocol} eq AUTH_PROTOCOL_HMACMD5) { $this->{_priv_data}->{hash} = Digest::MD5->new(); } elsif ($this->{_auth_protocol} eq AUTH_PROTOCOL_HMACSHA) { $this->{_priv_data}->{hash} = Digest::SHA1->new(); } return TRUE; } sub _priv_encrypt_3desede { # my ($this, $priv_params, $plain) = @_; if (!defined $_[0]->{_priv_data}) { return $_[0]->_error('The required privacy data is not defined'); } # Pad the plain text data using "standard block padding". my $pad = 8 - (length($_[2]) % 8); $_[2] .= pack('C', $pad) x $pad; # Create and set the salt if ($_[0]->{_priv_data}->{salt}++ == ~0) { $_[0]->{_priv_data}->{salt} = 0; } $_[1] = pack 'NN', $_[0]->{_engine_boots}, $_[0]->{_priv_data}->{salt}; # Draft 3DES-EDE for USM Section 5.1.1.1.2 - "To achieve effective # bit spreading, the complete 8-octet 'salt' value SHOULD be # hashed using the usmUserAuthProtocol." if (exists $_[0]->{_priv_data}->{hash}) { $_[1] = substr $_[0]->{_priv_data}->{hash}->add($_[1])->digest(), 0, 8; } # Create the initial vector (IV) my $iv = $_[0]->{_priv_data}->{pre_iv} ^ $_[1]; my $cipher = q{}; # Perform Cipher Block Chaining (CBC) while ($_[2] =~ /(.{8})/gs) { $cipher .= $iv = $_[0]->{_priv_data}->{des3}->encrypt( $_[0]->{_priv_data}->{des2}->decrypt( $_[0]->{_priv_data}->{des1}->encrypt($1 ^ $iv) ) ); } return $cipher; } sub _priv_decrypt_3desede { # my ($this, $priv_params, $cipher) = @_; if (!defined $_[0]->{_priv_data}) { return $_[0]->_error('The required privacy data is not defined'); } if (length($_[1]) != 8) { return $_[0]->_error( 'The msgPrivParameters length of %d is invalid', length $_[1] ); } if (length($_[2]) % 8) { return $_[0]->_error( 'The CBC-3DES-EDE cipher length is not a multiple of the block size' ); } # Create the initial vector (IV) my $iv = $_[0]->{_priv_data}->{pre_iv} ^ $_[1]; my $plain = q{}; # Perform Cipher Block Chaining (CBC) while ($_[2] =~ /(.{8})/gs) { $plain .= $iv ^ $_[0]->{_priv_data}->{des1}->decrypt( $_[0]->{_priv_data}->{des2}->encrypt( $_[0]->{_priv_data}->{des3}->decrypt($1) ) ); $iv = $1; } return $plain; } sub _priv_data_init_aescfbxxx { my ($this) = @_; if (!defined $this->{_priv_key}) { return $this->_error('The required privKey is not defined'); } { # Avoid a "strict subs" error if Crypt::Rijndael is not loaded. no strict 'subs'; # Create the AES (Rijndael) object with a 128, 192, or 256 bit key. $this->{_priv_data}->{aes} = Crypt::Rijndael->new($this->{_priv_key}, Crypt::Rijndael::MODE_CFB()); } # Initialize the salt $this->{_priv_data}->{salt1} = int rand ~0; $this->{_priv_data}->{salt2} = int rand ~0; return TRUE; } sub _priv_encrypt_aescfbxxx { # my ($this, $priv_params, $plain) = @_; if (!defined $_[0]->{_priv_data}) { return $_[0]->_error('The required privacy data is not defined'); } # Validate the plain text length my $length = length $_[2]; if ($length <= 16) { return $_[0]->_error( 'The AES plain text length is not greater than the block size' ); } # Create and set the salt if ($_[0]->{_priv_data}->{salt1}++ == ~0) { $_[0]->{_priv_data}->{salt1} = 0; if ($_[0]->{_priv_data}->{salt2}++ == ~0) { $_[0]->{_priv_data}->{salt2} = 0; } } $_[1] = pack 'NN', $_[0]->{_priv_data}->{salt2}, $_[0]->{_priv_data}->{salt1}; # AES in the USM Section - Section 3.1.3 "The last ciphertext # block is produced by exclusive-ORing the last plaintext segment # of r bits (r is less or equal to 128) with the segment of the r # most significant bits of the last output block." # This operation is identical to those performed on the previous # blocks except for the fact that the block can be less than the # block size. We can just pad the last block and operate on it as # usual and then ignore the padding after encrypting. $_[2] .= "\000" x (16 - ($length % 16)); # Create the IV by concatenating "...the generating SNMP engine's # 32-bit snmpEngineBoots, the SNMP engine's 32-bit snmpEngineTime, # and a local 64-bit integer..." $_[0]->{_priv_data}->{aes}->set_iv( pack('NN', $_[0]->{_engine_boots}, $_[0]->{_engine_time}) . $_[1] ); # Let the Crypt::Rijndael module perform 128 bit Cipher Feedback # (CFB) and return the result minus the "internal" padding. return substr $_[0]->{_priv_data}->{aes}->encrypt($_[2]), 0, $length; } sub _priv_decrypt_aescfbxxx { # my ($this, $priv_params, $cipher) = @_; if (!defined $_[0]->{_priv_data}) { return $_[0]->_error('The required privacy data is not defined'); } # Validate the msgPrivParameters length. We assume that the # msgAuthoritativeEngineBoots and msgAuthoritativeEngineTime # have been prepended to the msgPrivParameters to create the # required 128 bit IV. if (length($_[1]) != 16) { return $_[0]->_error( 'The AES IV length of %d is invalid', length $_[1] ); } # Validate the cipher length my $length = length $_[2]; if ($length <= 16) { return $_[0]->_error( 'The AES cipher length is not greater than the block size' ); } # AES in the USM Section - Section 3.1.4 "The last ciphertext # block (whose size r is less or equal to 128) is less or equal # to 128) is exclusive-ORed with the segment of the r most # significant bits of the last output block to recover the last # plaintext block of r bits." # This operation is identical to those performed on the previous # blocks except for the fact that the block can be less than the # block size. We can just pad the last block and operate on it as # usual and then ignore the padding after decrypting. $_[2] .= "\000" x (16 - ($length % 16)); # Use the msgPrivParameters as the IV. $_[0]->{_priv_data}->{aes}->set_iv($_[1]); # Let the Crypt::Rijndael module perform 128 bit Cipher Feedback # (CFB) and return the result minus the "internal" padding. return substr $_[0]->{_priv_data}->{aes}->decrypt($_[2]), 0, $length; } sub _auth_key_generate { my ($this) = @_; if (!defined($this->{_engine_id}) || !defined $this->{_auth_password}) { return $this->_error('Unable to generate the authKey'); } $this->{_auth_key} = $this->_password_localize($this->{_auth_password}); return $this->{_auth_key}; } sub _auth_key_validate { my ($this) = @_; my $key_len = { AUTH_PROTOCOL_HMACMD5, [ 16, 'HMAC-MD5' ], AUTH_PROTOCOL_HMACSHA, [ 20, 'HMAC-SHA1' ], }; if (!exists $key_len->{$this->{_auth_protocol}}) { return $this->_error( 'The authProtocol "%s" is unknown', $this->{_auth_protocol} ); } if (length($this->{_auth_key}) != $key_len->{$this->{_auth_protocol}}->[0]) { return $this->_error( 'The %s authKey length of %d is invalid, expected %d', $key_len->{$this->{_auth_protocol}}->[1], length($this->{_auth_key}), $key_len->{$this->{_auth_protocol}}->[0] ); } return TRUE; } sub _priv_key_generate { my ($this) = @_; if (!defined($this->{_engine_id}) || !defined $this->{_priv_password}) { return $this->_error('Unable to generate the privKey'); } $this->{_priv_key} = $this->_password_localize($this->{_priv_password}); return $this->_error() if !defined $this->{_priv_key}; if ($this->{_priv_protocol} eq PRIV_PROTOCOL_DRAFT_3DESEDE) { # Draft 3DES-EDE for USM Section 2.1 - "To acquire the necessary # number of key bits, the password-to-key algorithm may be chained # using its output as further input in order to generate an # appropriate number of key bits." $this->{_priv_key} .= $this->_password_localize($this->{_priv_key}); } elsif (($this->{_priv_protocol} eq PRIV_PROTOCOL_DRAFT_AESCFB192) || ($this->{_priv_protocol} eq PRIV_PROTOCOL_DRAFT_AESCFB256)) { # Draft AES in the USM Section 3.1.2.1 - "...if the size of the # localized key is not large enough to generate an encryption # key... ...set Kul = Kul || Hnnn(Kul) where Hnnn is the hash # function for the authentication protocol..." my $hnnn; if ($this->{_auth_protocol} eq AUTH_PROTOCOL_HMACMD5) { $hnnn = Digest::MD5->new(); } elsif ($this->{_auth_protocol} eq AUTH_PROTOCOL_HMACSHA) { $hnnn = Digest::SHA1->new(); } else { return $this->_error( 'The authProtocol "%s" is unknown', $this->{_auth_protocol} ); } $this->{_priv_key} .= $hnnn->add($this->{_priv_key})->digest(); } # Truncate the privKey to the appropriate length. my $key_len = { PRIV_PROTOCOL_DES, 16, # RFC 3414 Section 8.2.1 PRIV_PROTOCOL_DRAFT_3DESEDE, 32, # Draft 3DES for USM Section 5.2.1 PRIV_PROTOCOL_AESCFB128, 16, # AES in the USM Section 3.2.1 PRIV_PROTOCOL_DRAFT_AESCFB192, 24, # Draft AES in the USM Section 3.2.1 PRIV_PROTOCOL_DRAFT_AESCFB256, 32 # Draft AES in the USM Section 3.2.1 }; if (!exists $key_len->{$this->{_priv_protocol}}) { return $this->_error( 'The privProtocol "%s" is unknown', $this->{_priv_protocol} ); } $this->{_priv_key} = substr $this->{_priv_key}, 0, $key_len->{$this->{_priv_protocol}}; return $this->{_priv_key}; } sub _priv_key_validate { my ($this) = @_; my $key_len = { PRIV_PROTOCOL_DES, [ 16, 'CBC-DES' ], PRIV_PROTOCOL_DRAFT_3DESEDE, [ 32, 'CBC-3DES-EDE' ], PRIV_PROTOCOL_AESCFB128, [ 16, 'CFB128-AES-128' ], PRIV_PROTOCOL_DRAFT_AESCFB192, [ 24, 'CFB128-AES-192' ], PRIV_PROTOCOL_DRAFT_AESCFB256, [ 32, 'CFB128-AES-256' ] }; if (!exists $key_len->{$this->{_priv_protocol}}) { return $this->_error( 'The privProtocol "%s" is unknown', $this->{_priv_protocol} ); } if (length($this->{_priv_key}) != $key_len->{$this->{_priv_protocol}}->[0]) { return $this->_error( 'The %s privKey length of %d is invalid, expected %d', $key_len->{$this->{_priv_protocol}}->[1], length($this->{_priv_key}), $key_len->{$this->{_priv_protocol}}->[0] ); } if ($this->{_priv_protocol} eq PRIV_PROTOCOL_DRAFT_3DESEDE) { # Draft 3DES-EDE for USM Section 5.1.1.1.1 "The checks for difference # and weakness... ...should be performed when the key is assigned. # If any of the mandated tests fail, then the whole key MUST be # discarded and an appropriate exception noted." if (substr($this->{_priv_key}, 0, 8) eq substr $this->{_priv_key}, 8, 8) { return $this->_error( 'The CBC-3DES-EDE privKey is invalid (K1 equals K2)' ); } if (substr($this->{_priv_key}, 8, 8) eq substr $this->{_priv_key}, 16, 8) { return $this->_error( 'The CBC-3DES-EDE privKey is invalid (K2 equals K3)' ); } if (substr($this->{_priv_key}, 0, 8) eq substr $this->{_priv_key}, 16, 8) { return $this->_error( 'The CBC-3DES-EDE privKey is invalid (K1 equals K3)' ); } } return TRUE; } sub _password_localize { my ($this, $password) = @_; my $digests = { AUTH_PROTOCOL_HMACMD5, 'Digest::MD5', AUTH_PROTOCOL_HMACSHA, 'Digest::SHA1', }; if (!exists $digests->{$this->{_auth_protocol}}) { return $this->_error( 'The authProtocol "%s" is unknown', $this->{_auth_protocol} ); } my $digest = $digests->{$this->{_auth_protocol}}->new; # Create the initial digest using the password my $d = my $pad = $password x ((2048 / length $password) + 1); for (my $count = 0; $count < 2**20; $count += 2048) { $digest->add(substr $d, 0, 2048, q{}); $d .= $pad; } $d = $digest->digest; # Localize the key with the authoritativeEngineID return $digest->add($d . $this->{_engine_id} . $d)->digest(); } { my %modules; sub load_module { my ($module) = @_; # We attempt to load the required module under the protection of an # eval statement. If there is a failure, typically it is due to a # missing module required by the requested module and we attempt to # simplify the error message by just listing that module. We also # need to track failures since require() only produces an error on # the first attempt to load the module. # NOTE: Contrary to our typical convention, a return value of "undef" # actually means success and a defined value means error. return $modules{$module} if exists $modules{$module}; if (!eval "require $module") { if ($@ =~ /locate (\S+\.pm)/) { $modules{$module} = sprintf '(Required module %s not found)', $1; } else { $modules{$module} = sprintf '(%s)', $@; } } else { $modules{$module} = undef; } return $modules{$module}; } } # ============================================================================ 1; # [end Net::SNMP::Security::USM]
Close