[erlang-bugs] snmp agent inform w/AES privacy not working

Raimo Niskanen raimo+erlang-bugs@REDACTED
Wed Aug 6 11:51:33 CEST 2014


Sorry about the looong delay but I have just created a ticket for
this, now awaiting to be prioritized...

/ Raimo


On Tue, Feb 25, 2014 at 11:56:32AM -0600, Daniel Goertzen wrote:
> The SNMP agent AES initialization vector calculation is definitely wrong.
>  The IV is composed from the authoritative engine boots, engine time, and a
> random locally generated number.  The agent is currently always using the
> *local* engine to get engine boots and engine time, which happens to be
> correct for GET, SET, and TRAP, but is wrong for INFORM.
> 
> The attached patch fixes it.  When composing a packet for transmission, the
> existing code collects the correct engine parameters, so this patch just
> uses those for the AES IV instead of going off and getting the wrong local
> engine params.  The patch looks bigger than it really is because the order
> of packet composition had to be changed slightly.
> 
> With this patch applied, I am able to send AES encrypted informs.  AES
> encrypted traps also continued to work.
> 
> Cheers,
> Dan.
> 
> 
> On Mon, Feb 24, 2014 at 4:57 PM, Daniel Goertzen
> <daniel.goertzen@REDACTED>wrote:
> 
> > I am struggling to get SNMP informs with AES privacy working.  I have no
> > problems with DES privacy on informs.
> >
> > In snmpa_usm.erl I see that the *local engine* boots and time is passed to
> > snmp_usm:aes_encrypt() which forms part of the IV....
> >
> >
> >
> > However RFC 3826 states that the *authoritative* engine boots and time
> > should be used, and in the case of informs the authoritative engine is the
> > inform target engine, not the local engine....
> >
> > [from RFC 3826]
> >
> > 3.1.2.1.  AES Encryption Key and IV
> >
> >    The first 128 bits of the localized key Kul are used as the AES
> >    encryption key.  The 128-bit IV is obtained as the concatenation of
> >    the authoritative SNMP engine's 32-bit snmpEngineBoots, the SNMP
> >    engine's 32-bit snmpEngineTime, and a local 64-bit integer.  The 64-
> >    bit integer is initialized to a pseudo-random value at boot time.
> >
> >
> >
> > Could this be why AES privacy is not working for informs?
> >
> > Dan.
> >

> diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl
> index 719ea4e..0c3528a 100644
> --- a/lib/snmp/src/agent/snmpa_usm.erl
> +++ b/lib/snmp/src/agent/snmpa_usm.erl
> @@ -474,6 +474,23 @@ generate_outgoing_msg(Message, SecEngineID, SecName, SecData, SecLevel,
>  	    _ -> % 3.1.1a
>  		SecData
>  	end,
> +    %% 3.1.6
> +    SnmpEngineID = LocalEngineID,
> +    ?vtrace("generate_outgoing_msg -> SnmpEngineID: ~p [3.1.6]",
> +            [SnmpEngineID]),
> +    {MsgAuthEngineBoots, MsgAuthEngineTime} =
> +    case snmp_misc:is_auth(SecLevel) of
> +        false when SecData =:= [] -> % not a response
> +            {0, 0};
> +        false when UserName =:= "" -> % reply (report) to discovery step 1
> +            {0, 0};
> +        true when SecEngineID =/= SnmpEngineID ->
> +            {get_engine_boots(SecEngineID),
> +             get_engine_time(SecEngineID)};
> +        _ ->
> +            {get_local_engine_boots(SnmpEngineID),
> +             get_local_engine_time(SnmpEngineID)}
> +    end,
>      %% 3.1.4
>      ?vtrace("generate_outgoing_msg -> [3.1.4]"
>  	    "~n   UserName:     ~p"
> @@ -482,24 +499,7 @@ generate_outgoing_msg(Message, SecEngineID, SecName, SecData, SecLevel,
>  	    [UserName, AuthProtocol, PrivProtocol]),
>      ScopedPduBytes = Message#message.data,
>      {ScopedPduData, MsgPrivParams} =
> -	encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel),
> -    SnmpEngineID = LocalEngineID, 
> -    ?vtrace("generate_outgoing_msg -> SnmpEngineID: ~p [3.1.6]",
> -	    [SnmpEngineID]),
> -    %% 3.1.6
> -    {MsgAuthEngineBoots, MsgAuthEngineTime} =
> -	case snmp_misc:is_auth(SecLevel) of
> -	    false when SecData =:= [] -> % not a response
> -		{0, 0}; 
> -	    false when UserName =:= "" -> % reply (report) to discovery step 1
> -		{0, 0}; 
> -	    true when SecEngineID =/= SnmpEngineID ->
> -		{get_engine_boots(SecEngineID),
> -		 get_engine_time(SecEngineID)};
> -	    _ ->
> -		{get_local_engine_boots(SnmpEngineID),
> -		 get_local_engine_time(SnmpEngineID)}
> -	end,
> +	encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel, MsgAuthEngineBoots, MsgAuthEngineTime),
>      %% 3.1.5 - 3.1.7
>      ?vtrace("generate_outgoing_msg -> [3.1.5 - 3.1.7]",[]),
>      UsmSecParams =
> @@ -560,12 +560,14 @@ generate_discovery_msg(Message,
>  		end
>  	end,
>      ScopedPduBytes = Message#message.data,
> +    Boots = 0,
> +    Time = 0,
>      {ScopedPduData, MsgPrivParams} =
> -	encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel),
> +	encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel, Boots, Time),
>      UsmSecParams =
>  	#usmSecurityParameters{msgAuthoritativeEngineID    = SecEngineID, 
> -			       msgAuthoritativeEngineBoots = 0, % Boots, 
> -			       msgAuthoritativeEngineTime  = 0, % Time, 
> +			       msgAuthoritativeEngineBoots = Boots,
> +			       msgAuthoritativeEngineTime  = Time,
>  			       msgUserName                 = UserName,
>  			       msgPrivacyParameters        = MsgPrivParams},
>      Message2 = Message#message{data = ScopedPduData},
> @@ -574,14 +576,14 @@ generate_discovery_msg(Message,
>  
>      
>  %% Ret: {ScopedPDU, MsgPrivParams} - both are already encoded as OCTET STRINGs
> -encrypt(Data, PrivProtocol, PrivKey, SecLevel) ->
> +encrypt(Data, PrivProtocol, PrivKey, SecLevel, AuthEngineBoots, AuthEngineTime) ->
>      case snmp_misc:is_priv(SecLevel) of
>  	false -> % 3.1.4b
>  	    ?vtrace("encrypt -> 3.1.4b",[]),
>  	    {Data, []};
>  	true -> % 3.1.4a
>  	    ?vtrace("encrypt -> 3.1.4a",[]),
> -	    case (catch try_encrypt(PrivProtocol, PrivKey, Data)) of
> +	    case (catch try_encrypt(PrivProtocol, PrivKey, Data, AuthEngineBoots, AuthEngineTime)) of
>  		{ok, ScopedPduData, MsgPrivParams} ->
>  		    ?vtrace("encrypt -> encrypted - now encode tag",[]),
>  		    {snmp_pdus:enc_oct_str_tag(ScopedPduData), MsgPrivParams};
> @@ -596,12 +598,12 @@ encrypt(Data, PrivProtocol, PrivKey, SecLevel) ->
>  	    end
>      end.
>  
> -try_encrypt(?usmNoPrivProtocol, _PrivKey, _Data) -> % 3.1.2
> +try_encrypt(?usmNoPrivProtocol, _PrivKey, _Data, _AuthEngineBoots, _AuthEngineTime) -> % 3.1.2
>      error(unsupportedSecurityLevel);
> -try_encrypt(?usmDESPrivProtocol, PrivKey, Data) ->
> +try_encrypt(?usmDESPrivProtocol, PrivKey, Data, _AuthEngineBoots, _AuthEngineTime) ->
>      des_encrypt(PrivKey, Data);
> -try_encrypt(?usmAesCfb128Protocol, PrivKey, Data) ->
> -    aes_encrypt(PrivKey, Data).
> +try_encrypt(?usmAesCfb128Protocol, PrivKey, Data, AuthEngineBoots, AuthEngineTime) ->
> +    aes_encrypt(PrivKey, Data, AuthEngineBoots, AuthEngineTime).
>  
>  
>  authenticate_outgoing(Message, UsmSecParams, 
> @@ -654,10 +656,8 @@ get_des_salt() ->
>      EngineBoots = snmp_framework_mib:get_engine_boots(),
>      [?i32(EngineBoots), ?i32(SaltInt)].
>  
> -aes_encrypt(PrivKey, Data) ->
> -    EngineBoots = snmp_framework_mib:get_engine_boots(),
> -    EngineTime  = snmp_framework_mib:get_engine_time(),
> -    snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0, 
> +aes_encrypt(PrivKey, Data, EngineBoots, EngineTime) ->
> +    snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0,
>  			 EngineBoots, EngineTime).
>  
>  aes_decrypt(PrivKey, UsmSecParams, EncData) ->

> _______________________________________________
> erlang-bugs mailing list
> erlang-bugs@REDACTED
> http://erlang.org/mailman/listinfo/erlang-bugs


-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB



More information about the erlang-bugs mailing list