File 0960-Fix-PrivParams-for-SNMPv3-USM-with-AES-privacy.patch of Package erlang
From a33b8c2e52e766f3ee90dae9d122d3d8e00528a9 Mon Sep 17 00:00:00 2001
From: "Jonathan D. Storm" <jds@idio.link>
Date: Sun, 15 Jul 2018 13:56:17 -0500
Subject: [PATCH 1/4] Fix PrivParams for SNMPv3 USM with AES privacy
* In `snmp_usm:do_decrypt/3`, pass full UsmSecParams to
`snmp_usm:try_decrypt/5` as expected by AES clause.
* Change `snmpm_usm:aes_encrypt/3` to use EngineBoots and
EngineTime as cached by `snmpm_config:get_usm_eboots/1`
and `snmpm_config:get_usm_etime/1` instead of
`snmpm_config:get_engine_boots/0` and
`snmpm_config:get_engine_time/0`. This ensures correct
msgPrivacyParameters are sent when AES is used.
* Add test `snmp.snmp_manager_SUITE.usm_priv_aes/1` to
avoid regression.
* Fix counting bug in `snmp_usm` macro `?BLOCK_CIPHER_AES`,
introduced by commit 8d942cd.
---
lib/snmp/src/manager/snmpm_usm.erl | 36 +++----
lib/snmp/src/misc/snmp_usm.erl | 11 +-
lib/snmp/test/snmp_manager_SUITE.erl | 155 ++++++++++++++++++++++++++-
3 files changed, 179 insertions(+), 23 deletions(-)
diff --git a/lib/snmp/src/manager/snmpm_usm.erl b/lib/snmp/src/manager/snmpm_usm.erl
index 7dd79e703a..9e625d0315 100644
--- a/lib/snmp/src/manager/snmpm_usm.erl
+++ b/lib/snmp/src/manager/snmpm_usm.erl
@@ -268,15 +268,16 @@ decrypt(Data, UsmUser, UsmSecParams, SecLevel) ->
do_decrypt(Data, #usm_user{sec_name = SecName,
priv = PrivP,
priv_key = PrivKey},
- #usmSecurityParameters{msgPrivacyParameters = PrivParms}) ->
+ UsmSecParams) ->
EncryptedPDU = snmp_pdus:dec_scoped_pdu_data(Data),
- try_decrypt(PrivP, PrivKey, PrivParms, EncryptedPDU, SecName).
+ try_decrypt(PrivP, PrivKey, UsmSecParams, EncryptedPDU, SecName).
try_decrypt(usmNoPrivProtocol, _, _, _, SecName) -> % 3.2.5
error(usmStatsUnsupportedSecLevels,
?usmStatsUnsupportedSecLevels_instance, SecName);
try_decrypt(usmDESPrivProtocol,
- PrivKey, MsgPrivParams, EncryptedPDU, SecName) ->
+ PrivKey, UsmSecParams, EncryptedPDU, SecName) ->
+ #usmSecurityParameters{msgPrivacyParameters = MsgPrivParams} = UsmSecParams,
case (catch des_decrypt(PrivKey, MsgPrivParams, EncryptedPDU)) of
{ok, DecryptedData} ->
DecryptedData;
@@ -328,11 +329,6 @@ generate_outgoing_msg(Message, SecEngineID, SecName, SecData, SecLevel) ->
_ -> % 3.1.1a
SecData
end,
- %% 3.1.4
- ?vtrace("generate_outgoing_msg -> (3.1.4)",[]),
- ScopedPduBytes = Message#message.data,
- {ScopedPduData, MsgPrivParams} =
- encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel),
SnmpEngineID = get_engine_id(),
?vtrace("SnmpEngineID: ~p (3.1.6)",[SnmpEngineID]),
%% 3.1.6
@@ -345,6 +341,11 @@ generate_outgoing_msg(Message, SecEngineID, SecName, SecData, SecLevel) ->
_ ->
{get_engine_boots(), get_engine_time()}
end,
+ %% 3.1.4
+ ?vtrace("generate_outgoing_msg -> (3.1.4)",[]),
+ ScopedPduBytes = Message#message.data,
+ {ScopedPduData, MsgPrivParams} = encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel, MsgAuthEngineBoots,
+ MsgAuthEngineTime),
%% 3.1.5 - 3.1.7
?vtrace("generate_outgoing_msg -> (3.1.5 - 3.1.7)",[]),
UsmSecParams =
@@ -361,12 +362,12 @@ generate_outgoing_msg(Message, SecEngineID, SecName, SecData, SecLevel) ->
%% Ret: {ScopedPDU, MsgPrivParams} - both are already encoded as OCTET STRINGs
-encrypt(Data, PrivProtocol, PrivKey, SecLevel) ->
+encrypt(Data, PrivProtocol, PrivKey, SecLevel, EngineBoots, EngineTime) ->
case snmp_misc:is_priv(SecLevel) of
false -> % 3.1.4b
{Data, []};
true -> % 3.1.4a
- case (catch try_encrypt(PrivProtocol, PrivKey, Data)) of
+ case (catch try_encrypt(PrivProtocol, PrivKey, Data, EngineBoots, EngineTime)) of
{ok, ScopedPduData, MsgPrivParams} ->
{snmp_pdus:enc_oct_str_tag(ScopedPduData), MsgPrivParams};
{error, Reason} ->
@@ -376,12 +377,12 @@ encrypt(Data, PrivProtocol, PrivKey, SecLevel) ->
end
end.
-try_encrypt(usmNoPrivProtocol, _PrivKey, _Data) -> % 3.1.2
+try_encrypt(usmNoPrivProtocol, _PrivKey, _Data, _EngineBoots, _EngineTime) -> % 3.1.2
error(unsupportedSecurityLevel);
-try_encrypt(usmDESPrivProtocol, PrivKey, Data) ->
+try_encrypt(usmDESPrivProtocol, PrivKey, Data, _EngineBoots, _EngineTime) ->
des_encrypt(PrivKey, Data);
-try_encrypt(usmAesCfb128Protocol, PrivKey, Data) ->
- aes_encrypt(PrivKey, Data).
+try_encrypt(usmAesCfb128Protocol, PrivKey, Data, EngineBoots, EngineTime) ->
+ aes_encrypt(PrivKey, Data, EngineBoots, EngineTime).
authenticate_outgoing(Message, UsmSecParams,
AuthKey, AuthProtocol, SecLevel) ->
@@ -419,11 +420,8 @@ get_des_salt() ->
EngineBoots = get_engine_boots(),
[?i32(EngineBoots), ?i32(SaltInt)].
-aes_encrypt(PrivKey, Data) ->
- EngineBoots = get_engine_boots(),
- EngineTime = get_engine_time(),
- snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0,
- EngineBoots, EngineTime).
+aes_encrypt(PrivKey, Data, EngineBoots, EngineTime) ->
+ snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0, EngineBoots, EngineTime).
aes_decrypt(PrivKey, UsmSecParams, EncData) ->
#usmSecurityParameters{msgPrivacyParameters = MsgPrivParams,
diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl
index bae6bdec72..149d9f0dfb 100644
--- a/lib/snmp/src/misc/snmp_usm.erl
+++ b/lib/snmp/src/misc/snmp_usm.erl
@@ -45,7 +45,12 @@
-define(i32(Int), (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255).
--define(BLOCK_CIPHER_AES, aes_cfb128).
+-define(BLOCK_CIPHER_AES(Key), case bit_size(iolist_to_binary(Key)) of
+ 128 -> aes_128_cfb128;
+ 192 -> aes_192_cfb128;
+ 256 -> aes_256_cfb128
+ end).
+
-define(BLOCK_CIPHER_DES, des_cbc).
@@ -248,7 +253,7 @@ aes_encrypt(PrivKey, Data, SaltFun, EngineBoots, EngineTime) ->
AesKey = PrivKey,
Salt = SaltFun(),
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
- EncData = crypto:block_encrypt(?BLOCK_CIPHER_AES,
+ EncData = crypto:block_encrypt(?BLOCK_CIPHER_AES(AesKey),
AesKey, IV, Data),
{ok, binary_to_list(EncData), Salt}.
@@ -258,7 +263,7 @@ aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
Salt = MsgPrivParams,
IV = list_to_binary([?i32(EngineBoots), ?i32(EngineTime) | Salt]),
%% Whatabout errors here??? E.g. not a mulitple of 8!
- Data = binary_to_list(crypto:block_decrypt(?BLOCK_CIPHER_AES,
+ Data = binary_to_list(crypto:block_decrypt(?BLOCK_CIPHER_AES(AesKey),
AesKey, IV, EncData)),
Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
{ok, Data2}.
--
2.26.2