summaryrefslogtreecommitdiff
path: root/lib/ssh/src/ssh_transport.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ssh/src/ssh_transport.erl')
-rw-r--r--lib/ssh/src/ssh_transport.erl122
1 files changed, 42 insertions, 80 deletions
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index e43c345130..c0b46b338b 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2023. 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.
@@ -49,7 +49,6 @@
handle_kex_ecdh_init/2,
handle_kex_ecdh_reply/2,
parallell_gen_key/1,
- extract_public_key/1,
ssh_packet/2, pack/2,
valid_key_sha_alg/3,
sign/3, sign/4,
@@ -62,6 +61,8 @@
-behaviour(ssh_dbg).
-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
+-define(MIN_DH_KEY_SIZE, 400).
+
%%% For test suites
-export([pack/3, adjust_algs_for_peer_version/2]).
@@ -432,7 +433,12 @@ kexinit_error(Class, Error, Role, Own, CounterPart) ->
_ ->
{"Kexinit failed in ~p: ~p:~p", [Role,Class,Error]}
end,
- io_lib:format(Fmt, Args).
+ try io_lib:format(Fmt, Args) of
+ R -> R
+ catch
+ _:_ ->
+ io_lib:format("Kexinit failed in ~p: ~p:~p", [Role, Class, Error])
+ end.
alg_info(client, Alg) ->
alg_info(Alg);
@@ -553,7 +559,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
{Public, Private} = generate_key(dh, [P,G,2*Sz]),
K = compute_key(dh, E, Private, [P,G]),
MyPrivHostKey = get_host_key(SignAlg, Opts),
- MyPubHostKey = extract_public_key(MyPrivHostKey),
+ MyPubHostKey = ssh_file:extract_public_key(MyPrivHostKey),
H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {E,Public,K}),
case sign(H, SignAlg, MyPrivHostKey, Ssh0) of
{ok,H_SIG} ->
@@ -705,7 +711,7 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
if
1<K, K<(P-1) ->
MyPrivHostKey = get_host_key(SignAlg, Opts),
- MyPubHostKey = extract_public_key(MyPrivHostKey),
+ MyPubHostKey = ssh_file:extract_public_key(MyPrivHostKey),
H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {Min,NBits,Max,P,G,E,Public,K}),
case sign(H, SignAlg, MyPrivHostKey, Ssh0) of
{ok,H_SIG} ->
@@ -788,7 +794,7 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
of
K ->
MyPrivHostKey = get_host_key(SignAlg, Opts),
- MyPubHostKey = extract_public_key(MyPrivHostKey),
+ MyPubHostKey = ssh_file:extract_public_key(MyPrivHostKey),
H = kex_hash(Ssh0, MyPubHostKey, sha(Curve), {PeerPublic, MyPublic, K}),
case sign(H, SignAlg, MyPrivHostKey, Ssh0) of
{ok,H_SIG} ->
@@ -926,37 +932,6 @@ call_KeyCb(F, Args, Opts) ->
UserOpts = ?GET_OPT(key_cb_options, Opts),
apply(KeyCb, F, Args ++ [[{key_cb_private,KeyCbOpts}|UserOpts]]).
-extract_public_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) ->
- #'RSAPublicKey'{modulus = N, publicExponent = E};
-extract_public_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) ->
- {Y, #'Dss-Parms'{p=P, q=Q, g=G}};
-extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID},
- publicKey = Pub0, privateKey = Priv}) when
- OID == ?'id-Ed25519'orelse
- OID == ?'id-Ed448' ->
- case {pubkey_cert_records:namedCurves(OID), Pub0} of
- {Alg, asn1_NOVALUE} ->
- %% If we're missing the public key, we can create it with
- %% the private key.
- {Pub, Priv} = crypto:generate_key(eddsa, Alg, Priv),
- {ed_pub, Alg, Pub};
- {Alg, Pub} ->
- {ed_pub, Alg, Pub}
- end;
-extract_public_key(#'ECPrivateKey'{parameters = {namedCurve,OID},
- publicKey = Q}) when is_tuple(OID) ->
- {#'ECPoint'{point=Q}, {namedCurve,OID}};
-extract_public_key({ed_pri, Alg, Pub, _Priv}) ->
- {ed_pub, Alg, Pub};
-extract_public_key(#{engine:=_, key_id:=_, algorithm:=Alg} = M) ->
- case {Alg, crypto:privkey_to_pubkey(Alg, M)} of
- {rsa, [E,N]} ->
- #'RSAPublicKey'{modulus = N, publicExponent = E};
- {dss, [P,Q,G,Y]} ->
- {Y, #'Dss-Parms'{p=P, q=Q, g=G}}
- end.
-
-
verify_host_key(#ssh{algorithms=Alg}=SSH, PublicKey, Digest, {AlgStr,Signature}) ->
case atom_to_list(Alg#alg.hkey) of
@@ -1274,8 +1249,8 @@ alg_final(rcv, SSH0) ->
select_all(CL, SL) when length(CL) + length(SL) < ?MAX_NUM_ALGORITHMS ->
- %% algortihms only used by client
- %% NOTE: an algorithm occuring more than once in CL will still be present
+ %% algorithms only used by client
+ %% NOTE: an algorithm occurring more than once in CL will still be present
%% in CLonly. This is not a problem for nice clients.
CLonly = CL -- SL,
@@ -1335,9 +1310,9 @@ pack(common, rfc4253, PlainText, DeltaLenTst,
#ssh{send_sequence = SeqNum,
send_mac = MacAlg,
send_mac_key = MacKey} = Ssh0) ->
- PadLen = padding_length(4+1+size(PlainText), Ssh0),
+ PadLen = padding_length(4+1+byte_size(PlainText), Ssh0),
Pad = ssh_bits:random(PadLen),
- TextLen = 1 + size(PlainText) + PadLen + DeltaLenTst,
+ TextLen = 1 + byte_size(PlainText) + PadLen + DeltaLenTst,
PlainPkt = <<?UINT32(TextLen),?BYTE(PadLen), PlainText/binary, Pad/binary>>,
{Ssh1, CipherPkt} = encrypt(Ssh0, PlainPkt),
MAC0 = mac(MacAlg, MacKey, SeqNum, PlainPkt),
@@ -1348,9 +1323,9 @@ pack(common, enc_then_mac, PlainText, DeltaLenTst,
#ssh{send_sequence = SeqNum,
send_mac = MacAlg,
send_mac_key = MacKey} = Ssh0) ->
- PadLen = padding_length(1+size(PlainText), Ssh0),
+ PadLen = padding_length(1+byte_size(PlainText), Ssh0),
Pad = ssh_bits:random(PadLen),
- PlainLen = 1 + size(PlainText) + PadLen + DeltaLenTst,
+ PlainLen = 1 + byte_size(PlainText) + PadLen + DeltaLenTst,
PlainPkt = <<?BYTE(PadLen), PlainText/binary, Pad/binary>>,
{Ssh1, CipherPkt} = encrypt(Ssh0, PlainPkt),
EncPacketPkt = <<?UINT32(PlainLen), CipherPkt/binary>>,
@@ -1358,9 +1333,9 @@ pack(common, enc_then_mac, PlainText, DeltaLenTst,
{<<?UINT32(PlainLen), CipherPkt/binary, MAC0/binary>>, Ssh1};
pack(aead, _, PlainText, DeltaLenTst, Ssh0) ->
- PadLen = padding_length(1+size(PlainText), Ssh0),
+ PadLen = padding_length(1+byte_size(PlainText), Ssh0),
Pad = ssh_bits:random(PadLen),
- PlainLen = 1 + size(PlainText) + PadLen + DeltaLenTst,
+ PlainLen = 1 + byte_size(PlainText) + PadLen + DeltaLenTst,
PlainPkt = <<?BYTE(PadLen), PlainText/binary, Pad/binary>>,
{Ssh1, {CipherPkt,MAC0}} = encrypt(Ssh0, <<?UINT32(PlainLen),PlainPkt/binary>>),
{<<CipherPkt/binary,MAC0/binary>>, Ssh1}.
@@ -1387,7 +1362,7 @@ handle_packet_part(<<>>, Encrypted0, AEAD0, undefined, #ssh{decrypt = CryptoAlg,
end;
handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0)
- when (size(DecryptedPfx)+size(EncryptedBuffer)) < TotalNeeded ->
+ when (byte_size(DecryptedPfx)+byte_size(EncryptedBuffer)) < TotalNeeded ->
%% need more bytes to finalize the packet
{get_more, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0};
@@ -1406,7 +1381,7 @@ handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, #ssh{decryp
%%%----------------
unpack(common, rfc4253, DecryptedPfx, EncryptedBuffer, _AEAD, TotalNeeded,
#ssh{recv_mac_size = MacSize} = Ssh0) ->
- MoreNeeded = TotalNeeded - size(DecryptedPfx) - MacSize,
+ MoreNeeded = TotalNeeded - byte_size(DecryptedPfx) - MacSize,
<<EncryptedSfx:MoreNeeded/binary, Mac:MacSize/binary, NextPacketBytes/binary>> = EncryptedBuffer,
{Ssh1, DecryptedSfx} = decrypt(Ssh0, EncryptedSfx),
PlainPkt = <<DecryptedPfx/binary, DecryptedSfx/binary>>,
@@ -1423,7 +1398,7 @@ unpack(common, enc_then_mac, <<?UINT32(PlainLen)>>, EncryptedBuffer, _AEAD, _Tot
case is_valid_mac(MAC0, <<?UINT32(PlainLen),Payload/binary>>, Ssh0) of
true ->
{Ssh1, <<?BYTE(PaddingLen), PlainRest/binary>>} = decrypt(Ssh0, Payload),
- CompressedPlainTextLen = size(PlainRest) - PaddingLen,
+ CompressedPlainTextLen = byte_size(PlainRest) - PaddingLen,
<<CompressedPlainText:CompressedPlainTextLen/binary, _Padding/binary>> = PlainRest,
{ok, CompressedPlainText, NextPacketBytes, Ssh1};
false ->
@@ -1433,7 +1408,7 @@ unpack(common, enc_then_mac, <<?UINT32(PlainLen)>>, EncryptedBuffer, _AEAD, _Tot
unpack(aead, _, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded,
#ssh{recv_mac_size = MacSize} = Ssh0) ->
%% enough bytes to decode the packet.
- MoreNeeded = TotalNeeded - size(DecryptedPfx) - MacSize,
+ MoreNeeded = TotalNeeded - byte_size(DecryptedPfx) - MacSize,
<<EncryptedSfx:MoreNeeded/binary, Mac:MacSize/binary, NextPacketBytes/binary>> = EncryptedBuffer,
case decrypt(Ssh0, {AEAD,EncryptedSfx,Mac}) of
{Ssh1, error} ->
@@ -1445,7 +1420,7 @@ unpack(aead, _, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded,
%%%----------------------------------------------------------------
get_length(common, rfc4253, EncryptedBuffer, #ssh{decrypt_block_size = BlockSize} = Ssh0) ->
- case size(EncryptedBuffer) >= erlang:max(8, BlockSize) of
+ case byte_size(EncryptedBuffer) >= erlang:max(8, BlockSize) of
true ->
<<EncBlock:BlockSize/binary, EncryptedRest/binary>> = EncryptedBuffer,
{Ssh,
@@ -1465,7 +1440,7 @@ get_length(common, enc_then_mac, EncryptedBuffer, Ssh) ->
end;
get_length(aead, _, EncryptedBuffer, Ssh) ->
- case {size(EncryptedBuffer) >= 4, Ssh#ssh.decrypt} of
+ case {byte_size(EncryptedBuffer) >= 4, Ssh#ssh.decrypt} of
{true, 'chacha20-poly1305@openssh.com'} ->
<<EncryptedLen:4/binary, EncryptedRest/binary>> = EncryptedBuffer,
{Ssh1, PacketLenBin} = decrypt(Ssh, {length,EncryptedLen}),
@@ -1546,7 +1521,7 @@ do_verify(PlainText, HashAlg, Sig, {_, #'Dss-Parms'{}} = Key, _) ->
_ ->
false
end;
-do_verify(PlainText, HashAlg, Sig, {#'ECPoint'{},_} = Key, _) ->
+do_verify(PlainText, HashAlg, Sig, {#'ECPoint'{},_} = Key, _) when HashAlg =/= undefined ->
case Sig of
<<?UINT32(Rlen),R:Rlen/big-signed-integer-unit:8,
?UINT32(Slen),S:Slen/big-signed-integer-unit:8>> ->
@@ -2061,40 +2036,27 @@ valid_key_sha_alg(private, #'RSAPrivateKey'{}, 'ssh-rsa' ) -> true;
valid_key_sha_alg(public, {_, #'Dss-Parms'{}}, 'ssh-dss') -> true;
valid_key_sha_alg(private, #'DSAPrivateKey'{}, 'ssh-dss') -> true;
-valid_key_sha_alg(public, {ed_pub, ed25519,_}, 'ssh-ed25519') -> true;
-valid_key_sha_alg(private, {ed_pri, ed25519,_,_},'ssh-ed25519') -> true;
-valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}},'ssh-ed25519') when OID == ?'id-Ed25519' -> true;
-valid_key_sha_alg(public, {ed_pub, ed448,_}, 'ssh-ed448') -> true;
-valid_key_sha_alg(private, {ed_pri, ed448,_,_}, 'ssh-ed448') -> true;
-valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}},'ssh-ed448') when OID == ?'id-Ed448' -> true;
-
-valid_key_sha_alg(public, {#'ECPoint'{},{namedCurve,OID}}, Alg) when is_tuple(OID) ->
+valid_key_sha_alg(public, {#'ECPoint'{},{namedCurve,OID}}, Alg) ->
valid_key_sha_alg_ec(OID, Alg);
-valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}}, Alg) when is_tuple(OID) ->
+valid_key_sha_alg(private, #'ECPrivateKey'{parameters = {namedCurve,OID}}, Alg) ->
valid_key_sha_alg_ec(OID, Alg);
valid_key_sha_alg(_, _, _) -> false.
-
-valid_key_sha_alg_ec(OID, Alg) ->
- try
- Curve = public_key:oid2ssh_curvename(OID),
- Alg == list_to_existing_atom("ecdsa-sha2-" ++ binary_to_list(Curve))
- catch
- _:_ -> false
- end.
+
+
+valid_key_sha_alg_ec(OID, Alg) when is_tuple(OID) ->
+ {SshCurveType, _} = ssh_message:oid2ssh_curvename(OID),
+ Alg == binary_to_atom(SshCurveType);
+valid_key_sha_alg_ec(_, _) -> false.
+
-dialyzer({no_match, public_algo/1}).
public_algo(#'RSAPublicKey'{}) -> 'ssh-rsa'; % FIXME: Not right with draft-curdle-rsa-sha2
public_algo({_, #'Dss-Parms'{}}) -> 'ssh-dss';
-public_algo({ed_pub, ed25519,_}) -> 'ssh-ed25519';
-public_algo({ed_pub, ed448,_}) -> 'ssh-ed448';
public_algo({#'ECPoint'{},{namedCurve,OID}}) when is_tuple(OID) ->
- SshName = public_key:oid2ssh_curvename(OID),
- try list_to_existing_atom("ecdsa-sha2-" ++ binary_to_list(SshName))
- catch
- _:_ -> undefined
- end.
+ {SshCurveType, _} = ssh_message:oid2ssh_curvename(OID),
+ binary_to_atom(SshCurveType).
sha('ssh-rsa') -> sha;
@@ -2179,10 +2141,10 @@ parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}.
-generate_key(ecdh = Algorithm, Args) ->
- crypto:generate_key(Algorithm, Args);
-generate_key(Algorithm, Args) ->
- {Public,Private} = crypto:generate_key(Algorithm, Args),
+generate_key(ecdh, Args) ->
+ crypto:generate_key(ecdh, Args);
+generate_key(dh, [P,G,Sz2]) ->
+ {Public,Private} = crypto:generate_key(dh, [P, G, max(Sz2,?MIN_DH_KEY_SIZE)] ),
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.