Current section

Files

Jump to
kerlberos src krbtests.erl
Raw

src/krbtests.erl

-module(krbtests).
-export([client/0, server/0]).
-include("SPNEGO.hrl").
server() ->
{ok, KeyTab} = krb_mit_keytab:file("keytab"),
Princs = lists:usort([P || #{principal := P} <- KeyTab]),
io:format("keytab has keys for ~p\n", [Princs]),
Etypes = lists:usort([krb_crypto:key_etype(K) || #{key := K} <- KeyTab]),
io:format("etypes = ~p\n", [Etypes]),
{ok, LSock} = gen_tcp:listen(8082,
[binary, {active, true}, {packet, line}, {reuseaddr, true},
{packet_size, 16384}, {buffer, 16384}]),
server(LSock, KeyTab).
server(LSock, KeyTab) ->
{ok, Sock} = gen_tcp:accept(LSock),
receive
{tcp, Sock, Data} ->
io:format("<= ~s\n", [Data]),
Ret = gss_spnego:accept(
base64:decode(Data),
#{
keytab => KeyTab,
chan_bindings => <<0:128/big>>,
mutual_auth => true
}),
case Ret of
{ok, T0, S0} ->
io:format("=> ~s\n", [base64:encode(T0)]),
{ok, Peer} = gss_spnego:peer_name(S0),
{ok, PeerName} = gss_spnego:translate_name(Peer, ?'id-krb5-name'),
io:format("peer: ~s\n", [PeerName]),
gen_tcp:send(Sock, [base64:encode(T0), $\n]),
server_loop(Sock, S0);
{continue, T0, S0} ->
io:format("=> ~s\n", [base64:encode(T0)]),
gen_tcp:send(Sock, [base64:encode(T0), $\n]),
server_continue(Sock, S0)
end;
{tcp_closed, Sock} ->
ok
end,
server(LSock, KeyTab).
server_continue(Sock, S0) ->
receive
{tcp, Sock, Data} ->
io:format("<= ~s\n", [Data]),
Ret = gss_spnego:continue(base64:decode(Data), S0),
case Ret of
{ok, S1} ->
{ok, Peer} = gss_spnego:peer_name(S1),
{ok, PeerName} = gss_spnego:translate_name(Peer, ?'id-krb5-name'),
io:format("peer: ~s\n", [PeerName]),
server_loop(Sock, S1);
{ok, T0, S1} ->
io:format("=> ~s\n", [base64:encode(T0)]),
{ok, Peer} = gss_spnego:peer_name(S1),
{ok, PeerName} = gss_spnego:translate_name(Peer, ?'id-krb5-name'),
io:format("peer: ~s\n", [PeerName]),
gen_tcp:send(Sock, [base64:encode(T0), $\n]),
server_loop(Sock, S1);
{continue, T0, S1} ->
io:format("=> ~s\n", [base64:encode(T0)]),
gen_tcp:send(Sock, [base64:encode(T0), $\n]),
server_continue(Sock, S1)
end;
{tcp_closed, Sock} ->
ok
end.
server_loop(Sock, S0) ->
receive
{tcp_closed, Sock} -> ok;
{tcp, Sock, <<"wrap||", Data/binary>>} ->
{ok, Msg, S1} = gss_spnego:unwrap(base64:decode(Data), S0),
io:format("<= ~p\n", [Msg]),
{ok, T, S2} = gss_spnego:wrap(<<"ok\n">>, S1),
gen_tcp:send(Sock, ["wrap||", base64:encode(T), $\n]),
case Msg of
<<"exit">> ->
gen_tcp:close(Sock),
ok;
_ -> server_loop(Sock, S2)
end;
{tcp, Sock, <<"mic|", Data/binary>>} ->
[MsgB64, TokData] = binary:split(Data, [<<$|>>]),
Msg = base64:decode(MsgB64),
{ok, S1} = gss_spnego:verify_mic(Msg, base64:decode(TokData), S0),
io:format("<= ~p\n", [Msg]),
OutMsg = <<"ok\n">>,
{ok, T, S2} = gss_spnego:get_mic(OutMsg, S1),
gen_tcp:send(Sock, ["mic|", base64:encode(OutMsg), $|,
base64:encode(T), $\n]),
case Msg of
<<"exit">> ->
gen_tcp:close(Sock),
ok;
_ -> server_loop(Sock, S2)
end
end.
client() ->
{ok, R} = krb_realm:open("EXAMPLE.COM"),
{ok, TGT} = krb_realm:authenticate(R, ["root"], "root", #{
etypes => [rc4_hmac]}),
{ok, SvcTicket} = krb_realm:obtain_ticket(R, TGT,
["host", "kdc.example.com"], #{etypes => [rc4_hmac]}),
{continue, T0, S0} = gss_spnego:initiate(#{
ticket => SvcTicket,
chan_bindings => <<0:128/big>>,
mutual_auth => true
}),
{ok, Sock} = gen_tcp:connect("kdc.example.com", 8082,
[binary, {active, true}, {packet, line}, {packet_size, 16384},
{buffer, 16384}]),
gen_tcp:send(Sock, [base64:encode(T0), $\n]),
client_continue(Sock, S0).
client_loop(Sock, S0) ->
io:format("in client_loop\n"),
{ok, T1, S1} = gss_spnego:wrap(<<"hello world\n">>, S0),
gen_tcp:send(Sock, ["wrap||", base64:encode(T1), $\n]),
receive
{tcp, Sock, <<"wrap||", Data1/binary>>} ->
{ok, Msg0, S2} = gss_spnego:unwrap(base64:decode(Data1), S1),
io:format("<= ~p\n", [Msg0]),
Q = <<"what is your name\n">>,
{ok, T2, S3} = gss_spnego:get_mic(Q, S2),
gen_tcp:send(Sock, ["mic|", base64:encode(Q), $|,
base64:encode(T2), $\n]),
receive
{tcp, Sock, <<"mic|", Data2Rem/binary>>} ->
[Msg1B64, Data2] = binary:split(Data2Rem, [<<$|>>]),
Msg1 = base64:decode(Msg1B64),
{ok, S4} = gss_spnego:verify_mic(Msg1, base64:decode(Data2), S3),
io:format("<= ~p\n", [Msg1]),
{ok, T3, S5} = gss_spnego:get_mic(<<"exit">>, S4),
gen_tcp:send(Sock, ["mic|", base64:encode(<<"exit">>),
$|, base64:encode(T3), $\n])
end
end,
receive
{tcp_closed, Sock} ->
ok
end.
client_continue(Sock, S0) ->
io:format("client_continue\n"),
receive
{tcp, Sock, Data0} ->
case gss_spnego:continue(base64:decode(Data0), S0) of
{ok, S1} ->
client_loop(Sock, S1);
{ok, Token, S1} ->
gen_tcp:send(Sock, [base64:encode(Token), $\n]),
client_loop(Sock, S1);
{continue, Token, S1} ->
gen_tcp:send(Sock, [base64:encode(Token), $\n]),
client_continue(Sock, S1)
end
end.