diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ssh/src/Makefile | 1 | ||||
-rw-r--r-- | lib/ssh/src/ssh.app.src | 1 | ||||
-rw-r--r-- | lib/ssh/src/ssh_auth.erl | 98 | ||||
-rw-r--r-- | lib/ssh/src/ssh_bits.erl | 222 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection.erl | 68 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_handler.erl | 5 | ||||
-rw-r--r-- | lib/ssh/src/ssh_connection_manager.erl | 6 | ||||
-rw-r--r-- | lib/ssh/src/ssh_message.erl | 519 | ||||
-rw-r--r-- | lib/ssh/src/ssh_transport.erl | 156 |
9 files changed, 714 insertions, 362 deletions
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index 93d0b54f57..a31e4a8525 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -67,6 +67,7 @@ MODULES= \ ssh_file \ ssh_io \ ssh_math \ + ssh_message \ ssh_no_io \ ssh_sftp \ ssh_sftpd \ diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src index 49707f3378..bae8f82d01 100644 --- a/lib/ssh/src/ssh.app.src +++ b/lib/ssh/src/ssh.app.src @@ -8,6 +8,7 @@ ssh_acceptor, ssh_acceptor_sup, ssh_auth, + ssh_message, ssh_bits, ssh_cli, ssh_client_key_api, diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index cb0c7751f0..f3d1a711ae 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,8 +30,8 @@ -export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1, service_request_msg/1, init_userauth_request_msg/1, userauth_request_msg/1, handle_userauth_request/3, - handle_userauth_info_request/3, handle_userauth_info_response/2, - userauth_messages/0 + handle_userauth_info_request/3, handle_userauth_info_response/2 + %%userauth_messages/0 ]). %%-------------------------------------------------------------------- @@ -43,7 +43,7 @@ publickey_msg([Alg, #ssh{user = User, opts = Opts} = Ssh]) -> Hash = sha, %% Maybe option?! - ssh_bits:install_messages(userauth_pk_messages()), + %%ssh_bits:install_messages(userauth_pk_messages()), KeyCb = proplists:get_value(key_cb, Opts, ssh_file), case KeyCb:user_key(Alg, Opts) of @@ -69,7 +69,7 @@ publickey_msg([Alg, #ssh{user = User, password_msg([#ssh{opts = Opts, io_cb = IoCb, user = User, service = Service} = Ssh]) -> - ssh_bits:install_messages(userauth_passwd_messages()), + %%ssh_bits:install_messages(userauth_passwd_messages()), Password = case proplists:get_value(password, Opts) of undefined -> user_interaction(IoCb, Ssh); @@ -99,7 +99,7 @@ user_interaction(IoCb, Ssh) -> %% See RFC 4256 for info on keyboard-interactive keyboard_interactive_msg([#ssh{user = User, service = Service} = Ssh]) -> - ssh_bits:install_messages(userauth_keyboard_interactive_messages()), + %%ssh_bits:install_messages(userauth_keyboard_interactive_messages()), ssh_transport:ssh_packet( #ssh_msg_userauth_request{user = User, service = Service, @@ -239,7 +239,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, partial_success = false}, Ssh)} end; ?FALSE -> - ssh_bits:install_messages(userauth_pk_messages()), + %%ssh_bits:install_messages(userauth_pk_messages()), {not_authorized, {User, undefined}, ssh_transport:ssh_packet( #ssh_msg_userauth_pk_ok{algorithm_name = Alg, @@ -278,23 +278,23 @@ handle_userauth_info_response(#ssh_msg_userauth_info_response{}, description = "Server does not support" "keyboard-interactive", language = "en"}). -userauth_messages() -> - [ {ssh_msg_userauth_request, ?SSH_MSG_USERAUTH_REQUEST, - [string, - string, - string, - '...']}, - - {ssh_msg_userauth_failure, ?SSH_MSG_USERAUTH_FAILURE, - [string, - boolean]}, - - {ssh_msg_userauth_success, ?SSH_MSG_USERAUTH_SUCCESS, - []}, - - {ssh_msg_userauth_banner, ?SSH_MSG_USERAUTH_BANNER, - [string, - string]}]. +%% userauth_messages() -> +%% [ {ssh_msg_userauth_request, ?SSH_MSG_USERAUTH_REQUEST, +%% [string, +%% string, +%% string, +%% '...']}, + +%% {ssh_msg_userauth_failure, ?SSH_MSG_USERAUTH_FAILURE, +%% [string, +%% boolean]}, + +%% {ssh_msg_userauth_success, ?SSH_MSG_USERAUTH_SUCCESS, +%% []}, + +%% {ssh_msg_userauth_banner, ?SSH_MSG_USERAUTH_BANNER, +%% [string, +%% string]}]. %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -431,31 +431,31 @@ keyboard_interact(IoCb, Name, Instr, Prompts, Opts) -> end, Prompts). -userauth_passwd_messages() -> - [ - {ssh_msg_userauth_passwd_changereq, ?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, - [string, - string]} - ]. - -userauth_keyboard_interactive_messages() -> - [ {ssh_msg_userauth_info_request, ?SSH_MSG_USERAUTH_INFO_REQUEST, - [string, - string, - string, - uint32, - '...']}, - - {ssh_msg_userauth_info_response, ?SSH_MSG_USERAUTH_INFO_RESPONSE, - [uint32, - '...']} - ]. - -userauth_pk_messages() -> - [ {ssh_msg_userauth_pk_ok, ?SSH_MSG_USERAUTH_PK_OK, - [string, % algorithm name - binary]} % key blob - ]. +%% userauth_passwd_messages() -> +%% [ +%% {ssh_msg_userauth_passwd_changereq, ?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, +%% [string, +%% string]} +%% ]. + +%% userauth_keyboard_interactive_messages() -> +%% [ {ssh_msg_userauth_info_request, ?SSH_MSG_USERAUTH_INFO_REQUEST, +%% [string, +%% string, +%% string, +%% uint32, +%% '...']}, + + %% {ssh_msg_userauth_info_response, ?SSH_MSG_USERAUTH_INFO_RESPONSE, + %% [uint32, + %% '...']} + %% ]. + +%% userauth_pk_messages() -> +%% [ {ssh_msg_userauth_pk_ok, ?SSH_MSG_USERAUTH_PK_OK, +%% [string, % algorithm name +%% binary]} % key blob +%% ]. other_alg('ssh-rsa') -> 'ssh-dss'; diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index fc6efc817f..1570e5ed4d 100644 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -25,19 +25,19 @@ -include("ssh.hrl"). --export([encode/1, encode/2]). --export([decode/1, decode/2, decode/3]). +-export([encode/2, decode/2]). +%%-export([decode/1, decode/2, decode/3]). -export([mpint/1, bignum/1, string/1, name_list/1]). --export([b64_encode/1, b64_decode/1]). --export([install_messages/1, uninstall_messages/1]). +%%-export([b64_encode/1, b64_decode/1]). +%%-export([install_messages/1, uninstall_messages/1]). %% integer utils -export([isize/1]). -export([random/1]). --export([xor_bits/2, fill_bits/2]). +%%-export([xor_bits/2, fill_bits/2]). -export([i2bin/2, bin2i/1]). --import(lists, [foreach/2, reverse/1]). +%%-import(lists, [foreach/2, reverse/1]). -define(name_list(X), (fun(B) -> ?binary(B) end)(list_to_binary(name_concat(X)))). @@ -102,30 +102,30 @@ bignum(X) -> <<?UINT16(XSz),0:Pad/unsigned-integer,X:XSz/big-unsigned-integer>>. -install_messages(Codes) -> - foreach(fun({Name, Code, Ts}) -> - put({msg_name,Code}, {Name,Ts}), - put({msg_code,Name}, {Code,Ts}) - end, Codes). +%% install_messages(Codes) -> +%% foreach(fun({Name, Code, Ts}) -> +%% put({msg_name,Code}, {Name,Ts}), +%% put({msg_code,Name}, {Code,Ts}) +%% end, Codes). -uninstall_messages(Codes) -> - foreach(fun({Name, Code, _Ts}) -> - erase({msg_name,Code}), - erase({msg_code,Name}) - end, Codes). +%% uninstall_messages(Codes) -> +%% foreach(fun({Name, Code, _Ts}) -> +%% erase({msg_name,Code}), +%% erase({msg_code,Name}) +%% end, Codes). %% %% Encode a record, the type spec is expected to be %% in process dictionary under the key {msg_code, RecodeName} %% -encode(Record) -> - case get({msg_code, element(1, Record)}) of - undefined -> - {error, unimplemented}; - {Code, Ts} -> - Data = enc(tl(tuple_to_list(Record)), Ts), - list_to_binary([Code, Data]) - end. +%% encode(Record) -> +%% case get({msg_code, element(1, Record)}) of +%% undefined -> +%% {error, unimplemented}; +%% {Code, Ts} -> +%% Data = enc(tl(tuple_to_list(Record)), Ts), +%% list_to_binary([Code, Data]) +%% end. encode(List, Types) -> list_to_binary(enc(List, Types)). @@ -136,74 +136,70 @@ encode(List, Types) -> enc(Xs, Ts) -> enc(Xs, Ts, 0). -enc(Xs, [Type|Ts], Offset) -> - case Type of - boolean -> - X=hd(Xs), - [?boolean(X) | enc(tl(Xs), Ts, Offset+1)]; - byte -> - X=hd(Xs), - [?byte(X) | enc(tl(Xs), Ts,Offset+1)]; - uint16 -> - X=hd(Xs), - [?uint16(X) | enc(tl(Xs), Ts,Offset+2)]; - uint32 -> - X=hd(Xs), - [?uint32(X) | enc(tl(Xs), Ts,Offset+4)]; - uint64 -> - X=hd(Xs), - [?uint64(X) | enc(tl(Xs), Ts,Offset+8)]; - mpint -> - Y=mpint(hd(Xs)), - [Y | enc(tl(Xs), Ts,Offset+size(Y))]; - bignum -> - Y=bignum(hd(Xs)), - [Y | enc(tl(Xs),Ts,Offset+size(Y))]; - string -> - X0=hd(Xs), - Y=?string(X0), - [Y | enc(tl(Xs),Ts,Offset+size(Y))]; - binary -> - X0=hd(Xs), - Y=?binary(X0), - [Y | enc(tl(Xs), Ts,Offset+size(Y))]; - name_list -> - X0=hd(Xs), - Y=?name_list(X0), - [Y | enc(tl(Xs), Ts, Offset+size(Y))]; - cookie -> - [random(16) | enc(tl(Xs), Ts, Offset+16)]; - {pad,N} -> - K = (N - (Offset rem N)) rem N, - [fill_bits(K,0) | enc(Xs, Ts, Offset+K)]; - '...' when Ts==[] -> - X=hd(Xs), - if is_binary(X) -> - [X]; - is_list(X) -> - [list_to_binary(X)]; - X==undefined -> - [] - end +enc(Xs, [boolean|Ts], Offset) -> + X = hd(Xs), + [?boolean(X) | enc(tl(Xs), Ts, Offset+1)]; +enc(Xs, [byte|Ts], Offset) -> + X = hd(Xs), + [?byte(X) | enc(tl(Xs), Ts,Offset+1)]; +enc(Xs, [uint16|Ts], Offset) -> + X = hd(Xs), + [?uint16(X) | enc(tl(Xs), Ts,Offset+2)]; +enc(Xs, [uint32 |Ts], Offset) -> + X = hd(Xs), + [?uint32(X) | enc(tl(Xs), Ts,Offset+4)]; +enc(Xs, [uint64|Ts], Offset) -> + X = hd(Xs), + [?uint64(X) | enc(tl(Xs), Ts,Offset+8)]; +enc(Xs, [mpint|Ts], Offset) -> + Y = mpint(hd(Xs)), + [Y | enc(tl(Xs), Ts,Offset+size(Y))]; +enc(Xs, [bignum|Ts], Offset) -> + Y = bignum(hd(Xs)), + [Y | enc(tl(Xs),Ts,Offset+size(Y))]; +enc(Xs, [string|Ts], Offset) -> + X0 = hd(Xs), + Y = ?string(X0), + [Y | enc(tl(Xs),Ts,Offset+size(Y))]; +enc(Xs, [binary|Ts], Offset) -> + X0 = hd(Xs), + Y = ?binary(X0), + [Y | enc(tl(Xs), Ts,Offset+size(Y))]; +enc(Xs, [name_list|Ts], Offset) -> + X0 = hd(Xs), + Y = ?name_list(X0), + [Y | enc(tl(Xs), Ts, Offset+size(Y))]; +enc(Xs, [cookie|Ts], Offset) -> + [random(16) | enc(tl(Xs), Ts, Offset+16)]; +enc(Xs, [{pad,N}|Ts], Offset) -> + K = (N - (Offset rem N)) rem N, + [fill_bits(K,0) | enc(Xs, Ts, Offset+K)]; +enc(Xs, ['...'| []], _Offset) -> + X = hd(Xs), + if is_binary(X) -> + [X]; + is_list(X) -> + [list_to_binary(X)]; + X==undefined -> + [] end; + enc([], [],_) -> []. - - %% %% Decode a SSH record the type is encoded as the first byte %% and the type spec MUST be installed in {msg_name, ID} %% -decode(Binary = <<?BYTE(ID), _/binary>>) -> - case get({msg_name, ID}) of - undefined -> - {unknown, Binary}; - {Name, Ts} -> - {_, Elems} = decode(Binary,1,Ts), - list_to_tuple([Name | Elems]) - end. +%% decode(Binary = <<?BYTE(ID), _/binary>>) -> +%% case get({msg_name, ID}) of +%% undefined -> +%% {unknown, Binary}; +%% {Name, Ts} -> +%% {_, Elems} = decode(Binary,1,Ts), +%% list_to_tuple([Name | Elems]) +%% end. %% %% Decode a binary form offset 0 @@ -214,15 +210,15 @@ decode(Binary, Types) when is_binary(Binary) andalso is_list(Types) -> Elems. -%% -%% Decode a binary from byte offset Offset -%% return {UpdatedOffset, DecodedElements} -%% +%% %% +%% %% Decode a binary from byte offset Offset +%% %% return {UpdatedOffset, DecodedElements} +%% %% decode(Binary, Offset, Types) -> - decode(Binary, Offset, Types, []). + decode(Binary, Offset, Types, []). decode(Binary, Offset, [Type|Ts], Acc) -> - case Type of + case Type of boolean -> <<_:Offset/binary, ?BOOLEAN(X0), _/binary>> = Binary, X = if X0 == 0 -> false; true -> true end, @@ -262,11 +258,11 @@ decode(Binary, Offset, [Type|Ts], Acc) -> Size = size(Binary), if Size < Offset + 4 -> %% empty string at end - {Size, reverse(["" | Acc])}; + {Size, lists:reverse(["" | Acc])}; true -> <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary, - decode(Binary, Offset+4+L, Ts, [binary_to_list(X) | + decode(Binary, Offset+4+L, Ts, [binary_to_list(X) | Acc]) end; @@ -290,10 +286,10 @@ decode(Binary, Offset, [Type|Ts], Acc) -> '...' when Ts==[] -> <<_:Offset/binary, X/binary>> = Binary, - {Offset+size(X), reverse([X | Acc])} - end; -decode(_Binary, Offset, [], Acc) -> - {Offset, reverse(Acc)}. + {Offset+size(X), lists:reverse([X | Acc])} + end; + decode(_Binary, Offset, [], Acc) -> + {Offset, lists:reverse(Acc)}. @@ -378,13 +374,13 @@ fill(N,C) -> end. %% xor 2 binaries -xor_bits(XBits, YBits) -> - XSz = size(XBits)*8, - YSz = size(YBits)*8, - Sz = if XSz < YSz -> XSz; true -> YSz end, %% min - <<X:Sz, _/binary>> = XBits, - <<Y:Sz, _/binary>> = YBits, - <<(X bxor Y):Sz>>. +%% xor_bits(XBits, YBits) -> +%% XSz = size(XBits)*8, +%% YSz = size(YBits)*8, +%% Sz = if XSz < YSz -> XSz; true -> YSz end, %% min +%% <<X:Sz, _/binary>> = XBits, +%% <<Y:Sz, _/binary>> = YBits, +%% <<(X bxor Y):Sz>>. %% random/1 @@ -393,18 +389,18 @@ xor_bits(XBits, YBits) -> random(N) -> crypto:strong_rand_bytes(N). -%% -%% Base 64 encode/decode -%% +%% %% +%% %% Base 64 encode/decode +%% %% -b64_encode(Bs) when is_list(Bs) -> - base64:encode(Bs); -b64_encode(Bin) when is_binary(Bin) -> - base64:encode(Bin). +%% b64_encode(Bs) when is_list(Bs) -> +%% base64:encode(Bs); +%% b64_encode(Bin) when is_binary(Bin) -> +%% base64:encode(Bin). -b64_decode(Bin) when is_binary(Bin) -> - base64:mime_decode(Bin); -b64_decode(Cs) when is_list(Cs) -> - base64:mime_decode(Cs). +%% b64_decode(Bin) when is_binary(Bin) -> +%% base64:mime_decode(Bin); +%% b64_decode(Cs) when is_list(Cs) -> +%% base64:mime_decode(Cs). diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 9424cdd423..ec3022e7c1 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2012. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -44,7 +44,7 @@ channel_open_failure_msg/4, channel_request_msg/4, global_request_msg/3, request_failure_msg/0, request_success_msg/1, bind/4, unbind/3, unbind_channel/2, - bound_channel/3, messages/0]). + bound_channel/3]). %%-------------------------------------------------------------------- %%% Internal application API @@ -880,70 +880,6 @@ bound_channel(IP, Port, Connection) -> _ -> undefined end. -messages() -> - [ {ssh_msg_global_request, ?SSH_MSG_GLOBAL_REQUEST, - [string, - boolean, - '...']}, - - {ssh_msg_request_success, ?SSH_MSG_REQUEST_SUCCESS, - ['...']}, - - {ssh_msg_request_failure, ?SSH_MSG_REQUEST_FAILURE, - []}, - - {ssh_msg_channel_open, ?SSH_MSG_CHANNEL_OPEN, - [string, - uint32, - uint32, - uint32, - '...']}, - - {ssh_msg_channel_open_confirmation, ?SSH_MSG_CHANNEL_OPEN_CONFIRMATION, - [uint32, - uint32, - uint32, - uint32, - '...']}, - - {ssh_msg_channel_open_failure, ?SSH_MSG_CHANNEL_OPEN_FAILURE, - [uint32, - uint32, - string, - string]}, - - {ssh_msg_channel_window_adjust, ?SSH_MSG_CHANNEL_WINDOW_ADJUST, - [uint32, - uint32]}, - - {ssh_msg_channel_data, ?SSH_MSG_CHANNEL_DATA, - [uint32, - binary]}, - - {ssh_msg_channel_extended_data, ?SSH_MSG_CHANNEL_EXTENDED_DATA, - [uint32, - uint32, - binary]}, - - {ssh_msg_channel_eof, ?SSH_MSG_CHANNEL_EOF, - [uint32]}, - - {ssh_msg_channel_close, ?SSH_MSG_CHANNEL_CLOSE, - [uint32]}, - - {ssh_msg_channel_request, ?SSH_MSG_CHANNEL_REQUEST, - [uint32, - string, - boolean, - '...']}, - - {ssh_msg_channel_success, ?SSH_MSG_CHANNEL_SUCCESS, - [uint32]}, - - {ssh_msg_channel_failure, ?SSH_MSG_CHANNEL_FAILURE, - [uint32]} - ]. - encode_ip(Addr) when is_tuple(Addr) -> case catch inet_parse:ntoa(Addr) of {'EXIT',_} -> false; diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index c3e8a3c742..c10a60bfcf 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -111,7 +111,6 @@ peer_address(ConnectionHandler) -> init([Role, Manager, Socket, SshOpts]) -> process_flag(trap_exit, true), {NumVsn, StrVsn} = ssh_transport:versions(Role, SshOpts), - ssh_bits:install_messages(ssh_transport:transport_messages(NumVsn)), {Protocol, Callback, CloseTag} = proplists:get_value(transport, SshOpts, {tcp, gen_tcp, tcp_closed}), try init_ssh(Role, NumVsn, StrVsn, SshOpts, Socket) of @@ -323,7 +322,6 @@ new_keys(#ssh_msg_newkeys{} = Msg, #state{ssh_params = Ssh0} = State0) -> userauth(#ssh_msg_service_request{name = "ssh-userauth"} = Msg, #state{ssh_params = #ssh{role = server, session_id = SessionId} = Ssh0} = State) -> - ssh_bits:install_messages(ssh_auth:userauth_messages()), try ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of {ok, {Reply, Ssh}} -> send_msg(Reply, State), @@ -887,7 +885,7 @@ generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName, {stop, {shutdown, Reason}, State0} end; generate_event(Msg, StateName, State0, EncData) -> - Event = ssh_bits:decode(Msg), + Event = ssh_message:decode(Msg), State = generate_event_new_state(State0, EncData), case Event of #ssh_msg_kexinit{} -> @@ -931,7 +929,6 @@ after_new_keys(#state{renegotiate = true} = State) -> {connected, State#state{renegotiate = false}}; after_new_keys(#state{renegotiate = false, ssh_params = #ssh{role = client} = Ssh0} = State) -> - ssh_bits:install_messages(ssh_auth:userauth_messages()), {Msg, Ssh} = ssh_auth:service_request_msg(Ssh0), send_msg(Msg, State), {userauth, State#state{ssh_params = Ssh}}; diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl index 99a0b6a7c8..fb57a790fe 100644 --- a/lib/ssh/src/ssh_connection_manager.erl +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -183,7 +183,6 @@ send_eof(ConnectionManager, ChannelId) -> %%-------------------------------------------------------------------- init([server, _Socket, Opts]) -> process_flag(trap_exit, true), - ssh_bits:install_messages(ssh_connection:messages()), Cache = ssh_channel:cache_create(), {ok, #state{role = server, connection_state = #connection{channel_cache = Cache, @@ -196,7 +195,6 @@ init([server, _Socket, Opts]) -> init([client, Opts]) -> process_flag(trap_exit, true), {links, [Parent]} = process_info(self(), links), - ssh_bits:install_messages(ssh_connection:messages()), Cache = ssh_channel:cache_create(), Address = proplists:get_value(address, Opts), Port = proplists:get_value(port, Opts), @@ -762,7 +760,7 @@ cast(Pid, Msg) -> gen_server:cast(Pid, Msg). decode_ssh_msg(BinMsg) when is_binary(BinMsg)-> - ssh_bits:decode(BinMsg); + ssh_message:decode(BinMsg); decode_ssh_msg(Msg) -> Msg. @@ -774,7 +772,7 @@ do_send_msg({channel_data, Pid, Data}) -> do_send_msg({channel_requst_reply, From, Data}) -> gen_server:reply(From, Data); do_send_msg({connection_reply, Pid, Data}) -> - Msg = ssh_bits:encode(Data), + Msg = ssh_message:encode(Data), ssh_connection_handler:send(Pid, Msg); do_send_msg({flow_control, Cache, Channel, From, Msg}) -> ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}), diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl new file mode 100644 index 0000000000..dc4943ace4 --- /dev/null +++ b/lib/ssh/src/ssh_message.erl @@ -0,0 +1,519 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2013-2013. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%------------------------------------------------------------------ +-module(ssh_message). + +-include_lib("public_key/include/public_key.hrl"). + +-include("ssh.hrl"). +-include("ssh_connect.hrl"). +-include("ssh_auth.hrl"). +-include("ssh_transport.hrl"). + +-export([encode/1, decode/1, encode_host_key/1]). + +encode(#ssh_msg_global_request{ + name = Name, + want_reply = Bool, + data = Data}) -> + ssh_bits:encode([?SSH_MSG_GLOBAL_REQUEST, + Name, Bool, Data], [byte, string, boolean, '...']); +encode(#ssh_msg_request_success{data = Data}) -> + <<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>; +encode(#ssh_msg_request_failure{}) -> + <<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>; +encode(#ssh_msg_channel_open{ + channel_type = Type, + sender_channel = Sender, + initial_window_size = Window, + maximum_packet_size = Max, + data = Data + }) -> + ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN, + Type, Sender, Window, Max, Data], [byte, string, uint32, + uint32, uint32, '...']); +encode(#ssh_msg_channel_open_confirmation{ + recipient_channel = Recipient, + sender_channel = Sender, + initial_window_size = InitWindowSize, + maximum_packet_size = MaxPacketSize, + data = Data + }) -> + ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN_CONFIRMATION, Recipient, + Sender, InitWindowSize, MaxPacketSize, Data], + [byte, uint32, uint32, uint32, uint32, '...']); +encode(#ssh_msg_channel_open_failure{ + recipient_channel = Recipient, + reason = Reason, + description = Desc, + lang = Lang + }) -> + ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN_FAILURE, Recipient, + Reason, Desc, Lang], [byte, uint32, uint32, string, string]); +encode(#ssh_msg_channel_window_adjust{ + recipient_channel = Recipient, + bytes_to_add = Bytes + }) -> + ssh_bits:encode([?SSH_MSG_CHANNEL_WINDOW_ADJUST, Recipient, Bytes], + [byte, uint32, uint32]); +encode(#ssh_msg_channel_data{ + recipient_channel = Recipient, + data = Data + }) -> + ssh_bits:encode([?SSH_MSG_CHANNEL_DATA, Recipient, Data], [byte, uint32, binary]); + +encode(#ssh_msg_channel_extended_data{ + recipient_channel = Recipient, + data_type_code = DataType, + data = Data + }) -> + ssh_bits:encode([?SSH_MSG_CHANNEL_EXTENDED_DATA, Recipient, + DataType, Data], [byte, uint32, uint32, binary]); + +encode(#ssh_msg_channel_eof{recipient_channel = Recipient + }) -> + <<?BYTE(?SSH_MSG_CHANNEL_EOF), ?UINT32(Recipient)>>; +encode(#ssh_msg_channel_close{ + recipient_channel = Recipient + }) -> + <<?BYTE(?SSH_MSG_CHANNEL_CLOSE), ?UINT32(Recipient)>>; +encode(#ssh_msg_channel_request{ + recipient_channel = Recipient, + request_type = Type, + want_reply = Bool, + data = Data + }) -> + ssh_bits:encode([?SSH_MSG_CHANNEL_REQUEST, Recipient, Type, Bool, Data], + [byte, uint32, string, boolean, '...']); +encode(#ssh_msg_channel_success{ + recipient_channel = Recipient + }) -> + <<?BYTE(?SSH_MSG_CHANNEL_SUCCESS), ?UINT32(Recipient)>>; +encode(#ssh_msg_channel_failure{ + recipient_channel = Recipient + }) -> + <<?BYTE(?SSH_MSG_CHANNEL_FAILURE), ?UINT32(Recipient)>>; + +encode(#ssh_msg_userauth_request{ + user = User, + service = Service, + method = Method, + data = Data + }) -> + ssh_bits:encode([?SSH_MSG_USERAUTH_REQUEST, User, Service, Method, Data], + [byte, string, string, string, '...']); +encode(#ssh_msg_userauth_failure{ + authentications = Auths, + partial_success = Bool + }) -> + ssh_bits:encode([?SSH_MSG_USERAUTH_FAILURE, Auths, Bool], + [byte, string, boolean]); +encode(#ssh_msg_userauth_success{}) -> + <<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>; + +encode(#ssh_msg_userauth_banner{ + message = Banner, + language = Lang + }) -> + ssh_bits:encode([?SSH_MSG_USERAUTH_BANNER, Banner, Lang], + [byte, string, string]); + +encode(#ssh_msg_userauth_pk_ok{ + algorithm_name = Alg, + key_blob = KeyBlob + }) -> + ssh_bits:encode([?SSH_MSG_USERAUTH_PK_OK, Alg, KeyBlob], + [byte, string, binary]); + +encode(#ssh_msg_userauth_passwd_changereq{prompt = Prompt, + languge = Lang + })-> + ssh_bits:encode([?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, Prompt, Lang], + [byte, string, string]); + +encode(#ssh_msg_userauth_info_request{ + name = Name, + instruction = Inst, + language_tag = Lang, + num_prompts = NumPromtps, + data = Data}) -> + ssh_bits:encode([?SSH_MSG_USERAUTH_INFO_REQUEST, Name, Inst, Lang, NumPromtps, Data], + [byte, string, string, string, uint32, '...']); + +encode(#ssh_msg_userauth_info_response{ + num_responses = Num, + data = Data}) -> + ssh_bits:encode([?SSH_MSG_USERAUTH_INFO_RESPONSE, Num, Data], + [byte, uint32, '...']); +encode(#ssh_msg_disconnect{ + code = Code, + description = Desc, + language = Lang + }) -> + ssh_bits:encode([?SSH_MSG_DISCONNECT, Code, Desc, Lang], + [byte, uint32, string, string]); + +encode(#ssh_msg_service_request{ + name = Service + }) -> + ssh_bits:encode([?SSH_MSG_SERVICE_REQUEST, Service], [byte, string]); + +encode(#ssh_msg_service_accept{ + name = Service + }) -> + ssh_bits:encode([?SSH_MSG_SERVICE_ACCEPT, Service], [byte, string]); + +encode(#ssh_msg_newkeys{}) -> + <<?BYTE(?SSH_MSG_NEWKEYS)>>; + +encode(#ssh_msg_kexinit{ + cookie = Cookie, + kex_algorithms = KeyAlgs, + server_host_key_algorithms = HostKeyAlgs, + encryption_algorithms_client_to_server = EncAlgC2S, + encryption_algorithms_server_to_client = EncAlgS2C, + mac_algorithms_client_to_server = MacAlgC2S, + mac_algorithms_server_to_client = MacAlgS2C, + compression_algorithms_client_to_server = CompAlgS2C, + compression_algorithms_server_to_client = CompAlgC2S, + languages_client_to_server = LangC2S, + languages_server_to_client = LangS2C, + first_kex_packet_follows = Bool, + reserved = Reserved + }) -> + ssh_bits:encode([?SSH_MSG_KEXINIT, Cookie, KeyAlgs, HostKeyAlgs, EncAlgC2S, EncAlgS2C, + MacAlgC2S, MacAlgS2C, CompAlgS2C, CompAlgC2S, LangC2S, LangS2C, Bool, + Reserved], + [byte, cookie, + name_list, name_list, + name_list, name_list, + name_list, name_list, + name_list, name_list, + name_list, name_list, + boolean, uint32]); + +encode(#ssh_msg_kexdh_init{e = E}) -> + ssh_bits:encode([?SSH_MSG_KEXDH_INIT, E], [byte, mpint]); + +encode(#ssh_msg_kexdh_reply{ + public_host_key = Key, + f = F, + h_sig = Signature + }) -> + EncKey = encode_host_key(Key), + EncSign = encode_sign(Key, Signature), + ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]); + +encode(#ssh_msg_kex_dh_gex_request{ + min = Min, + n = N, + max = Max + }) -> + ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST, Min, N, Max], + [byte, uint32, uint32, uint32, uint32]); +encode(#ssh_msg_kex_dh_gex_request_old{n = N}) -> + ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST_OLD, N], + [byte, uint32]); + +encode(#ssh_msg_kex_dh_gex_group{p = Prime, g = Generator}) -> + ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_GROUP, Prime, Generator], + [byte, mpint, mpint]); + +encode(#ssh_msg_kex_dh_gex_reply{ + %% Will be private key encode_host_key extracts only the public part! + public_host_key = Key, + f = F, + h_sig = Signature + }) -> + EncKey = encode_host_key(Key), + EncSign = encode_sign(Key, Signature), + ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]); + +encode(#ssh_msg_ignore{data = Data}) -> + ssh_bits:encode([?SSH_MSG_IGNORE, Data], [byte, string]); + +encode(#ssh_msg_unimplemented{sequence = Seq}) -> + ssh_bits:encode([?SSH_MSG_IGNORE, Seq], [byte, uint32]); + +encode(#ssh_msg_debug{always_display = Bool, + message = Msg, + language = Lang}) -> + ssh_bits:encode([?SSH_MSG_DEBUG, Bool, Msg, Lang], [byte, boolean, string, string]). + + +%% Connection Messages +decode(<<?BYTE(?SSH_MSG_GLOBAL_REQUEST), ?UINT32(Len), Name:Len/binary, + ?BYTE(Bool), Data/binary>>) -> + #ssh_msg_global_request{ + name = Name, + want_reply = erl_boolean(Bool), + data = Data + }; +decode(<<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>) -> + #ssh_msg_request_success{data = Data}; +decode(<<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>) -> + #ssh_msg_request_failure{}; +decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN), + ?UINT32(Len), Type:Len/binary, + ?UINT32(Sender), ?UINT32(Window), ?UINT32(Max), + Data/binary>>) -> + #ssh_msg_channel_open{ + channel_type = binary_to_list(Type), + sender_channel = Sender, + initial_window_size = Window, + maximum_packet_size = Max, + data = Data + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_CONFIRMATION), ?UINT32(Recipient), ?UINT32(Sender), + ?UINT32(InitWindowSize), ?UINT32(MaxPacketSize), + Data/binary>>) -> + #ssh_msg_channel_open_confirmation{ + recipient_channel = Recipient, + sender_channel = Sender, + initial_window_size = InitWindowSize, + maximum_packet_size = MaxPacketSize, + data = Data + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_FAILURE), ?UINT32(Recipient), ?UINT32(Reason), + ?UINT32(Len0), Desc:Len0/binary, ?UINT32(Len1), Lang:Len1/binary >>) -> + #ssh_msg_channel_open_failure{ + recipient_channel = Recipient, + reason = Reason, + description = unicode:characters_to_list(Desc), + lang = Lang + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_WINDOW_ADJUST), ?UINT32(Recipient), ?UINT32(Bytes)>>) -> + #ssh_msg_channel_window_adjust{ + recipient_channel = Recipient, + bytes_to_add = Bytes + }; + +decode(<<?BYTE(?SSH_MSG_CHANNEL_DATA), ?UINT32(Recipient), ?UINT32(Len), Data:Len/binary>>) -> + #ssh_msg_channel_data{ + recipient_channel = Recipient, + data = Data + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_EXTENDED_DATA), ?UINT32(Recipient), + ?UINT32(DataType), Data/binary>>) -> + #ssh_msg_channel_extended_data{ + recipient_channel = Recipient, + data_type_code = DataType, + data = Data + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_EOF), ?UINT32(Recipient)>>) -> + #ssh_msg_channel_eof{ + recipient_channel = Recipient + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_CLOSE), ?UINT32(Recipient)>>) -> + #ssh_msg_channel_close{ + recipient_channel = Recipient + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_REQUEST), ?UINT32(Recipient), + ?UINT32(Len), RequestType:Len/binary, + ?BYTE(Bool), Data/binary>>) -> + #ssh_msg_channel_request{ + recipient_channel = Recipient, + request_type = unicode:characters_to_list(RequestType), + want_reply = erl_boolean(Bool), + data = Data + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_SUCCESS), ?UINT32(Recipient)>>) -> + #ssh_msg_channel_success{ + recipient_channel = Recipient + }; +decode(<<?BYTE(?SSH_MSG_CHANNEL_FAILURE), ?UINT32(Recipient)>>) -> + #ssh_msg_channel_failure{ + recipient_channel = Recipient + }; + +%%% Auth Messages +decode(<<?BYTE(?SSH_MSG_USERAUTH_REQUEST), + ?UINT32(Len0), User:Len0/binary, + ?UINT32(Len1), Service:Len1/binary, + ?UINT32(Len2), Method:Len2/binary, + Data/binary>>) -> + #ssh_msg_userauth_request{ + user = unicode:characters_to_list(User), + service = unicode:characters_to_list(Service), + method = unicode:characters_to_list(Method), + data = Data + }; + +decode(<<?BYTE(?SSH_MSG_USERAUTH_FAILURE), + ?UINT32(Len0), Auths:Len0/binary, + ?BYTE(Bool)>>) -> + #ssh_msg_userauth_failure { + authentications = unicode:characters_to_list(Auths), + partial_success = erl_boolean(Bool) + }; + +decode(<<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>) -> + #ssh_msg_userauth_success{}; + +decode(<<?BYTE(?SSH_MSG_USERAUTH_BANNER), + ?UINT32(Len0), Banner:Len0/binary, + ?UINT32(Len1), Lang:Len1/binary>>) -> + #ssh_msg_userauth_banner{ + message = Banner, + language = Lang + }; + +decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?UINT32(Len), Alg:Len/binary, KeyBlob/binary>>) -> + #ssh_msg_userauth_pk_ok{ + algorithm_name = Alg, + key_blob = KeyBlob + }; + +decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?UINT32(Len0), Prompt:Len0/binary, + ?UINT32(Len1), Lang:Len1/binary>>) -> + #ssh_msg_userauth_passwd_changereq{ + prompt = Prompt, + languge = Lang + }; +decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary, + ?UINT32(Len1), Inst:Len1/binary, ?UINT32(Len2), Lang:Len2/binary, + ?UINT32(NumPromtps), Data/binary>>) -> + #ssh_msg_userauth_info_request{ + name = Name, + instruction = Inst, + language_tag = Lang, + num_prompts = NumPromtps, + data = Data}; + +decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) -> + #ssh_msg_userauth_info_response{ + num_responses = Num, + data = Data}; + +%%% Keyexchange messages +decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>) -> + decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10); + +decode(<<?BYTE(?SSH_MSG_KEXDH_INIT), ?UINT32(Len), E:Len/binary>>) -> + #ssh_msg_kexdh_init{e = erlint(Len, E) + }; +decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST), ?UINT32(Min), ?UINT32(N), ?UINT32(Max)>>) -> + #ssh_msg_kex_dh_gex_request{ + min = Min, + n = N, + max = Max + }; +decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) -> + #ssh_msg_kex_dh_gex_request_old{ + n = N + }; +decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), ?UINT32(Len0), Prime:Len0/big-signed-integer, + ?UINT32(Len1), Generator:Len1/big-signed-integer>>) -> + #ssh_msg_kex_dh_gex_group{ + p = Prime, + g = Generator + }; +decode(<<?BYTE(?SSH_MSG_KEXDH_REPLY), ?UINT32(Len0), Key:Len0/binary, + ?UINT32(Len1), F:Len1/binary, + ?UINT32(Len2), Hashsign:Len2/binary>>) -> + #ssh_msg_kexdh_reply{ + public_host_key = decode_host_key(Key), + f = erlint(Len1, F), + h_sig = decode_sign(Hashsign) + }; + +decode(<<?SSH_MSG_SERVICE_REQUEST, ?UINT32(Len0), Service:Len0/binary>>) -> + #ssh_msg_service_request{ + name = unicode:characters_to_list(Service) + }; + +decode(<<?SSH_MSG_SERVICE_ACCEPT, ?UINT32(Len0), Service:Len0/binary>>) -> + #ssh_msg_service_accept{ + name = unicode:characters_to_list(Service) + }; + +decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), + ?UINT32(Len0), Desc:Len0/binary, ?UINT32(Len1), Lang:Len1/binary>>) -> + #ssh_msg_disconnect{ + code = Code, + description = unicode:characters_to_list(Desc), + language = Lang + }; + +decode(<<?SSH_MSG_NEWKEYS>>) -> + #ssh_msg_newkeys{}; + +decode(<<?BYTE(?SSH_MSG_IGNORE), Data/binary>>) -> + #ssh_msg_ignore{data = Data}; + +decode(<<?BYTE(?SSH_MSG_UNIMPLEMENTED), ?UINT32(Seq)>>) -> + #ssh_msg_unimplemented{sequence = Seq}; + +decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?UINT32(Len0), Msg:Len0/binary, + ?UINT32(Len1), Lang:Len1/binary>>) -> + #ssh_msg_debug{always_display = erl_boolean(Bool), + message = Msg, + language = Lang}. +erl_boolean(0) -> + false; +erl_boolean(1) -> + true. + +decode_kex_init(<<?BYTE(Bool), ?UINT32(X)>>, Acc, 0) -> + list_to_tuple(lists:reverse([X, erl_boolean(Bool) | Acc])); +decode_kex_init(<<?UINT32(Len), Data:Len/binary, Rest/binary>>, Acc, N) -> + Names = string:tokens(unicode:characters_to_list(Data), ","), + decode_kex_init(Rest, [Names | Acc], N -1). + +erlint(MPIntSize, MPIntValue) -> + Bits = MPIntSize * 8, + <<Integer:Bits/integer>> = MPIntValue, + Integer. + +decode_sign(<<?UINT32(Len), _Alg:Len/binary, ?UINT32(_), Signature/binary>>) -> + Signature. + +decode_host_key(<<?UINT32(Len), Alg:Len/binary, Rest/binary>>) -> + decode_host_key(Alg, Rest). + +decode_host_key(<<"ssh-rsa">>, <<?UINT32(Len0), E:Len0/binary, + ?UINT32(Len1), N:Len1/binary>>) -> + #'RSAPublicKey'{publicExponent = erlint(Len0, E), + modulus = erlint(Len1, N)}; + +decode_host_key(<<"ssh-dss">>, + <<?UINT32(Len0), P:Len0/binary, + ?UINT32(Len1), Q:Len1/binary, + ?UINT32(Len2), G:Len2/binary, + ?UINT32(Len3), Y:Len3/binary>>) -> + {erlint(Len3, Y), #'Dss-Parms'{p = erlint(Len0, P), q = erlint(Len1, Q), + g = erlint(Len2, G)}}. + +encode_host_key(#'RSAPublicKey'{modulus = N, publicExponent = E}) -> + ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]); +encode_host_key({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) -> + ssh_bits:encode(["ssh-dss", P, Q, G, Y], + [string, mpint, mpint, mpint, mpint]); +encode_host_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) -> + ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]); +encode_host_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) -> + ssh_bits:encode(["ssh-dss", P, Q, G, Y], + [string, mpint, mpint, mpint, mpint]). +encode_sign(#'RSAPrivateKey'{}, Signature) -> + ssh_bits:encode(["ssh-rsa", Signature],[string, binary]); +encode_sign(#'DSAPrivateKey'{}, Signature) -> + ssh_bits:encode(["ssh-dss", Signature],[string, binary]). diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index 682d766d99..45292ca6f0 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -32,9 +32,10 @@ -export([connect/5, accept/4]). -export([versions/2, hello_version_msg/1]). -export([next_seqnum/1, decrypt_first_block/2, decrypt_blocks/3, - is_valid_mac/3, transport_messages/1, kexdh_messages/0, - kex_dh_gex_messages/0, handle_hello_version/1, - key_exchange_init_msg/1, key_init/3, new_keys_message/1, + is_valid_mac/3, + handle_hello_version/1, + key_exchange_init_msg/1, + key_init/3, new_keys_message/1, handle_kexinit_msg/3, handle_kexdh_init/2, handle_kex_dh_gex_group/2, handle_kex_dh_gex_reply/2, handle_new_keys/2, handle_kex_dh_gex_request/2, @@ -74,64 +75,6 @@ is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm, recv_mac_key = Key, recv_sequence = SeqNum}) -> Mac == mac(Algorithm, Key, SeqNum, Data). -transport_messages(_) -> - [{ssh_msg_disconnect, ?SSH_MSG_DISCONNECT, - [uint32, string, string]}, - - {ssh_msg_ignore, ?SSH_MSG_IGNORE, - [string]}, - - {ssh_msg_unimplemented, ?SSH_MSG_UNIMPLEMENTED, - [uint32]}, - - {ssh_msg_debug, ?SSH_MSG_DEBUG, - [boolean, string, string]}, - - {ssh_msg_service_request, ?SSH_MSG_SERVICE_REQUEST, - [string]}, - - {ssh_msg_service_accept, ?SSH_MSG_SERVICE_ACCEPT, - [string]}, - - {ssh_msg_kexinit, ?SSH_MSG_KEXINIT, - [cookie, - name_list, name_list, - name_list, name_list, - name_list, name_list, - name_list, name_list, - name_list, name_list, - boolean, - uint32]}, - - {ssh_msg_newkeys, ?SSH_MSG_NEWKEYS, - []} - ]. - -kexdh_messages() -> - [{ssh_msg_kexdh_init, ?SSH_MSG_KEXDH_INIT, - [mpint]}, - - {ssh_msg_kexdh_reply, ?SSH_MSG_KEXDH_REPLY, - [binary, mpint, binary]} - ]. - -kex_dh_gex_messages() -> - [{ssh_msg_kex_dh_gex_request, ?SSH_MSG_KEX_DH_GEX_REQUEST, - [uint32, uint32, uint32]}, - - {ssh_msg_kex_dh_gex_request_old, ?SSH_MSG_KEX_DH_GEX_REQUEST_OLD, - [uint32]}, - - {ssh_msg_kex_dh_gex_group, ?SSH_MSG_KEX_DH_GEX_GROUP, - [mpint, mpint]}, - - {ssh_msg_kex_dh_gex_init, ?SSH_MSG_KEX_DH_GEX_INIT, - [mpint]}, - - {ssh_msg_kex_dh_gex_reply, ?SSH_MSG_KEX_DH_GEX_REPLY, - [binary, mpint, binary]} - ]. - yes_no(Ssh, Prompt) -> (Ssh#ssh.io_cb):yes_no(Prompt, Ssh). @@ -257,7 +200,6 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own, {ok, Algoritms} = select_algorithm(client, Own, CounterPart), case verify_algorithm(Algoritms) of true -> - install_messages(Algoritms#alg.kex), key_exchange_first_msg(Algoritms#alg.kex, Ssh0#ssh{algorithms = Algoritms}); _ -> @@ -271,7 +213,6 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own, handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own, #ssh{role = server} = Ssh) -> {ok, Algoritms} = select_algorithm(server, CounterPart, Own), - install_messages(Algoritms#alg.kex), {ok, Ssh#ssh{algorithms = Algoritms}}. @@ -284,11 +225,6 @@ verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) -> verify_algorithm(_) -> false. -install_messages('diffie-hellman-group1-sha1') -> - ssh_bits:install_messages(kexdh_messages()); -install_messages('diffie-hellman-group-exchange-sha1') -> - ssh_bits:install_messages(kex_dh_gex_messages()). - key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) -> {G, P} = dh_group1(), {Private, Public} = dh_gen_key(G, P, 1024), @@ -312,10 +248,10 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) -> {G, P} = dh_group1(), {Private, Public} = dh_gen_key(G, P, 1024), K = ssh_math:ipow(E, Private, P), - {Key, K_S} = get_host_key(Ssh0), - H = kex_h(Ssh0, K_S, E, Public, K), + Key = get_host_key(Ssh0), + H = kex_h(Ssh0, Key, E, Public, K), H_SIG = sign_host_key(Ssh0, Key, H), - {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_reply{public_host_key = K_S, + {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_reply{public_host_key = Key, f = Public, h_sig = H_SIG }, Ssh0), @@ -411,65 +347,33 @@ get_host_key(SSH) -> #ssh{key_cb = Mod, opts = Opts, algorithms = ALG} = SSH, case Mod:host_key(ALG#alg.hkey, Opts) of - {ok, #'RSAPrivateKey'{modulus = N, publicExponent = E} = Key} -> - {Key, - ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])}; - {ok, #'DSAPrivateKey'{y = Y, p = P, q = Q, g = G} = Key} -> - {Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y], - [string,mpint,mpint,mpint,mpint])}; + {ok, #'RSAPrivateKey'{} = Key} -> + Key; + {ok, #'DSAPrivateKey'{} = Key} -> + Key; Result -> exit({error, {Result, unsupported_key_type}}) end. sign_host_key(_Ssh, #'RSAPrivateKey'{} = Private, H) -> Hash = sha, %% Option ?! - Signature = sign(H, Hash, Private), - ssh_bits:encode(["ssh-rsa", Signature],[string, binary]); + _Signature = sign(H, Hash, Private); sign_host_key(_Ssh, #'DSAPrivateKey'{} = Private, H) -> Hash = sha, %% Option ?! - RawSignature = sign(H, Hash, Private), - ssh_bits:encode(["ssh-dss", RawSignature],[string, binary]). - -verify_host_key(SSH, K_S, H, H_SIG) -> - ALG = SSH#ssh.algorithms, - case ALG#alg.hkey of - 'ssh-rsa' -> - verify_host_key_rsa(SSH, K_S, H, H_SIG); - 'ssh-dss' -> - verify_host_key_dss(SSH, K_S, H, H_SIG); - _ -> - {error, bad_host_key_algorithm} - end. + _RawSignature = sign(H, Hash, Private). -verify_host_key_rsa(SSH, K_S, H, H_SIG) -> - case ssh_bits:decode(K_S,[string,mpint,mpint]) of - ["ssh-rsa", E, N] -> - ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]), - Public = #'RSAPublicKey'{publicExponent = E, modulus = N}, - case verify(H, sha, SIG, Public) of - false -> - {error, bad_signature}; - true -> - known_host_key(SSH, Public, 'ssh-rsa') - end; - _ -> - {error, bad_format} +verify_host_key(SSH, PublicKey, Digest, Signature) -> + case verify(Digest, sha, Signature, PublicKey) of + false -> + {error, bad_signature}; + true -> + known_host_key(SSH, PublicKey, public_algo(PublicKey)) end. -verify_host_key_dss(SSH, K_S, H, H_SIG) -> - case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of - ["ssh-dss",P,Q,G,Y] -> - ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]), - Public = {Y, #'Dss-Parms'{p = P, q = Q, g = G}}, - case verify(H, sha, SIG, Public) of - false -> - {error, bad_signature}; - true -> - known_host_key(SSH, Public, 'ssh-dss') - end; - _ -> - {error, bad_host_key_format} - end. +public_algo(#'RSAPublicKey'{}) -> + 'ssh-rsa'; +public_algo({_, #'Dss-Parms'{}}) -> + 'ssh-dss'. accepted_host(Ssh, PeerName, Opts) -> case proplists:get_value(silently_accept_hosts, Opts, false) of @@ -636,12 +540,12 @@ select(CL, SL) -> C. ssh_packet(#ssh_msg_kexinit{} = Msg, Ssh0) -> - BinMsg = ssh_bits:encode(Msg), + BinMsg = ssh_message:encode(Msg), Ssh = key_init(Ssh0#ssh.role, Ssh0, BinMsg), pack(BinMsg, Ssh); ssh_packet(Msg, Ssh) -> - BinMsg = ssh_bits:encode(Msg), + BinMsg = ssh_message:encode(Msg), pack(BinMsg, Ssh). pack(Data0, #ssh{encrypt_block_size = BlockSize, @@ -1021,23 +925,23 @@ hash(K, H, Ki, N, HASH) -> Kj = HASH([K, H, Ki]), hash(K, H, <<Ki/binary, Kj/binary>>, N-128, HASH). -kex_h(SSH, K_S, E, F, K) -> +kex_h(SSH, Key, E, F, K) -> L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version, SSH#ssh.c_keyinit, SSH#ssh.s_keyinit, - K_S, E,F,K], + ssh_message:encode_host_key(Key), E,F,K], [string,string,binary,binary,binary, mpint,mpint,mpint]), crypto:hash(sha,L). -kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) -> +kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) -> L = if Min==-1; Max==-1 -> Ts = [string,string,binary,binary,binary, uint32, mpint,mpint,mpint,mpint,mpint], ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version, SSH#ssh.c_keyinit,SSH#ssh.s_keyinit, - K_S, NBits, Prime, Gen, E,F,K], + ssh_message:encode_host_key(Key), NBits, Prime, Gen, E,F,K], Ts); true -> Ts = [string,string,binary,binary,binary, @@ -1045,7 +949,7 @@ kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) -> mpint,mpint,mpint,mpint,mpint], ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version, SSH#ssh.c_keyinit,SSH#ssh.s_keyinit, - K_S, Min, NBits, Max, + ssh_message:encode_host_key(Key), Min, NBits, Max, Prime, Gen, E,F,K], Ts) end, crypto:hash(sha,L). |