Skip to content

Commit

Permalink
Rework unit test to common test
Browse files Browse the repository at this point in the history
  • Loading branch information
platinumthinker committed Sep 27, 2017
1 parent f7a3616 commit 49b0bf8
Show file tree
Hide file tree
Showing 17 changed files with 532 additions and 378 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ otp_release:
- 20.0
install: "true"
script:
- ./rebar3 do compile, eunit && ./rebar3 ct
- ./rebar3 do compile && ./rebar3 do ct && ./rebar3 coveralls send
3 changes: 1 addition & 2 deletions cover.spec
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
{incl_app, eradius, details}.
{import, ".eunit/cover.coverdata"}.
{incl_app, eradius, details}.
{export, "logs/all.coverdata"}.
16 changes: 16 additions & 0 deletions include/eradius_lib.hrl
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
-define(BYTE, integer-unit:8). % Nice syntactic sugar...

-define(DEFAULT_TYPE, realm).
-define(DEFAULT_STRIP, false).
-define(DEFAULT_SEPARATOR, "@").

-define(DEFAULT_OPTIONS, [{type, ?DEFAULT_TYPE},
{strip, ?DEFAULT_STRIP},
{separator, ?DEFAULT_SEPARATOR}]).

-type server() :: {inet:ip_address(), eradius_server:port_number()}.
-type handler() :: {module(), term()}.
-type server_name() :: atom().
Expand Down Expand Up @@ -109,3 +117,11 @@
msg_hmac = false :: boolean(),
eap_msg = <<>> :: binary()
}).


-record(decoder_state, {
request_authenticator :: 'undefined' | binary(),
attrs = [] :: eradius_lib:attribute_list(),
hmac_pos :: 'undefined' | non_neg_integer(),
eap_msg = [] :: [binary()]
}).
4 changes: 1 addition & 3 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{eunit_opts, [verbose]}.

{erl_opts, [debug_info, {parse_transform, lager_transform}]}.
{minimum_otp_vsn, "18.0"}.

Expand All @@ -21,5 +19,5 @@
{coveralls_service_name, "travis-ci"}.
{do_coveralls_after_ct, false}.
{do_coveralls_after_eunit, false}.
{coveralls_coverdata, "logs/all.coverdata"}.
{coveralls_coverdata, "_build/test/cover/ct.coverdata"}.
{coveralls_service_name, "travis-ci"}.
109 changes: 8 additions & 101 deletions src/eradius_auth.erl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@
-module(eradius_auth).
-export([check_password/2]).
-export([pap/2, chap/3, ms_chap/3, ms_chap_v2/4]).
-export([des_key_from_hash/1, nt_password_hash/1, challenge_response/2, ascii_to_unicode/1]).
-export([des_key_from_hash/1, nt_password_hash/1, challenge_response/2,
ascii_to_unicode/1]).

-ifdef(TEST).
-export([nt_hash/1, v2_generate_nt_response/4, mppe_get_master_key/2,
mppe_generate_session_keys/3, mppe_get_asymetric_send_start_key/2,
v2_generate_authenticator_response/5]).
-endif.

-include("eradius_lib.hrl").
-include("eradius_dict.hrl").
Expand Down Expand Up @@ -292,103 +299,3 @@ mppe_sha_pad2() ->
16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2,
16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2, 16#F2>>.

%% ------------------------------------------------------------------------------------------
%% -- EUnit Tests
-ifdef(TEST).

-include_lib("eunit/include/eunit.hrl").

