diff options
Diffstat (limited to 'lib/ssh/src/ssh_message.erl')
| -rw-r--r-- | lib/ssh/src/ssh_message.erl | 161 | 
1 files changed, 143 insertions, 18 deletions
| diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl index 562f040477..d95e58c1bb 100644 --- a/lib/ssh/src/ssh_message.erl +++ b/lib/ssh/src/ssh_message.erl @@ -1,7 +1,7 @@  %%  %% %CopyrightBegin%  %% -%% Copyright Ericsson AB 2013-2016. All Rights Reserved. +%% Copyright Ericsson AB 2013-2018. 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. @@ -32,6 +32,8 @@  -export([encode/1, decode/1, decode_keyboard_interactive_prompts/2]). +-export([dbg_trace/3]). +  -define('2bin'(X), (if is_binary(X) -> X;  		       is_list(X) -> list_to_binary(X);  		       X==undefined -> <<>> @@ -215,6 +217,16 @@ encode(#ssh_msg_service_accept{  	 }) ->      <<?Ebyte(?SSH_MSG_SERVICE_ACCEPT), ?Estring_utf8(Service)>>; +encode(#ssh_msg_ext_info{ +          nr_extensions = N, +          data = Data +         }) -> +    lists:foldl(fun({ExtName,ExtVal}, Acc) -> +                        <<Acc/binary, ?Estring(ExtName), ?Estring(ExtVal)>> +                end, +                <<?Ebyte(?SSH_MSG_EXT_INFO), ?Euint32(N)>>, +                Data); +  encode(#ssh_msg_newkeys{}) ->      <<?Ebyte(?SSH_MSG_NEWKEYS)>>; @@ -242,12 +254,12 @@ encode(#ssh_msg_kexdh_init{e = E}) ->      <<?Ebyte(?SSH_MSG_KEXDH_INIT), ?Empint(E)>>;  encode(#ssh_msg_kexdh_reply{ -	  public_host_key = Key, +	  public_host_key = {Key,SigAlg},  	  f = F,  	  h_sig = Signature  	 }) ->      EncKey = public_key:ssh_encode(Key, ssh2_pubkey), -    EncSign = encode_signature(Key, Signature), +    EncSign = encode_signature(Key, SigAlg, Signature),      <<?Ebyte(?SSH_MSG_KEXDH_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;  encode(#ssh_msg_kex_dh_gex_request{ @@ -268,21 +280,21 @@ encode(#ssh_msg_kex_dh_gex_init{e = Public}) ->  encode(#ssh_msg_kex_dh_gex_reply{  	  %% Will be private key encode_host_key extracts only the public part! -	  public_host_key = Key, +	  public_host_key = {Key,SigAlg},  	  f = F,  	  h_sig = Signature  	 }) ->      EncKey = public_key:ssh_encode(Key, ssh2_pubkey), -    EncSign = encode_signature(Key, Signature), +    EncSign = encode_signature(Key, SigAlg, Signature),      <<?Ebyte(?SSH_MSG_KEX_DH_GEX_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;  encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) -> -    <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Empint(Q_c)>>; +    <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Ebinary(Q_c)>>; -encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) -> +encode(#ssh_msg_kex_ecdh_reply{public_host_key = {Key,SigAlg}, q_s = Q_s, h_sig = Sign}) ->      EncKey = public_key:ssh_encode(Key, ssh2_pubkey), -    EncSign = encode_signature(Key, Sign), -    <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Empint(Q_s), ?Ebinary(EncSign)>>; +    EncSign = encode_signature(Key, SigAlg, Sign), +    <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Ebinary(Q_s), ?Ebinary(EncSign)>>;  encode(#ssh_msg_ignore{data = Data}) ->      <<?Ebyte(?SSH_MSG_IGNORE), ?Estring_utf8(Data)>>; @@ -435,6 +447,18 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) ->         num_responses = Num,         data = Data}; +decode(<<?BYTE(?SSH_MSG_EXT_INFO), ?UINT32(N), BinData/binary>>) -> +    Data = bin_foldr( +             fun(Bin,Acc) when length(Acc) == N -> +                     {Bin,Acc}; +                (<<?DEC_BIN(V0,__0), ?DEC_BIN(V1,__1), Rest/binary>>, Acc) ->  +                     {Rest,[{binary_to_list(V0),binary_to_list(V1)}|Acc]} +             end, [], BinData), +    #ssh_msg_ext_info{ +       nr_extensions = N, +       data = Data +      }; +  %%% Keyexchange messages  decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>) ->      decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10); @@ -480,13 +504,13 @@ decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1),         h_sig = decode_signature(Hashsign)        }; -decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_MPINT(Q_c,__0)>>) -> +decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_BIN(Q_c,__0)>>) ->      #ssh_msg_kex_ecdh_init{         q_c = Q_c        };  decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY), -	 ?DEC_BIN(Key,__1), ?DEC_MPINT(Q_s,__2), ?DEC_BIN(Sig,__3)>>) -> +	 ?DEC_BIN(Key,__1), ?DEC_BIN(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->      #ssh_msg_kex_ecdh_reply{         public_host_key = public_key:ssh_decode(Key, ssh2_pubkey),         q_s = Q_s, @@ -537,17 +561,28 @@ decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?DEC_BIN(Msg,__0), ?DEC_BIN(Lang,__  %%% Helper functions  %%% +bin_foldr(Fun, Acc, Bin) -> +    lists:reverse(bin_foldl(Fun, Acc, Bin)). + +bin_foldl(_, Acc, <<>>) -> Acc; +bin_foldl(Fun, Acc0, Bin0) -> +    {Bin,Acc} = Fun(Bin0,Acc0), +    bin_foldl(Fun, Acc, Bin). + +%%%----------------------------------------------------------------  decode_keyboard_interactive_prompts(<<>>, Acc) ->      lists:reverse(Acc);  decode_keyboard_interactive_prompts(<<?DEC_BIN(Prompt,__0), ?BYTE(Bool), Bin/binary>>,  				    Acc) ->      decode_keyboard_interactive_prompts(Bin, [{Prompt, erl_boolean(Bool)} | Acc]). +%%%----------------------------------------------------------------  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(<<?BYTE(Bool)>>, Acc, 0) -> @@ -565,15 +600,105 @@ decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) ->  %%% Signature decode/encode  %%% -decode_signature(<<?DEC_BIN(_Alg,__0), ?UINT32(_), Signature/binary>>) -> -    Signature. +decode_signature(<<?DEC_BIN(Alg,__0), ?UINT32(_), Signature/binary>>) -> +    {binary_to_list(Alg), Signature}. -encode_signature(#'RSAPublicKey'{}, Signature) -> -    <<?Ebinary(<<"ssh-rsa">>), ?Ebinary(Signature)>>; -encode_signature({_, #'Dss-Parms'{}}, Signature) -> +encode_signature(#'RSAPublicKey'{}, SigAlg, Signature) -> +    SignName = list_to_binary(atom_to_list(SigAlg)), +    <<?Ebinary(SignName), ?Ebinary(Signature)>>; +encode_signature({_, #'Dss-Parms'{}}, _SigAlg, Signature) ->      <<?Ebinary(<<"ssh-dss">>), ?Ebinary(Signature)>>; -encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) -> +encode_signature({#'ECPoint'{}, {namedCurve,OID}}, _SigAlg, Signature) ->      CurveName = public_key:oid2ssh_curvename(OID), -    <<?Ebinary(<<"ecdsa-sha2-",CurveName/binary>>), ?Ebinary(Signature)>>. +    <<?Ebinary(<<"ecdsa-sha2-",CurveName/binary>>), ?Ebinary(Signature)>>; +encode_signature({ed_pub, ed25519,_}, _SigAlg, Signature) -> +    <<?Ebinary(<<"ssh-ed25519">>), ?Ebinary(Signature)>>; +encode_signature({ed_pub, ed448,_}, _SigAlg, Signature) -> +    <<?Ebinary(<<"ssh-ed448">>), ?Ebinary(Signature)>>. +     + + +%%%################################################################ +%%%# +%%%# Tracing +%%%# + +dbg_trace(points,         _,  _) -> [ssh_messages, raw_messages]; + +dbg_trace(flags, ssh_messages, _) -> [c]; +dbg_trace(on,    ssh_messages, _) -> dbg:tp(?MODULE,encode,1,x), +                                     dbg:tp(?MODULE,decode,1,x); +dbg_trace(off,   ssh_messages, _) -> dbg:ctpg(?MODULE,encode,1), +                                     dbg:ctpg(?MODULE,decode,1); + +dbg_trace(flags, raw_messages, A) -> dbg_trace(flags, ssh_messages, A); +dbg_trace(on,    raw_messages, A) -> dbg_trace(on,    ssh_messages, A); +dbg_trace(off,   raw_messages, A) -> dbg_trace(off,   ssh_messages, A); + +dbg_trace(format, ssh_messages, {call,{?MODULE,encode,[Msg]}}) -> +    Name = string:to_upper(atom_to_list(element(1,Msg))), +    ["Going to send ",Name,":\n", +     wr_record(ssh_dbg:shrink_bin(Msg)) +    ]; +dbg_trace(format, ssh_messages, {return_from,{?MODULE,decode,1},Msg}) -> +    Name = string:to_upper(atom_to_list(element(1,Msg))), +    ["Received ",Name,":\n", +     wr_record(ssh_dbg:shrink_bin(Msg)) +    ]; + +dbg_trace(format, raw_messages, {call,{?MODULE,decode,[BytesPT]}}) -> +    ["Received plain text bytes (shown after decryption):\n", +     io_lib:format("~p",[BytesPT]) +    ]; +dbg_trace(format, raw_messages, {return_from,{?MODULE,encode,1},BytesPT}) -> +    ["Going to send plain text bytes (shown before encryption):\n", +     io_lib:format("~p",[BytesPT]) +    ]. + + +?wr_record(ssh_msg_disconnect); +?wr_record(ssh_msg_ignore); +?wr_record(ssh_msg_unimplemented); +?wr_record(ssh_msg_debug); +?wr_record(ssh_msg_service_request); +?wr_record(ssh_msg_service_accept); +?wr_record(ssh_msg_kexinit); +?wr_record(ssh_msg_kexdh_init); +?wr_record(ssh_msg_kexdh_reply); +?wr_record(ssh_msg_newkeys); +?wr_record(ssh_msg_ext_info); +?wr_record(ssh_msg_kex_dh_gex_request); +?wr_record(ssh_msg_kex_dh_gex_request_old); +?wr_record(ssh_msg_kex_dh_gex_group); +?wr_record(ssh_msg_kex_dh_gex_init); +?wr_record(ssh_msg_kex_dh_gex_reply); +?wr_record(ssh_msg_kex_ecdh_init); +?wr_record(ssh_msg_kex_ecdh_reply); + +?wr_record(ssh_msg_userauth_request); +?wr_record(ssh_msg_userauth_failure); +?wr_record(ssh_msg_userauth_success); +?wr_record(ssh_msg_userauth_banner); +?wr_record(ssh_msg_userauth_passwd_changereq); +?wr_record(ssh_msg_userauth_pk_ok); +?wr_record(ssh_msg_userauth_info_request); +?wr_record(ssh_msg_userauth_info_response); + +?wr_record(ssh_msg_global_request); +?wr_record(ssh_msg_request_success); +?wr_record(ssh_msg_request_failure); +?wr_record(ssh_msg_channel_open); +?wr_record(ssh_msg_channel_open_confirmation); +?wr_record(ssh_msg_channel_open_failure); +?wr_record(ssh_msg_channel_window_adjust); +?wr_record(ssh_msg_channel_data); +?wr_record(ssh_msg_channel_extended_data); +?wr_record(ssh_msg_channel_eof); +?wr_record(ssh_msg_channel_close); +?wr_record(ssh_msg_channel_request); +?wr_record(ssh_msg_channel_success); +?wr_record(ssh_msg_channel_failure); + +wr_record(R) -> io_lib:format('~p~n',[R]). | 
