diff options
-rw-r--r-- | lib/ssh/doc/src/ssh.xml | 14 | ||||
-rw-r--r-- | lib/ssh/src/ssh.erl | 9 | ||||
-rw-r--r-- | lib/ssh/src/ssh_transport.erl | 16 |
3 files changed, 31 insertions, 8 deletions
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index ef9f7cbd9b..6b49f89449 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -175,11 +175,21 @@ supplied with this option. </p> </item> - <tag><c><![CDATA[{silently_accept_hosts, boolean()}]]></c></tag> + <tag><c><![CDATA[{silently_accept_hosts, boolean() | accept_fun() | {crypto:digest_type(), accept_fun()} }]]></c> + <br/> + <c><![CDATA[accept_fun() :: fun(PeerName::string(), FingerPrint::string()) -> boolean()]]></c> + </tag> <item> <p>When <c>true</c>, hosts are added to the file <c><![CDATA[known_hosts]]></c> without asking the user. - Defaults to <c>false</c>. + Defaults to <c>false</c> which will give a user question on stdio of whether to accept or reject a previously + unseen host.</p> + <p>If the option value is has an <c>accept_fun()</c>, that fun will called with the arguments + <c>(PeerName, PeerHostKeyFingerPrint)</c>. The fingerprint is calculated on the Peer's Host Key with + <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-1">public_key:ssh_hostkey_fingerprint/1</seealso>. + </p> + <p>If the <c>crypto:digest_type()</c> is present, the fingerprint is calculated with that digest type by the function + <seealso marker="public_key:public_key#ssh_hostkey_fingerprint-2">public_key:ssh_hostkey_fingerprint/2</seealso>. </p> </item> <tag><c><![CDATA[{user_interaction, boolean()}]]></c></tag> diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 1d7be3547b..31e343e81b 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -617,6 +617,15 @@ handle_ssh_option({user_dir_fun, Value} = Opt) when is_function(Value) -> Opt; handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) -> Opt; +handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_function(Value,2) -> + Opt; +handle_ssh_option({silently_accept_hosts, {DigestAlg,Value}} = Opt) when is_function(Value,2) -> + case lists:member(DigestAlg, [md5, sha, sha224, sha256, sha384, sha512]) of + true -> + Opt; + false -> + throw({error, {eoptions, Opt}}) + end; handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) -> Opt; handle_ssh_option({preferred_algorithms,[_|_]} = Opt) -> diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index 15b80de30a..21ba34506a 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -734,12 +734,16 @@ public_algo({#'ECPoint'{},{namedCurve,OID}}) -> list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)). -accepted_host(Ssh, PeerName, Opts) -> +accepted_host(Ssh, PeerName, Public, Opts) -> case proplists:get_value(silently_accept_hosts, Opts, false) of + F when is_function(F,2) -> + true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(Public))); + {DigestAlg,F} when is_function(F,2) -> + true == (catch F(PeerName, public_key:ssh_hostkey_fingerprint(DigestAlg,Public))); true -> - yes; + true; false -> - yes_no(Ssh, "New host " ++ PeerName ++ " accept") + yes == yes_no(Ssh, "New host " ++ PeerName ++ " accept") end. known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh, @@ -749,10 +753,10 @@ known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh, true -> ok; false -> - case accepted_host(Ssh, PeerName, Opts) of - yes -> + case accepted_host(Ssh, PeerName, Public, Opts) of + true -> Mod:add_host_key(PeerName, Public, Opts); - no -> + false -> {error, rejected} end end. |