diff options
Diffstat (limited to 'lib/snmp/src/misc/snmp_usm.erl')
-rw-r--r-- | lib/snmp/src/misc/snmp_usm.erl | 305 |
1 files changed, 242 insertions, 63 deletions
diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl index e46993aad4..9652e3a3ff 100644 --- a/lib/snmp/src/misc/snmp_usm.erl +++ b/lib/snmp/src/misc/snmp_usm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2016. All Rights Reserved. +%% Copyright Ericsson AB 2004-2021. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,6 +34,8 @@ -include("snmp_types.hrl"). -include("SNMP-USER-BASED-SM-MIB.hrl"). -include("SNMP-USM-AES-MIB.hrl"). +-include("SNMP-USM-HMAC-SHA2-MIB.hrl"). +-include("snmp_usm.hrl"). -define(VMODULE,"USM"). -include("snmp_verbosity.hrl"). @@ -41,7 +43,15 @@ %%----------------------------------------------------------------- --define(twelwe_zeros, [0,0,0,0,0,0,0,0,0,0,0,0]). +-define(zeros12, [0,0,0,0,0,0,0,0,0,0,0,0]). +-define(zeros16, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]). +-define(zeros24, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0]). +-define(zeros32, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]). +-define(zeros48, [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]). -define(i32(Int), (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255). @@ -65,6 +75,14 @@ %% The algorithm is described in appendix A.1 2) of %% rfc2274. %%----------------------------------------------------------------- + +-type algorithm() :: md5 | sha | sha224 | sha256 | sha384 | sha512. + +-spec passwd2localized_key(Alg :: algorithm(), + Passwd :: string(), + EngineID :: string()) -> + LocalizedKey :: list(). + passwd2localized_key(Alg, Passwd, EngineID) when length(Passwd) > 0 -> Key = mk_digest(Alg, Passwd), localize_key(Alg, Key, EngineID). @@ -73,43 +91,38 @@ passwd2localized_key(Alg, Passwd, EngineID) when length(Passwd) > 0 -> %%----------------------------------------------------------------- %% Func: localize_key/3 %% Types: Alg = md5 | sha -%% Passwd = string() +%% Key = binary() %% EngineID = string() %% Purpose: Localizes an unlocalized key for EngineID. See rfc2274 %% section 2.6 for a definition of localized keys. %%----------------------------------------------------------------- + +-spec localize_key(Alg :: algorithm(), + Key :: binary(), + EngineID :: string()) -> + LocalizedKey :: list(). + localize_key(Alg, Key, EngineID) -> Str = [Key, EngineID, Key], binary_to_list(crypto:hash(Alg, Str)). -mk_digest(md5, Passwd) -> - mk_md5_digest(Passwd); -mk_digest(sha, Passwd) -> - mk_sha_digest(Passwd). - -mk_md5_digest(Passwd) -> - Ctx = crypto:hash_init(md5), - Ctx2 = md5_loop(0, [], Ctx, Passwd, length(Passwd)), - crypto:hash_final(Ctx2). - -md5_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 -> - {Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen), - NCtx = crypto:hash_update(Ctx, Buf64), - md5_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen); -md5_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) -> - Ctx. - -mk_sha_digest(Passwd) -> - Ctx = crypto:hash_init(sha), - Ctx2 = sha_loop(0, [], Ctx, Passwd, length(Passwd)), +mk_digest(Alg, Passwd) + when (Alg =:= md5) orelse + (Alg =:= sha) orelse + (Alg =:= sha224) orelse + (Alg =:= sha256) orelse + (Alg =:= sha384) orelse + (Alg =:= sha512) -> + Ctx = crypto:hash_init(Alg), + Ctx2 = mk_digest_loop(0, [], Ctx, Passwd, length(Passwd)), crypto:hash_final(Ctx2). -sha_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 -> +mk_digest_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 -> {Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen), NCtx = crypto:hash_update(Ctx, Buf64), - sha_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen); -sha_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) -> + mk_digest_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen); +mk_digest_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) -> Ctx. %% Create a 64 bytes long string, by repeating Passwd as many times @@ -137,20 +150,122 @@ auth_in(?usmHMACMD5AuthProtocol, AuthKey, AuthParams, Packet) -> auth_in(usmHMACSHAAuthProtocol, AuthKey, AuthParams, Packet) -> sha_auth_in(AuthKey, AuthParams, Packet); auth_in(?usmHMACSHAAuthProtocol, AuthKey, AuthParams, Packet) -> - sha_auth_in(AuthKey, AuthParams, Packet). + sha_auth_in(AuthKey, AuthParams, Packet); +auth_in(usmHMAC128SHA224AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha224) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha224, + ?usmHMAC128SHA224AuthProtocol_secret_key_length, + ?usmHMAC128SHA224AuthProtocol_mac_length); +auth_in(?usmHMAC128SHA224AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha224) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha224, + ?usmHMAC128SHA224AuthProtocol_secret_key_length, + ?usmHMAC128SHA224AuthProtocol_mac_length); +auth_in(usmHMAC192SHA256AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha256) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha256, + ?usmHMAC192SHA256AuthProtocol_secret_key_length, + ?usmHMAC192SHA256AuthProtocol_mac_length); +auth_in(?usmHMAC192SHA256AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha256) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha256, + ?usmHMAC192SHA256AuthProtocol_secret_key_length, + ?usmHMAC192SHA256AuthProtocol_mac_length); +auth_in(usmHMAC256SHA384AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha384) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha384, + ?usmHMAC256SHA384AuthProtocol_secret_key_length, + ?usmHMAC256SHA384AuthProtocol_mac_length); +auth_in(?usmHMAC256SHA384AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha384) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha384, + ?usmHMAC256SHA384AuthProtocol_secret_key_length, + ?usmHMAC256SHA384AuthProtocol_mac_length); +auth_in(usmHMAC384SHA512AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha512) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha512, + ?usmHMAC384SHA512AuthProtocol_secret_key_length, + ?usmHMAC384SHA512AuthProtocol_mac_length); +auth_in(?usmHMAC384SHA512AuthProtocol, AuthKey, AuthParams, Packet) -> + ?vtrace("auth_in(sha512) -> entry"), + sha2_auth_in(AuthKey, AuthParams, Packet, + sha512, + ?usmHMAC384SHA512AuthProtocol_secret_key_length, + ?usmHMAC384SHA512AuthProtocol_mac_length). auth_out(usmNoAuthProtocol, _AuthKey, _Message, _UsmSecParams) -> % 3.1.3 + %% ?vtrace("auth_out(noAuth) -> entry"), error(unSupportedSecurityLevel); auth_out(?usmNoAuthProtocol, _AuthKey, _Message, _UsmSecParams) -> % 3.1.3 + %% ?vtrace("auth_out(noAuth) -> entry"), error(unSupportedSecurityLevel); auth_out(usmHMACMD5AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(md5) -> entry"), md5_auth_out(AuthKey, Message, UsmSecParams); auth_out(?usmHMACMD5AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(md5) -> entry"), md5_auth_out(AuthKey, Message, UsmSecParams); auth_out(usmHMACSHAAuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha) -> entry"), sha_auth_out(AuthKey, Message, UsmSecParams); auth_out(?usmHMACSHAAuthProtocol, AuthKey, Message, UsmSecParams) -> - sha_auth_out(AuthKey, Message, UsmSecParams). + %% ?vtrace("auth_out(sha) -> entry"), + sha_auth_out(AuthKey, Message, UsmSecParams); +auth_out(usmHMAC128SHA224AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha224) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha224, + ?usmHMAC128SHA224AuthProtocol_secret_key_length, + ?usmHMAC128SHA224AuthProtocol_mac_length); +auth_out(?usmHMAC128SHA224AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha224) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha224, + ?usmHMAC128SHA224AuthProtocol_secret_key_length, + ?usmHMAC128SHA224AuthProtocol_mac_length); +auth_out(usmHMAC192SHA256AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha256) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha256, + ?usmHMAC192SHA256AuthProtocol_secret_key_length, + ?usmHMAC192SHA256AuthProtocol_mac_length); +auth_out(?usmHMAC192SHA256AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha256) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha256, + ?usmHMAC192SHA256AuthProtocol_secret_key_length, + ?usmHMAC192SHA256AuthProtocol_mac_length); +auth_out(usmHMAC256SHA384AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha384) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha384, + ?usmHMAC256SHA384AuthProtocol_secret_key_length, + ?usmHMAC256SHA384AuthProtocol_mac_length); +auth_out(?usmHMAC256SHA384AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha384) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha384, + ?usmHMAC256SHA384AuthProtocol_secret_key_length, + ?usmHMAC256SHA384AuthProtocol_mac_length); +auth_out(usmHMAC384SHA512AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha512) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha512, + ?usmHMAC384SHA512AuthProtocol_secret_key_length, + ?usmHMAC384SHA512AuthProtocol_mac_length); +auth_out(?usmHMAC384SHA512AuthProtocol, AuthKey, Message, UsmSecParams) -> + %% ?vtrace("auth_out(sha512) -> entry"), + sha2_auth_out(AuthKey, Message, UsmSecParams, + sha512, + ?usmHMAC384SHA512AuthProtocol_secret_key_length, + ?usmHMAC384SHA512AuthProtocol_mac_length). md5_auth_out(AuthKey, Message, UsmSecParams) -> %% ?vtrace("md5_auth_out -> entry with" @@ -158,7 +273,7 @@ md5_auth_out(AuthKey, Message, UsmSecParams) -> %% "~n Message: ~w" %% "~n UsmSecParams: ~w", [AuthKey, Message, UsmSecParams]), %% 6.3.1.1 - Message2 = set_msg_auth_params(Message, UsmSecParams, ?twelwe_zeros), + Message2 = set_msg_auth_params(Message, UsmSecParams, ?zeros12), Packet = snmp_pdus:enc_message_only(Message2), %% 6.3.1.2-4 is done by the crypto function %% 6.3.1.4 @@ -174,7 +289,7 @@ md5_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) == 12 -> %% "~n AuthParams: ~w" %% "~n Packet: ~w", [AuthKey, AuthParams, Packet]), %% 6.3.2.3 - Packet2 = patch_packet(binary_to_list(Packet)), + Packet2 = patch_packet(binary_to_list(Packet), ?zeros12), %% 6.3.2.5 MAC = binary_to_list(crypto:macN(hmac, md5, AuthKey, Packet2, 12)), %% 6.3.2.6 @@ -183,15 +298,15 @@ md5_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) == 12 -> MAC == AuthParams; md5_auth_in(_AuthKey, _AuthParams, _Packet) -> %% 6.3.2.1 - ?vtrace("md5_auth_in -> entry with" - "~n _AuthKey: ~p" - "~n _AuthParams: ~p", [_AuthKey, _AuthParams]), + ?vlog("md5_auth_in -> entry with" + "~n _AuthKey: ~p" + "~n _AuthParams: ~p", [_AuthKey, _AuthParams]), false. sha_auth_out(AuthKey, Message, UsmSecParams) -> %% 7.3.1.1 - Message2 = set_msg_auth_params(Message, UsmSecParams, ?twelwe_zeros), + Message2 = set_msg_auth_params(Message, UsmSecParams, ?zeros12), Packet = snmp_pdus:enc_message_only(Message2), %% 7.3.1.2-4 is done by the crypto function %% 7.3.1.4 @@ -201,19 +316,80 @@ sha_auth_out(AuthKey, Message, UsmSecParams) -> sha_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) =:= 12 -> %% 7.3.2.3 - Packet2 = patch_packet(binary_to_list(Packet)), + Packet2 = patch_packet(binary_to_list(Packet), ?zeros12), %% 7.3.2.5 MAC = binary_to_list(crypto:macN(hmac, sha, AuthKey, Packet2, 12)), %% 7.3.2.6 MAC == AuthParams; sha_auth_in(_AuthKey, _AuthParams, _Packet) -> %% 7.3.2.1 - ?vtrace("sha_auth_in -> entry with" - "~n _AuthKey: ~p" - "~n _AuthParams: ~p", [_AuthKey, _AuthParams]), + ?vlog("sha_auth_in -> entry with" + "~n _AuthKey: ~p" + "~n _AuthParams: ~p", [_AuthKey, _AuthParams]), + false. + + +%% RFC:4.2.1 +sha2_auth_out(AuthKey, Message, UsmSecParams, + HashAlg, M, N) + when (length(AuthKey) =:= M) -> + %% ?vtrace("sha2_auth_out -> entry with" + %% "~n AuthKey: ~p" + %% "~n UsmSecParams: ~p" + %% "~n HashAlg: ~p" + %% "~n M: ~p" + %% "~n N: ~p", + %% [AuthKey, UsmSecParams, HashAlg, M, N]), + %% 4.2.1:1 + Message2 = set_msg_auth_params(Message, UsmSecParams, zeros(N)), + Packet = snmp_pdus:enc_message_only(Message2), + %% 7.3.1.2-4 is done by the crypto function + %% 4.2.1:2-3 + MAC = binary_to_list(crypto:macN(hmac, HashAlg, AuthKey, Packet, N)), + %% ?vtrace("sha2_auth_out -> " + %% "~n MAC: ~p", [MAC]), + %% 4.2.1:4-5 + set_msg_auth_params(Message, UsmSecParams, MAC). + +%% RFC:4.2.2 +sha2_auth_in(AuthKey, AuthParams, Packet, + HashAlg, M, N) + when (length(AuthKey) =:= M) andalso + (length(AuthParams) =:= N) -> + %% ?vtrace("sha2_auth_in -> entry with" + %% "~n AuthKey: ~p" + %% "~n AuthParams: ~p" + %% "~n HashAlg: ~p" + %% "~n M: ~p" + %% "~n N: ~p", [AuthKey, AuthParams, HashAlg, M, N]), + %% 4.2.2:3 + Packet2 = patch_packet(binary_to_list(Packet), zeros(N)), + %% 4.2.2:4 + MAC = binary_to_list(crypto:macN(hmac, HashAlg, AuthKey, Packet2, N)), + %% ?vtrace("sha2_auth_in -> " + %% "~n MAC: ~p", [MAC]), + %% 4.2.2:7 + %% true | {false, authenticationFailure} + (MAC == AuthParams); +sha2_auth_in(_AuthKey, _AuthParams, _Packet, + _HashAlg, _M, _N) -> + %% 4.2.2 + ?vlog("sha2_auth_in -> entry with" + "~n _AuthKey: ~p" + "~n _AuthParams: ~p" + "~n _HashAlg: ~p" + "~n _M: ~p" + "~n _N: ~p", [_AuthKey, _AuthParams, _HashAlg, _M, _N]), + %% authenticationError. false. +zeros(16) -> ?zeros16; +zeros(24) -> ?zeros24; +zeros(32) -> ?zeros32; +zeros(48) -> ?zeros48. + + des_encrypt(PrivKey, Data, SaltFun) -> [A,B,C,D,E,F,G,H | PreIV] = PrivKey, DesKey = [A,B,C,D,E,F,G,H], @@ -289,58 +465,61 @@ set_msg_auth_params(Message, UsmSecParams, AuthParams) -> %% Not very nice... %% This function patches the asn.1 encoded message. It changes the -%% AuthenticationParameters to 12 zeros. +%% AuthenticationParameters to 12|16|24|32|48 zeros. %% NOTE: returns a deep list of bytes -patch_packet([48 | T]) -> +patch_packet([48 | T], Patch) -> %% Length for whole packet - 2 is tag for version {Len1, [2 | T1]} = split_len(T), %% Length for version - 48 is tag for header data {Len2, [Vsn,48|T2]} = split_len(T1), %% Length for header data {Len3, T3} = split_len(T2), - [48,Len1,2,Len2,Vsn,48,Len3|pp2(dec_len(Len3),T3)]. + [48,Len1,2,Len2,Vsn,48,Len3|pp2(dec_len(Len3),T3,Patch)]. %% Skip HeaderData - 4 is tag for SecurityParameters -pp2(0,[4|T]) -> +pp2(0,[4|T],Patch) -> %% 48 is tag for UsmSecParams {Len1,[48|T1]} = split_len(T), %% 4 is tag for EngineID {Len2,[4|T2]} = split_len(T1), %% Len 3 is length for EngineID {Len3,T3} = split_len(T2), - [4,Len1,48,Len2,4,Len3|pp3(dec_len(Len3),T3)]; -pp2(N,[H|T]) -> - [H|pp2(N-1,T)]. + [4,Len1,48,Len2,4,Len3|pp3(dec_len(Len3),T3,Patch)]; +pp2(N,[H|T],Patch) -> + [H|pp2(N-1,T,Patch)]. %% Skip EngineID - 2 is tag for EngineBoots -pp3(0,[2|T]) -> +pp3(0,[2|T],Patch) -> {Len1,T1} = split_len(T), - [2,Len1|pp4(dec_len(Len1),T1)]; -pp3(N,[H|T]) -> - [H|pp3(N-1,T)]. + [2,Len1|pp4(dec_len(Len1),T1,Patch)]; +pp3(N,[H|T],Patch) -> + [H|pp3(N-1,T,Patch)]. %% Skip EngineBoots - 2 is tag for EngineTime -pp4(0,[2|T]) -> +pp4(0,[2|T],Patch) -> {Len1,T1} = split_len(T), - [2,Len1|pp5(dec_len(Len1),T1)]; -pp4(N,[H|T]) -> - [H|pp4(N-1,T)]. + [2,Len1|pp5(dec_len(Len1),T1,Patch)]; +pp4(N,[H|T],Patch) -> + [H|pp4(N-1,T,Patch)]. %% Skip EngineTime - 4 is tag for UserName -pp5(0,[4|T]) -> +pp5(0,[4|T],Patch) -> {Len1,T1} = split_len(T), - [4,Len1|pp6(dec_len(Len1),T1)]; -pp5(N,[H|T]) -> - [H|pp5(N-1,T)]. + [4,Len1|pp6(dec_len(Len1),T1,Patch)]; +pp5(N,[H|T],Patch) -> + [H|pp5(N-1,T,Patch)]. %% Skip UserName - 4 is tag for AuthenticationParameters %% This is what we're looking for! -pp6(0,[4|T]) -> - {Len1,[_,_,_,_,_,_,_,_,_,_,_,_|T1]} = split_len(T), - 12 = dec_len(Len1), - [4,Len1,?twelwe_zeros|T1]; -pp6(N,[H|T]) -> - [H|pp6(N-1,T)]. +pp6(0, [4|T], Patch) -> + PatchLen = length(Patch), + {Len1, Rest1} = split_len(T), + PatchLen = dec_len(Len1), % Force match + {_Old, Rest2} = lists:split(PatchLen, Rest1), + %% Patch: list of zeros of length: 12 | 16 | 24 | 32 | 48 + [4, Len1, Patch|Rest2]; +pp6(N,[H|T],Patch) -> + [H|pp6(N-1,T,Patch)]. %% Returns {LengthOctets, Rest} |