aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh')
-rw-r--r--lib/ssh/src/ssh_bits.erl141
-rw-r--r--lib/ssh/src/ssh_connect.hrl5
-rw-r--r--lib/ssh/src/ssh_message.erl169
-rw-r--r--lib/ssh/src/ssh_sftp.erl28
-rw-r--r--lib/ssh/src/ssh_transport.erl48
-rw-r--r--lib/ssh/src/ssh_xfer.erl26
-rw-r--r--lib/ssh/test/Makefile6
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_upgrade_SUITE.erl23
9 files changed, 184 insertions, 264 deletions
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index 4da3a6018b..101bf76cd3 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -26,52 +26,30 @@
-include("ssh.hrl").
--export([encode/2]).
--export([mpint/1, string/1, name_list/1]).
+-export([mpint/1, name_list/1]).
-export([random/1]).
--define(name_list(X),
- (fun(B) -> ?binary(B) end)(list_to_binary(name_concat(X)))).
-
-
-name_concat([Name]) when is_atom(Name) -> atom_to_list(Name);
-name_concat([Name]) when is_list(Name) -> Name;
-name_concat([Name|Ns]) ->
- if is_atom(Name) ->
- [atom_to_list(Name),"," | name_concat(Ns)];
- is_list(Name) ->
- [Name,"," | name_concat(Ns)]
- end;
-name_concat([]) -> [].
-
-
-name_list(Ns) ->
- ?name_list(Ns).
+%%%----------------------------------------------------------------
+name_list([Name]) -> to_bin(Name);
+name_list([Name|Ns]) -> <<(to_bin(Name))/binary, ",", (name_list(Ns))/binary>>;
+name_list([]) -> <<>>.
+
+to_bin(A) when is_atom(A) -> list_to_binary(atom_to_list(A));
+to_bin(S) when is_list(S) -> list_to_binary(S);
+to_bin(B) when is_binary(B) -> B.
+
+%%%----------------------------------------------------------------
+%%% Multi Precision Integer encoding
+mpint(-1) -> <<0,0,0,1,16#ff>>;
+mpint(0) -> <<0,0,0,0>>;
+mpint(X) when X < 0 -> mpint_neg(X,0,[]);
+mpint(X) -> mpint_pos(X,0,[]).
-
-string(Str) ->
- ?string(Str).
-
-
-%% MP representaion (SSH2)
-mpint(X) when X < 0 ->
- if X == -1 ->
- <<0,0,0,1,16#ff>>;
- true ->
- mpint_neg(X,0,[])
- end;
-mpint(X) ->
- if X == 0 ->
- <<0,0,0,0>>;
- true ->
- mpint_pos(X,0,[])
- end.
-
mpint_neg(-1,I,Ds=[MSB|_]) ->
if MSB band 16#80 =/= 16#80 ->
<<?UINT32((I+1)), (list_to_binary([255|Ds]))/binary>>;
true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
+ <<?UINT32(I), (list_to_binary(Ds))/binary>>
end;
mpint_neg(X,I,Ds) ->
mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]).
@@ -80,96 +58,17 @@ mpint_pos(0,I,Ds=[MSB|_]) ->
if MSB band 16#80 == 16#80 ->
<<?UINT32((I+1)), (list_to_binary([0|Ds]))/binary>>;
true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
+ <<?UINT32(I), (list_to_binary(Ds))/binary>>
end;
mpint_pos(X,I,Ds) ->
mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).
-encode(List, Types) ->
- list_to_binary(enc(List, Types)).
-
-%%
-%% Encode record element
-%%
-enc(Xs, Ts) ->
- enc(Xs, Ts, 0).
-
-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, [string|Ts], Offset) ->
- X0 = hd(Xs),
- Y = ?string(X0),
- [Y | enc(tl(Xs),Ts,Offset+size(Y))];
-enc(Xs, [string_utf8|Ts], Offset) ->
- X0 = hd(Xs),
- Y = ?string_utf8(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([], [],_) ->
- [].
-
-
-%%
-%% Create a binary with constant bytes
-%%
-fill_bits(N,C) ->
- list_to_binary(fill(N,C)).
-
-fill(0,_C) -> [];
-fill(1,C) -> [C];
-fill(N,C) ->
- Cs = fill(N div 2, C),
- Cs1 = [Cs,Cs],
- if N band 1 == 0 ->
- Cs1;
- true ->
- [C,Cs,Cs]
- end.
-
-
+%%%----------------------------------------------------------------
%% random/1
%% Generate N random bytes
%%
-random(N) ->
- crypto:strong_rand_bytes(N).
+random(N) -> crypto:strong_rand_bytes(N).
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index 9f9f3de8fa..0c9ddad641 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -24,8 +24,9 @@
-type channel_id() :: integer().
--define(DEFAULT_PACKET_SIZE, 32768).
--define(DEFAULT_WINDOW_SIZE, 2*?DEFAULT_PACKET_SIZE).
+-define(DEFAULT_PACKET_SIZE, 65536).
+-define(DEFAULT_WINDOW_SIZE, 10*?DEFAULT_PACKET_SIZE).
+
-define(DEFAULT_TIMEOUT, 5000).
-define(MAX_PROTO_VERSION, 255).
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index b6c4496be2..a0e9a4961c 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -32,16 +32,44 @@
-export([encode/1, decode/1, decode_keyboard_interactive_prompts/2]).
+-define('2bin'(X), (if is_binary(X) -> X;
+ is_list(X) -> list_to_binary(X);
+ X==undefined -> <<>>
+ end) ).
+
+-define('E...'(X), ?'2bin'(X)/binary ).
+-define(Eboolean(X), ?BOOLEAN(case X of
+ true -> ?TRUE;
+ false -> ?FALSE
+ end) ).
+-define(Ebyte(X), ?BYTE(X) ).
+-define(Euint32(X), ?UINT32(X) ).
+-define(Estring(X), ?STRING(?'2bin'(X)) ).
+-define(Estring_utf8(X), ?string_utf8(X)/binary ).
+-define(Ename_list(X), ?STRING(ssh_bits:name_list(X)) ).
+-define(Empint(X), (ssh_bits:mpint(X))/binary ).
+-define(Ebinary(X), ?STRING(X) ).
+
+%% encode(Msg) ->
+%% try encode1(Msg)
+%% catch
+%% C:E ->
+%% io:format('***********************~n~p:~p ~p~n',[C,E,Msg]),
+%% error(E)
+%% end.
+
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, '...']);
+ <<?Ebyte(?SSH_MSG_GLOBAL_REQUEST), ?Estring(Name), ?Eboolean(Bool), ?'E...'(Data)>>;
+
encode(#ssh_msg_request_success{data = Data}) ->
- <<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>;
+ <<?Ebyte(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>;
+
encode(#ssh_msg_request_failure{}) ->
- <<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>;
+ <<?Ebyte(?SSH_MSG_REQUEST_FAILURE)>>;
+
encode(#ssh_msg_channel_open{
channel_type = Type,
sender_channel = Sender,
@@ -49,9 +77,8 @@ encode(#ssh_msg_channel_open{
maximum_packet_size = Max,
data = Data
}) ->
- ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN,
- Type, Sender, Window, Max, Data], [byte, string, uint32,
- uint32, uint32, '...']);
+ <<?Ebyte(?SSH_MSG_CHANNEL_OPEN), ?Estring(Type), ?Euint32(Sender), ?Euint32(Window), ?Euint32(Max), ?'E...'(Data)>>;
+
encode(#ssh_msg_channel_open_confirmation{
recipient_channel = Recipient,
sender_channel = Sender,
@@ -59,60 +86,63 @@ encode(#ssh_msg_channel_open_confirmation{
maximum_packet_size = MaxPacketSize,
data = Data
}) ->
- ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN_CONFIRMATION, Recipient,
- Sender, InitWindowSize, MaxPacketSize, Data],
- [byte, uint32, uint32, uint32, uint32, '...']);
+ <<?Ebyte(?SSH_MSG_CHANNEL_OPEN_CONFIRMATION),
+ ?Euint32(Recipient), ?Euint32(Sender), ?Euint32(InitWindowSize), ?Euint32(MaxPacketSize),
+ ?'E...'(Data)>>;
+
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]);
+ <<?Ebyte(?SSH_MSG_CHANNEL_OPEN_FAILURE), ?Euint32(Recipient),?Euint32(Reason), ?Estring(Desc), ?Estring(Lang)>>;
+
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]);
+ <<?Ebyte(?SSH_MSG_CHANNEL_WINDOW_ADJUST), ?Euint32(Recipient), ?Euint32(Bytes)>>;
+
encode(#ssh_msg_channel_data{
recipient_channel = Recipient,
data = Data
}) ->
- ssh_bits:encode([?SSH_MSG_CHANNEL_DATA, Recipient, Data], [byte, uint32, binary]);
+ <<?Ebyte(?SSH_MSG_CHANNEL_DATA), ?Euint32(Recipient), ?Ebinary(Data)>>;
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]);
+ <<?Ebyte(?SSH_MSG_CHANNEL_EXTENDED_DATA), ?Euint32(Recipient), ?Euint32(DataType), ?Ebinary(Data)>>;
encode(#ssh_msg_channel_eof{recipient_channel = Recipient
}) ->
- <<?BYTE(?SSH_MSG_CHANNEL_EOF), ?UINT32(Recipient)>>;
+ <<?Ebyte(?SSH_MSG_CHANNEL_EOF), ?Euint32(Recipient)>>;
+
encode(#ssh_msg_channel_close{
recipient_channel = Recipient
}) ->
- <<?BYTE(?SSH_MSG_CHANNEL_CLOSE), ?UINT32(Recipient)>>;
+ <<?Ebyte(?SSH_MSG_CHANNEL_CLOSE), ?Euint32(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, '...']);
+ <<?Ebyte(?SSH_MSG_CHANNEL_REQUEST), ?Euint32(Recipient), ?Estring(Type), ?Eboolean(Bool), ?'E...'(Data)>>;
+
encode(#ssh_msg_channel_success{
recipient_channel = Recipient
}) ->
- <<?BYTE(?SSH_MSG_CHANNEL_SUCCESS), ?UINT32(Recipient)>>;
+ <<?Ebyte(?SSH_MSG_CHANNEL_SUCCESS), ?Euint32(Recipient)>>;
+
encode(#ssh_msg_channel_failure{
recipient_channel = Recipient
}) ->
- <<?BYTE(?SSH_MSG_CHANNEL_FAILURE), ?UINT32(Recipient)>>;
+ <<?Ebyte(?SSH_MSG_CHANNEL_FAILURE), ?Euint32(Recipient)>>;
encode(#ssh_msg_userauth_request{
user = User,
@@ -120,36 +150,33 @@ encode(#ssh_msg_userauth_request{
method = Method,
data = Data
}) ->
- ssh_bits:encode([?SSH_MSG_USERAUTH_REQUEST, User, Service, Method, Data],
- [byte, string_utf8, string, string, '...']);
+ <<?Ebyte(?SSH_MSG_USERAUTH_REQUEST), ?Estring_utf8(User), ?Estring(Service), ?Estring(Method), ?'E...'(Data)>>;
+
encode(#ssh_msg_userauth_failure{
authentications = Auths,
partial_success = Bool
}) ->
- ssh_bits:encode([?SSH_MSG_USERAUTH_FAILURE, Auths, Bool],
- [byte, string, boolean]);
+ <<?Ebyte(?SSH_MSG_USERAUTH_FAILURE), ?Estring(Auths), ?Eboolean(Bool)>>;
+
encode(#ssh_msg_userauth_success{}) ->
- <<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>;
+ <<?Ebyte(?SSH_MSG_USERAUTH_SUCCESS)>>;
encode(#ssh_msg_userauth_banner{
message = Banner,
language = Lang
}) ->
- ssh_bits:encode([?SSH_MSG_USERAUTH_BANNER, Banner, Lang],
- [byte, string_utf8, string]);
+ <<?Ebyte(?SSH_MSG_USERAUTH_BANNER), ?Estring_utf8(Banner), ?Estring(Lang)>>;
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]);
+ <<?Ebyte(?SSH_MSG_USERAUTH_PK_OK), ?Estring(Alg), ?Ebinary(KeyBlob)>>;
encode(#ssh_msg_userauth_passwd_changereq{prompt = Prompt,
languge = Lang
})->
- ssh_bits:encode([?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, Prompt, Lang],
- [byte, string, string]);
+ <<?Ebyte(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?Estring(Prompt), ?Estring(Lang)>>;
encode(#ssh_msg_userauth_info_request{
name = Name,
@@ -157,41 +184,37 @@ encode(#ssh_msg_userauth_info_request{
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, '...']);
+ <<?Ebyte(?SSH_MSG_USERAUTH_INFO_REQUEST), ?Estring(Name), ?Estring(Inst), ?Estring(Lang),
+ ?Euint32(NumPromtps), ?'E...'(Data)>>;
encode(#ssh_msg_userauth_info_response{
num_responses = Num,
data = Data}) ->
- Responses = lists:map(fun("") ->
- <<>>;
- (Response) ->
- ssh_bits:encode([Response], [string])
- end, Data),
- Start = ssh_bits:encode([?SSH_MSG_USERAUTH_INFO_RESPONSE, Num],
- [byte, uint32]),
- iolist_to_binary([Start, Responses]);
+ lists:foldl(fun %%("", Acc) -> Acc; % commented out since it seem wrong
+ (Response, Acc) -> <<Acc/binary, ?Estring(Response)>>
+ end,
+ <<?Ebyte(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?Euint32(Num)>>,
+ Data);
encode(#ssh_msg_disconnect{
code = Code,
description = Desc,
language = Lang
}) ->
- ssh_bits:encode([?SSH_MSG_DISCONNECT, Code, Desc, Lang],
- [byte, uint32, string, string]);
+ <<?Ebyte(?SSH_MSG_DISCONNECT), ?Euint32(Code), ?Estring(Desc), ?Estring(Lang)>>;
encode(#ssh_msg_service_request{
name = Service
}) ->
- ssh_bits:encode([?SSH_MSG_SERVICE_REQUEST, Service], [byte, string]);
+ <<?Ebyte(?SSH_MSG_SERVICE_REQUEST), ?Estring(Service)>>;
encode(#ssh_msg_service_accept{
name = Service
}) ->
- ssh_bits:encode([?SSH_MSG_SERVICE_ACCEPT, Service], [byte, string]);
+ <<?Ebyte(?SSH_MSG_SERVICE_ACCEPT), ?Estring(Service)>>;
encode(#ssh_msg_newkeys{}) ->
- <<?BYTE(?SSH_MSG_NEWKEYS)>>;
+ <<?Ebyte(?SSH_MSG_NEWKEYS)>>;
encode(#ssh_msg_kexinit{
cookie = Cookie,
@@ -208,19 +231,13 @@ encode(#ssh_msg_kexinit{
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]);
+ <<?Ebyte(?SSH_MSG_KEXINIT), Cookie/binary,
+ ?Ename_list(KeyAlgs), ?Ename_list(HostKeyAlgs), ?Ename_list(EncAlgC2S), ?Ename_list(EncAlgS2C), ?Ename_list(MacAlgC2S),
+ ?Ename_list(MacAlgS2C), ?Ename_list(CompAlgS2C), ?Ename_list(CompAlgC2S), ?Ename_list(LangC2S), ?Ename_list(LangS2C),
+ ?Eboolean(Bool), ?Euint32(Reserved)>>;
encode(#ssh_msg_kexdh_init{e = E}) ->
- ssh_bits:encode([?SSH_MSG_KEXDH_INIT, E], [byte, mpint]);
+ <<?Ebyte(?SSH_MSG_KEXDH_INIT), ?Empint(E)>>;
encode(#ssh_msg_kexdh_reply{
public_host_key = Key,
@@ -229,25 +246,23 @@ encode(#ssh_msg_kexdh_reply{
}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
EncSign = encode_signature(Key, Signature),
- ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
+ <<?Ebyte(?SSH_MSG_KEXDH_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
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]);
+ <<?Ebyte(?SSH_MSG_KEX_DH_GEX_REQUEST), ?Euint32(Min), ?Euint32(N), ?Euint32(Max)>>;
+
encode(#ssh_msg_kex_dh_gex_request_old{n = N}) ->
- ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST_OLD, N],
- [byte, uint32]);
+ <<?Ebyte(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?Euint32(N)>>;
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]);
+ <<?Ebyte(?SSH_MSG_KEX_DH_GEX_GROUP), ?Empint(Prime), ?Empint(Generator)>>;
encode(#ssh_msg_kex_dh_gex_init{e = Public}) ->
- ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_INIT, Public], [byte, mpint]);
+ <<?Ebyte(?SSH_MSG_KEX_DH_GEX_INIT), ?Empint(Public)>>;
encode(#ssh_msg_kex_dh_gex_reply{
%% Will be private key encode_host_key extracts only the public part!
@@ -257,26 +272,26 @@ encode(#ssh_msg_kex_dh_gex_reply{
}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
EncSign = encode_signature(Key, Signature),
- ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
+ <<?Ebyte(?SSH_MSG_KEX_DH_GEX_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
- ssh_bits:encode([?SSH_MSG_KEX_ECDH_INIT, Q_c], [byte, mpint]);
+ <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Empint(Q_c)>>;
encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
EncSign = encode_signature(Key, Sign),
- ssh_bits:encode([?SSH_MSG_KEX_ECDH_REPLY, EncKey, Q_s, EncSign], [byte, binary, mpint, binary]);
+ <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Empint(Q_s), ?Ebinary(EncSign)>>;
encode(#ssh_msg_ignore{data = Data}) ->
- ssh_bits:encode([?SSH_MSG_IGNORE, Data], [byte, string]);
+ <<?Ebyte(?SSH_MSG_IGNORE), ?Estring(Data)>>;
encode(#ssh_msg_unimplemented{sequence = Seq}) ->
- ssh_bits:encode([?SSH_MSG_UNIMPLEMENTED, Seq], [byte, uint32]);
+ <<?Ebyte(?SSH_MSG_UNIMPLEMENTED), ?Euint32(Seq)>>;
encode(#ssh_msg_debug{always_display = Bool,
message = Msg,
language = Lang}) ->
- ssh_bits:encode([?SSH_MSG_DEBUG, Bool, Msg, Lang], [byte, boolean, string, string]).
+ <<?Ebyte(?SSH_MSG_DEBUG), ?Eboolean(Bool), ?Estring(Msg), ?Estring(Lang)>>.
%% Connection Messages
@@ -553,10 +568,10 @@ decode_signature(<<?DEC_BIN(_Alg,__0), ?UINT32(_), Signature/binary>>) ->
encode_signature(#'RSAPublicKey'{}, Signature) ->
- ssh_bits:encode(["ssh-rsa", Signature],[string, binary]);
+ <<?Ebinary(<<"ssh-rsa">>), ?Ebinary(Signature)>>;
encode_signature({_, #'Dss-Parms'{}}, Signature) ->
- ssh_bits:encode(["ssh-dss", Signature],[string, binary]);
+ <<?Ebinary(<<"ssh-dss">>), ?Ebinary(Signature)>>;
encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) ->
CurveName = public_key:oid2ssh_curvename(OID),
- ssh_bits:encode([<<"ecdsa-sha2-",CurveName/binary>>, Signature], [binary,binary]).
+ <<?Ebinary(<<"ecdsa-sha2-",CurveName/binary>>), ?Ebinary(Signature)>>.
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index dbacf730cc..eb99406626 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -99,8 +99,8 @@ start_channel(Host) when is_list(Host) ->
start_channel(Host, []).
start_channel(Cm, Opts) when is_pid(Cm) ->
Timeout = proplists:get_value(timeout, Opts, infinity),
- {_, SftpOpts} = handle_options(Opts, [], []),
- case ssh_xfer:attach(Cm, []) of
+ {_, ChanOpts, SftpOpts} = handle_options(Opts, [], [], []),
+ case ssh_xfer:attach(Cm, [], ChanOpts) of
{ok, ChannelId, Cm} ->
case ssh_channel:start(Cm, ChannelId,
?MODULE, [Cm, ChannelId, SftpOpts]) of
@@ -123,9 +123,9 @@ start_channel(Cm, Opts) when is_pid(Cm) ->
start_channel(Host, Opts) ->
start_channel(Host, 22, Opts).
start_channel(Host, Port, Opts) ->
- {SshOpts, SftpOpts} = handle_options(Opts, [], []),
+ {SshOpts, ChanOpts, SftpOpts} = handle_options(Opts, [], [], []),
Timeout = proplists:get_value(timeout, SftpOpts, infinity),
- case ssh_xfer:connect(Host, Port, SshOpts, Timeout) of
+ case ssh_xfer:connect(Host, Port, SshOpts, ChanOpts, Timeout) of
{ok, ChannelId, Cm} ->
case ssh_channel:start(Cm, ChannelId, ?MODULE, [Cm,
ChannelId, SftpOpts]) of
@@ -842,14 +842,18 @@ terminate(_Reason, State) ->
%%====================================================================
%% Internal functions
%%====================================================================
-handle_options([], Sftp, Ssh) ->
- {Ssh, Sftp};
-handle_options([{timeout, _} = Opt | Rest], Sftp, Ssh) ->
- handle_options(Rest, [Opt | Sftp], Ssh);
-handle_options([{sftp_vsn, _} = Opt| Rest], Sftp, Ssh) ->
- handle_options(Rest, [Opt | Sftp], Ssh);
-handle_options([Opt | Rest], Sftp, Ssh) ->
- handle_options(Rest, Sftp, [Opt | Ssh]).
+handle_options([], Sftp, Chan, Ssh) ->
+ {Ssh, Chan, Sftp};
+handle_options([{timeout, _} = Opt | Rest], Sftp, Chan, Ssh) ->
+ handle_options(Rest, [Opt|Sftp], Chan, Ssh);
+handle_options([{sftp_vsn, _} = Opt| Rest], Sftp, Chan, Ssh) ->
+ handle_options(Rest, [Opt|Sftp], Chan, Ssh);
+handle_options([{window_size, _} = Opt| Rest], Sftp, Chan, Ssh) ->
+ handle_options(Rest, Sftp, [Opt|Chan], Ssh);
+handle_options([{packet_size, _} = Opt| Rest], Sftp, Chan, Ssh) ->
+ handle_options(Rest, Sftp, [Opt|Chan], Ssh);
+handle_options([Opt|Rest], Sftp, Chan, Ssh) ->
+ handle_options(Rest, Sftp, Chan, [Opt|Ssh]).
call(Pid, Msg, TimeOut) ->
ssh_channel:call(Pid, {{timeout, TimeOut}, Msg}, infinity).
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 18037b8461..a648c7af3d 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -52,6 +52,14 @@
-export([pack/3]).
-export([decompress/2, decrypt_blocks/3, is_valid_mac/3 ]). % FIXME: remove
+-define(Estring(X), ?STRING((if is_binary(X) -> X;
+ is_list(X) -> list_to_binary(X);
+ X==undefined -> <<>>
+ end))).
+-define(Empint(X), (ssh_bits:mpint(X))/binary ).
+-define(Ebinary(X), ?STRING(X) ).
+-define(Euint32(X), ?UINT32(X) ).
+
%%%----------------------------------------------------------------------------
%%%
%%% There is a difference between supported and default algorithms. The
@@ -1084,7 +1092,7 @@ sign(SigData, Hash, #'DSAPrivateKey'{} = Key) ->
sign(SigData, Hash, Key = #'ECPrivateKey'{}) ->
DerEncodedSign = public_key:sign(SigData, Hash, Key),
#'ECDSA-Sig-Value'{r=R, s=S} = public_key:der_decode('ECDSA-Sig-Value', DerEncodedSign),
- ssh_bits:encode([R,S], [mpint,mpint]);
+ <<?Empint(R),?Empint(S)>>;
sign(SigData, Hash, Key) ->
public_key:sign(SigData, Hash, Key).
@@ -1584,21 +1592,16 @@ hash(K, H, Ki, N, HASH) ->
kex_h(SSH, Key, E, F, K) ->
KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
- L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
- SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
- KeyBin, E,F,K],
- [string,string,binary,binary,binary,
- mpint,mpint,mpint]),
+ L = <<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+ ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+ ?Empint(E), ?Empint(F), ?Empint(K)>>,
crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
-%% crypto:hash(sha,L).
kex_h(SSH, Curve, Key, Q_c, Q_s, K) ->
KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
- L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
- SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
- KeyBin, Q_c, Q_s, K],
- [string,string,binary,binary,binary,
- mpint,mpint,mpint]),
+ L = <<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+ ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+ ?Empint(Q_c), ?Empint(Q_s), ?Empint(K)>>,
crypto:hash(sha(Curve), L).
kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
@@ -1607,21 +1610,14 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
%% flag from 'ssh_msg_kex_dh_gex_request_old'
%% It was like this before that message was supported,
%% why?
- 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,
- KeyBin, NBits, Prime, Gen, E,F,K],
- Ts);
+ <<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+ ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+ ?Empint(E), ?Empint(F), ?Empint(K)>>;
true ->
- Ts = [string,string,binary,binary,binary,
- uint32,uint32,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,
- KeyBin, Min, NBits, Max,
- Prime, Gen, E,F,K], Ts)
+ <<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
+ ?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit), ?Ebinary(KeyBin),
+ ?Euint32(Min), ?Euint32(NBits), ?Euint32(Max),
+ ?Empint(Prime), ?Empint(Gen), ?Empint(E), ?Empint(F), ?Empint(K)>>
end,
crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index b8dff1c533..259dc71aa5 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -24,7 +24,7 @@
-module(ssh_xfer).
--export([attach/2, connect/3, connect/4]).
+-export([attach/2, attach/3, connect/3, connect/4, connect/5]).
-export([open/6, opendir/3, readdir/3, close/3, read/5, write/5,
rename/5, remove/3, mkdir/4, rmdir/3, realpath/3, extended/4,
stat/4, fstat/4, lstat/4, setstat/4,
@@ -47,28 +47,38 @@
-define(is_set(F, Bits),
((F) band (Bits)) == (F)).
--define(XFER_PACKET_SIZE, 32768).
--define(XFER_WINDOW_SIZE, 4*?XFER_PACKET_SIZE).
+-define(XFER_PACKET_SIZE, 65536).
+-define(XFER_WINDOW_SIZE, 20*?XFER_PACKET_SIZE).
attach(CM, Opts) ->
- open_xfer(CM, Opts).
+ open_xfer(CM, Opts, []).
+
+attach(CM, Opts, ChanOpts) ->
+ open_xfer(CM, Opts, ChanOpts).
+
connect(Host, Port, Opts) ->
case ssh:connect(Host, Port, Opts) of
- {ok, CM} -> open_xfer(CM, Opts);
+ {ok, CM} -> open_xfer(CM, Opts, []);
Error -> Error
end.
connect(Host, Port, Opts, Timeout) ->
+ connect(Host, Port, Opts, [], Timeout).
+
+connect(Host, Port, Opts, ChanOpts, Timeout) ->
case ssh:connect(Host, Port, Opts, Timeout) of
- {ok, CM} -> open_xfer(CM, [{timeout, Timeout}|Opts]);
+ {ok, CM} -> open_xfer(CM, [{timeout, Timeout}|Opts], ChanOpts);
{error, Timeout} -> {error, timeout};
Error -> Error
end.
-open_xfer(CM, Opts) ->
+
+open_xfer(CM, Opts, ChanOpts) ->
TMO = proplists:get_value(timeout, Opts, infinity),
- case ssh_connection:session_channel(CM, ?XFER_WINDOW_SIZE, ?XFER_PACKET_SIZE, TMO) of
+ WindowSize = proplists:get_value(window_size, ChanOpts, ?XFER_WINDOW_SIZE),
+ PacketSize = proplists:get_value(packet_size, ChanOpts, ?XFER_PACKET_SIZE),
+ case ssh_connection:session_channel(CM, WindowSize, PacketSize, TMO) of
{ok, ChannelId} ->
{ok, ChannelId, CM};
Error ->
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 9cd98f069f..fb539f98fa 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -64,8 +64,7 @@ TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
DATA_DIRS = $(MODULES:%=%_data)
-INCLUDES = -I$(ERL_TOP)/lib/test_server/include \
- -I$(ERL_TOP)/lib/ssh/src \
+INCLUDES = -I$(ERL_TOP)/lib/ssh/src
EMAKEFILE=Emakefile
MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile)
@@ -88,8 +87,7 @@ RELSYSDIR = $(RELEASE_PATH)/ssh_test
# The path to the test_server ebin dir is needed when
# running the target "targets".
# ----------------------------------------------------
-ERL_COMPILE_FLAGS += -pa ../../../internal_tools/test_server/ebin \
- $(INCLUDES)
+ERL_COMPILE_FLAGS += $(INCLUDES)
EBIN = .
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index fe197f8672..6b78a32a9b 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -307,7 +307,7 @@ no_common_alg_client_disconnects(Config) ->
{send, hello},
{match, #ssh_msg_kexinit{_='_'}, receive_msg},
{send, #ssh_msg_kexinit{ % with unsupported "SOME-UNSUPPORTED"
- cookie = 247381486335508958743193106082599558706,
+ cookie = <<80,158,95,51,174,35,73,130,246,141,200,49,180,190,82,234>>,
kex_algorithms = ["diffie-hellman-group1-sha1"],
server_host_key_algorithms = ["SOME-UNSUPPORTED"], % SIC!
encryption_algorithms_client_to_server = ["aes128-ctr"],
diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl
index 85f4d36258..0d936c118b 100644
--- a/lib/ssh/test/ssh_upgrade_SUITE.erl
+++ b/lib/ssh/test/ssh_upgrade_SUITE.erl
@@ -46,20 +46,17 @@ all() ->
init_per_suite(Config0) ->
catch crypto:stop(),
- try {crypto:start(), erlang:system_info({wordsize, internal}) ==
- erlang:system_info({wordsize, external})} of
- {ok, true} ->
- case ct_release_test:init(Config0) of
- {skip, Reason} ->
- {skip, Reason};
- Config ->
- ssh:start(),
- Config
- end;
- {ok, false} ->
- {skip, "Test server will not handle halfwordemulator correctly. Skip as halfwordemulator is deprecated"}
+ try crypto:start() of
+ ok ->
+ case ct_release_test:init(Config0) of
+ {skip, Reason} ->
+ {skip, Reason};
+ Config ->
+ ssh:start(),
+ Config
+ end
catch _:_ ->
- {skip, "Crypto did not start"}
+ {skip, "Crypto did not start"}
end.
end_per_suite(Config) ->