%% 0-to-256-char UserName
-define(USERNAME, <<16#55, 16#73, 16#65, 16#72>>).

%% Password
-define(PASSWORD, <<16#63, 16#6C, 16#69, 16#65, 16#6E, 16#74, 16#50, 16#61, 16#73, 16#73>>).

%% 0-to-256-unicode-char Password
-define(UNICODE_PASSWORD, <<16#63, 16#00, 16#6C, 16#00, 16#69, 16#00, 16#65, 16#00, 16#6E, 16#00, 16#74, 16#00, 16#50, 16#00, 16#61, 16#00, 16#73, 16#00, 16#73, 16#00>>).

%% 16-octet AuthenticatorChallenge:
-define(AUTHENTICATOR_CHALLENGE, <<16#5B, 16#5D, 16#7C, 16#7D, 16#7B, 16#3F, 16#2F, 16#3E, 16#3C, 16#2C, 16#60, 16#21, 16#32, 16#26, 16#26, 16#28>>).

%% 16-octet PeerChallenge:
-define(PEER_CHALLENGE, <<16#21, 16#40, 16#23, 16#24, 16#25, 16#5E, 16#26, 16#2A, 16#28, 16#29, 16#5F, 16#2B, 16#3A, 16#33, 16#7C, 16#7E>>).

%% 8-octet Challenge:
-define(CHALLENGE, <<16#D0, 16#2E, 16#43, 16#86, 16#BC, 16#E9, 16#12, 16#26>>).

%% 16-octet PasswordHash:
-define(PASSWORD_HASH, <<16#44, 16#EB, 16#BA, 16#8D, 16#53, 16#12, 16#B8, 16#D6, 16#11, 16#47, 16#44, 16#11, 16#F5, 16#69, 16#89, 16#AE>>).

%% 24 octet NT-Response:
-define(NT_RESPONSE, <<16#82, 16#30, 16#9E, 16#CD, 16#8D, 16#70, 16#8B, 16#5E, 16#A0, 16#8F, 16#AA, 16#39, 16#81, 16#CD, 16#83, 16#54, 16#42, 16#33, 16#11, 16#4A, 16#3D, 16#85, 16#D6, 16#DF>>).

%% 16-octet PasswordHashHash:
-define(PASSWORD_HASHHASH, <<16#41, 16#C0, 16#0C, 16#58, 16#4B, 16#D2, 16#D9, 16#1C, 16#40, 16#17, 16#A2, 16#A1, 16#2F, 16#A5, 16#9F, 16#3F>>).

%% 42-octet AuthenticatorResponse:
-define(AUTHENTICATOR_RESPONSE, <<"S=407A5589115FD0D6209F510FE9C04566932CDA56 ">>).

%% MPPE keys
-define(MASTER_KEY, <<16#FD, 16#EC, 16#E3, 16#71, 16#7A, 16#8C, 16#83, 16#8C, 16#B3, 16#88, 16#E5, 16#27, 16#AE, 16#3C, 16#DD, 16#31>>).
-define(SEND_START_KEY40, <<16#8B, 16#7C, 16#DC, 16#14, 16#9B, 16#99, 16#3A, 16#1B>>).
-define(SEND_SESSION_KEY40, <<16#D1, 16#26, 16#9E, 16#C4, 16#9F, 16#A6, 16#2E, 16#3E>>).
-define(SEND_START_KEY56, <<16#8B, 16#7C, 16#DC, 16#14, 16#9B, 16#99, 16#3A, 16#1B>>).
-define(SEND_SESSION_KEY56, <<16#D1, 16#5C, 16#00, 16#C4, 16#9F, 16#A6, 16#2E, 16#3E>>).
-define(SEND_START_KEY128, <<16#8B, 16#7C, 16#DC, 16#14, 16#9B, 16#99, 16#3A, 16#1B, 16#A1, 16#18, 16#CB, 16#15, 16#3F, 16#56, 16#DC, 16#CB>>).
-define(SEND_SESSION_KEY128, <<16#40, 16#5C, 16#B2, 16#24, 16#7A, 16#79, 16#56, 16#E6, 16#E2, 16#11, 16#00, 16#7A, 16#E2, 16#7B, 16#22, 16#D4>>).

%% 0-to-256-unicode-char Password:
-define(PASSWORD2, <<16#4D, 16#79, 16#50, 16#77>>).

%% 16-octet PasswordHash:
-define(PASSWORD_HASH2, <<16#FC, 16#15, 16#6A, 16#F7, 16#ED, 16#CD, 16#6C, 16#0E, 16#DD, 16#E3, 16#33, 16#7D, 16#42, 16#7F, 16#4E, 16#AC>>).

%% parity-corrected DES key:
-define(DES_KEY, <<16#FD, 16#0B, 16#5B, 16#5E, 16#7F, 16#6E, 16#34, 16#D9, 16#0E, 16#6E, 16#79, 16#67, 16#37, 16#EA, 16#08, 16#FE, 16#4F, 16#57>>).

unicode_test() ->
?UNICODE_PASSWORD = ascii_to_unicode(?PASSWORD).

password_hash_test() ->
?PASSWORD_HASH = nt_password_hash(?PASSWORD).

unicode_password_hash_test() ->
?PASSWORD_HASH = nt_hash(?UNICODE_PASSWORD).

password_hashhash_test() ->
?PASSWORD_HASHHASH = nt_hash(nt_hash(?UNICODE_PASSWORD)).

password_hash2_test() ->
?PASSWORD_HASH2 = nt_password_hash(?PASSWORD2).

des_key_test() ->
?DES_KEY = des_key_from_hash(?PASSWORD_HASH2).

nt_response_test() ->
?NT_RESPONSE = v2_generate_nt_response(?AUTHENTICATOR_CHALLENGE, ?PEER_CHALLENGE, ?USERNAME, ?PASSWORD_HASH).

v2_authenticator_test() ->
?AUTHENTICATOR_RESPONSE = v2_generate_authenticator_response(?PASSWORD_HASH, ?NT_RESPONSE, ?PEER_CHALLENGE, ?AUTHENTICATOR_CHALLENGE, ?USERNAME).

mppe_master_key_test() ->
?MASTER_KEY = mppe_get_master_key(?PASSWORD_HASHHASH, ?NT_RESPONSE).

mppe_sendstart_key40_test()->
?SEND_START_KEY40 = mppe_get_asymetric_send_start_key(?MASTER_KEY, 8).

mppe_sendstart_key56_test()->
?SEND_START_KEY56 = mppe_get_asymetric_send_start_key(?MASTER_KEY, 8).

mppe_sendstart_key128_test()->
?SEND_START_KEY128 = mppe_get_asymetric_send_start_key(?MASTER_KEY, 16).

mppe_start_key40_test()->
{?SEND_START_KEY40, _ } = mppe_generate_session_keys(?PASSWORD_HASH, ?NT_RESPONSE, 40).

mppe_start_key56_test()->
{?SEND_START_KEY56, _ } = mppe_generate_session_keys(?PASSWORD_HASH, ?NT_RESPONSE, 56).

mppe_start_key128_test()->
{?SEND_START_KEY128, _ } = mppe_generate_session_keys(?PASSWORD_HASH, ?NT_RESPONSE, 128).

-endif.
17 changes: 0 additions & 17 deletions src/eradius_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -358,20 +358,3 @@ generate_ip(E, E) ->
generate_ip(S, E) ->
<<A:8, B:8, C:8, D:8>> = <<S:32/integer>>,
[{A, B, C, D} | generate_ip(S+1, E)].


%% ------------------------------------------------------------------------------------------
%% -- EUnit Tests
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").

generate_ip_list_test() ->
?assertEqual([{192, 168, 11, 148}, {192, 168, 11, 149}, {192, 168, 11, 150}, {192, 168, 11, 151}],
generate_ip_list({192, 168, 11, 150}, "30")),
generate_ip_list({192, 168, 11, 150}, 24),
?assertEqual(256, length(generate_ip_list({192, 168, 11, 150}, 24))),
?assertEqual(2048, length(generate_ip_list({192, 168, 11, 10}, 21))),
?assertMatch({invalid, _}, generate_ip_list({192, 168, 11, 150}, "34")),
ok.

-endif.
122 changes: 9 additions & 113 deletions src/eradius_lib.erl
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
% -compile(bin_opt_info).

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-export([encode_value/2, decode_value/2]).
-export([encode_value/2, decode_value/2, scramble/3]).
-export([salt_encrypt/4, salt_decrypt/3, encode_attribute/3, decode_attribute/5]).
-endif.
-include("eradius_lib.hrl").
-include("eradius_dict.hrl").
Expand Down Expand Up @@ -220,13 +220,6 @@ encode_value(date, Date = {{_,_,_},{_,_,_}}) ->
%% ------------------------------------------------------------------------------------------
%% -- Wire Decoding

-record(decoder_state, {
request_authenticator :: 'undefined' | binary(),
attrs = [] :: eradius_lib:attribute_list(),
hmac_pos :: 'undefined' | non_neg_integer(),
eap_msg = [] :: [binary()]
}).

-spec decode_request_id(binary()) -> {0..255, binary()} | {bad_pdu, list()}.
decode_request_id(Req = <<_Cmd:8, ReqId:8, _Rest/binary>>) -> {ReqId, Req};
decode_request_id(_Req) -> {bad_pdu, "invalid request id"}.
Expand Down Expand Up @@ -278,9 +271,9 @@ validate_packet_authenticator(Cmd, ReqId, Len, Auth, Body, Pos, Secret) ->
case Body of
<<Before:Pos/bytes, Value:16/bytes, After/binary>> ->
case crypto:hmac(md5, Secret, [<<Cmd:8, ReqId:8, Len:16>>, Auth, Before, zero_authenticator(), After]) of
Value ->
Value ->
ok;
_ ->
_ ->
throw({bad_pdu, "Message-Authenticator Attribute is invalid"})
end;
_ ->
Expand All @@ -290,7 +283,7 @@ validate_packet_authenticator(Cmd, ReqId, Len, Auth, Body, Pos, Secret) ->
validate_authenticator(accreq, Head, _RequestAuthenticator, PacketAuthenticator, Body, Secret) ->
compare_authenticator(crypto:hash(md5, [Head, zero_authenticator(), Body, Secret]), PacketAuthenticator);
validate_authenticator(Cmd, Head, RequestAuthenticator, PacketAuthenticator, Body, Secret)
when
when
(Cmd =:= accept) orelse
(Cmd =:= reject) orelse
(Cmd =:= accresp) orelse
Expand All @@ -300,10 +293,10 @@ validate_authenticator(Cmd, Head, RequestAuthenticator, PacketAuthenticator, Bod
(Cmd =:= discnak) orelse
(Cmd =:= challenge) ->
compare_authenticator(crypto:hash(md5, [Head, RequestAuthenticator, Body, Secret]), PacketAuthenticator);
validate_authenticator(_Cmd, _Head, _RequestAuthenticator, _PacketAuthenticator, _Body, _Secret) ->
validate_authenticator(_Cmd, _Head, _RequestAuthenticator, _PacketAuthenticator, _Body, _Secret) ->
true.

compare_authenticator(Authenticator, Authenticator) ->
compare_authenticator(Authenticator, Authenticator) ->
true;
compare_authenticator(_RequestAuthenticator, _PacketAuthenticator) ->
throw({bad_pdu, "Authenticator Attribute is invalid"}).
Expand Down Expand Up @@ -461,7 +454,7 @@ do_scramble(_SharedSecret, _B, << >>, CipherText) ->

-spec generate_salt() -> salt().
generate_salt() ->
<<Salt1, Salt2>> = crypto:strong_rand_bytes(2),
<<Salt1, Salt2>> = crypto:strong_rand_bytes(2),
<<(Salt1 bor 16#80), Salt2>>.

-spec salt_encrypt(salt(), secret(), authenticator(), binary()) -> binary().
Expand Down Expand Up @@ -511,108 +504,11 @@ timestamp() ->
erlang:timestamp()
catch
error:undef ->
% call erlang:now() via erlang:apply/3
% call erlang:now() via erlang:apply/3
% for getting rid annoying compile warning on OTP >= 18
erlang:apply(erlang, now, [])
end.

-spec printable_peer(inet:ip4_address(),eradius_server:port_number()) -> io_lib:chars().
printable_peer({IA,IB,IC,ID}, Port) ->
io_lib:format("~b.~b.~b.~b:~b",[IA,IB,IC,ID,Port]).

-ifdef(TEST).

%%
%% EUnit Tests
%%
-define(SALT, <<171,213>>).
-define(REQUEST_AUTHENTICATOR, << 1, 2, 3, 4, 5, 6, 7, 8 >>).
-define(USER, "test").
-define(SECRET, <<"secret">>).
-define(PLAIN_TEXT, "secret").
-define(PLAIN_TEXT_PADDED, <<"secret",0,0,0,0,0,0,0,0,0,0>>).
-define(CIPHER_TEXT, <<171,213,166,95,152,126,124,120,86,10,78,216,190,216,26,87,55,15>>).
-define(ENC_PASSWORD, 186,128,194,207,68,25,190,19,23,226,48,206,244,143,56,238).
-define(PDU, #radius_request{ reqid = 1, secret = ?SECRET, authenticator = ?REQUEST_AUTHENTICATOR }).

selt_encrypt_test() ->
?CIPHER_TEXT = salt_encrypt(?SALT, ?SECRET, ?REQUEST_AUTHENTICATOR, << ?PLAIN_TEXT >>).

salt_decrypt_test() ->
<< ?PLAIN_TEXT >> = salt_decrypt(?SECRET, ?REQUEST_AUTHENTICATOR, ?CIPHER_TEXT).

scramble_enc_test() ->
<< ?ENC_PASSWORD >> = scramble(?SECRET, ?REQUEST_AUTHENTICATOR, << ?PLAIN_TEXT >>).

scramble_dec_test() ->
?PLAIN_TEXT_PADDED = scramble(?SECRET, ?REQUEST_AUTHENTICATOR, << ?ENC_PASSWORD >>).

enc_simple_test() ->
L = length(?USER) + 2,
<< ?RUser_Name, L:8, ?USER >> = encode_attribute(?PDU, #attribute{id = ?RUser_Name, type = string, enc = no}, << ?USER >>).

enc_scramble_test() ->
L = 16 + 2,
<< ?RUser_Passwd, L:8, ?ENC_PASSWORD >> = encode_attribute(?PDU, #attribute{id = ?RUser_Passwd, type = string, enc = scramble}, << ?PLAIN_TEXT >>).

enc_salt_test() ->
L = 16 + 4,
<< ?RUser_Passwd, L:8, Enc/binary >> = encode_attribute(?PDU, #attribute{id = ?RUser_Passwd, type = string, enc = salt_crypt}, << ?PLAIN_TEXT >>),
%% need to decrypt to verfiy due to salt
<< ?PLAIN_TEXT >> = salt_decrypt(?SECRET, ?REQUEST_AUTHENTICATOR, Enc).

enc_vendor_test() ->
L = length(?USER),
E = << ?RVendor_Specific, (L+8):8, 18681:32, 1:8, (L+2):8, ?USER >>,
E = encode_attribute(?PDU, #attribute{id = {18681,1}, type = string, enc = no}, << ?USER >>).

enc_vendor_octet_test() ->
E = << ?RVendor_Specific, (4+8):8, 311:32, 7:8, (4+2):8, 7:32 >>,
E = encode_attribute(?PDU, #attribute{id = {311,7}, type = octets, enc = no}, 7).

decode_attribute(A, B, C) -> decode_attribute(A, B, C, 0, #decoder_state{}).

dec_simple_integer_test() ->
State = decode_attribute(<<0,0,0,1>>, ?PDU, #attribute{id = 40, type = integer, enc = no}),
[{_, 1}] = State#decoder_state.attrs.

dec_simple_string_test() ->
State = decode_attribute(<<"29113">>, ?PDU, #attribute{id = 44, type = string, enc = no}),
[{_, <<"29113">>}] = State#decoder_state.attrs.

dec_simple_ipv4_test() ->
State = decode_attribute(<<10,33,0,1>>, ?PDU, #attribute{id = 4, type = ipaddr, enc = no}),
[{_, {10,33,0,1}}] = State#decoder_state.attrs.

dec_vendor_test_() ->
{setup,
fun() ->
application:set_env(eradius, tables, [dictionary]),
eradius_dict:start_link(),
ok
end,
fun(_) ->
ok
end,
[
{"dec_vendor_ipv4_t", fun dec_vendor_integer_t/0},
{"dec_vendor_string_t", fun dec_vendor_string_t/0},
{"dec_vendor_ipv4_t", fun dec_vendor_ipv4_t/0}
]
}.

dec_vendor_integer_t() ->
State = decode_attribute(<<0,0,40,175,3,6,0,0,0,0>>, ?PDU, #attribute{id = ?RVendor_Specific, type = octets, enc = no}),
[{_, <<0, 0, 0, 0>>}] = State#decoder_state.attrs.

dec_vendor_string_t() ->
State = decode_attribute(<<0,0,40,175,8,7,"23415">>, ?PDU, #attribute{id = ?RVendor_Specific, type = octets, enc = no}),
[{_, <<"23415">>}] = State#decoder_state.attrs.

dec_vendor_ipv4_t() ->
State = decode_attribute(<<0,0,40,175,6,6,212,183,144,246>>, ?PDU, #attribute{id = ?RVendor_Specific, type = octets, enc = no}),
[{_, <<212,183,144,246>>}] = State#decoder_state.attrs.

%% TODO: add more tests

-endif.
Loading

0 comments on commit 49b0bf8

Please sign in to comment.