aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngela Anderton Andin <[email protected]>2012-02-16 09:24:30 +0100
committerIngela Anderton Andin <[email protected]>2012-02-16 09:24:30 +0100
commit4d9dd06871d268942df763e556a0afb0bb6cf471 (patch)
tree020df21faf1409067cf8c92327ade0b7e1f856be
parent4a9cf8de2125832cdc636693ec23f625f195b9e8 (diff)
parent489fac442f15f08adf7745fb2d399cd521f0db74 (diff)
downloadotp-4d9dd06871d268942df763e556a0afb0bb6cf471.tar.gz
otp-4d9dd06871d268942df763e556a0afb0bb6cf471.tar.bz2
otp-4d9dd06871d268942df763e556a0afb0bb6cf471.zip
Merge branch 'ia/ssh/pass-phrase-protected-keys/OTP-6400' into maint
* ia/ssh/pass-phrase-protected-keys/OTP-6400: Remove unused files from test data as it is confusing Add support for key files protected by pass phrases
-rw-r--r--lib/ssh/doc/src/ssh.xml14
-rw-r--r--lib/ssh/src/ssh.erl4
-rw-r--r--lib/ssh/src/ssh_file.erl28
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl47
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub1
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_rsa27
-rw-r--r--lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub1
-rw-r--r--lib/ssh/test/ssh_test_lib.erl29
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_rsa_key.pub5
9 files changed, 125 insertions, 31 deletions
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 0f7add6d36..c205fc5dc7 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -86,7 +86,7 @@
by calling ssh_connect:session_channel/2.</p>
<p>Options are:</p>
<taglist>
- <tag><c><![CDATA[{user_dir, String}]]></c></tag>
+ <tag><c><![CDATA[{user_dir, string()}]]></c></tag>
<item>
<p>Sets the user directory e.i. the directory containing
ssh configuration files for the user such as
@@ -94,6 +94,18 @@
<c><![CDATA[authorized_key]]></c>. Defaults to the directory normally
referred to as <c><![CDATA[~/.ssh]]></c> </p>
</item>
+ <tag><c><![CDATA[{dsa_pass_phrase, string()}]]></c></tag>
+ <item>
+ <p>If the user dsa key is protected by a pass phrase it can be
+ supplied with this option.
+ </p>
+ </item>
+ <tag><c><![CDATA[{rsa_pass_phrase, string()}]]></c></tag>
+ <item>
+ <p>If the user rsa key is protected by a pass phrase it can be
+ supplied with this option.
+ </p>
+ </item>
<tag><c><![CDATA[{silently_accept_hosts, boolean()}]]></c></tag>
<item>
<p>When true hosts are added to the
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index c47db64497..5751f2eaa0 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -306,6 +306,10 @@ handle_options([{connect_timeout, _} = Opt | Rest], SockOpts, Opts) ->
handle_options(Rest, SockOpts, [Opt | Opts]);
handle_options([{user, _} = Opt | Rest], SockOpts, Opts) ->
handle_options(Rest, SockOpts, [Opt | Opts]);
+handle_options([{dsa_pass_phrase, _} = Opt | Rest], SockOpts, Opts) ->
+ handle_options(Rest, SockOpts, [Opt | Opts]);
+handle_options([{rsa_pass_phrase, _} = Opt | Rest], SockOpts, Opts) ->
+ handle_options(Rest, SockOpts, [Opt | Opts]);
handle_options([{password, _} = Opt | Rest], SockOpts, Opts) ->
handle_options(Rest, SockOpts, [Opt | Opts]);
handle_options([{user_passwords, _} = Opt | Rest], SockOpts, Opts) ->
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 8569051bee..d05fa8e09a 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -46,7 +46,10 @@
%% Used by server
host_key(Algorithm, Opts) ->
File = file_name(system, file_base_name(Algorithm), Opts),
- Password = proplists:get_value(password, Opts, ignore),
+ %% We do not expect host keys to have pass phrases
+ %% so probably we could hardcod Password = ignore, but
+ %% we keep it as an undocumented option for now.
+ Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore),
decode(File, Password).
@@ -68,9 +71,9 @@ is_host_key(Key, PeerName, Algorithm, Opts) ->
false
end.
-user_key(Alg, Opts) ->
- File = file_name(user, identity_key_filename(Alg), Opts),
- Password = proplists:get_value(password, Opts, ignore),
+user_key(Algorithm, Opts) ->
+ File = file_name(user, identity_key_filename(Algorithm), Opts),
+ Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore),
decode(File, Password).
@@ -210,10 +213,20 @@ do_lookup_host_key(Host, Alg, Opts) ->
Error -> Error
end.
-identity_key_filename("ssh-dss") -> "id_dsa";
-identity_key_filename("ssh-rsa") -> "id_rsa".
+identity_key_filename("ssh-dss") ->
+ "id_dsa";
+identity_key_filename("ssh-rsa") ->
+ "id_rsa".
+
+identity_pass_phrase("ssh-dss") ->
+ dsa_pass_phrase;
+identity_pass_phrase('ssh-dss') ->
+ dsa_pass_phrase;
+identity_pass_phrase('ssh-rsa') ->
+ rsa_pass_phrase;
+identity_pass_phrase("ssh-rsa") ->
+ rsa_pass_phrase.
-
lookup_host_key_fd(Fd, Host, KeyType) ->
case io:get_line(Fd, '') of
eof ->
@@ -290,7 +303,6 @@ is_auth_key(Key, Key) ->
is_auth_key(_,_) ->
false.
-
default_user_dir()->
{ok,[[Home|_]]} = init:get_argument(home),
UserDir = filename:join(Home, ".ssh"),
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index d69c71c842..9c13180159 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -106,12 +106,16 @@ all() ->
[app_test,
{group, dsa_key},
{group, rsa_key},
+ {group, dsa_pass_key},
+ {group, rsa_pass_key},
daemon_already_started,
server_password_option, server_userpassword_option].
groups() ->
[{dsa_key, [], [exec, exec_compressed, shell, known_hosts]},
- {rsa_key, [], [exec, exec_compressed, shell, known_hosts]}
+ {rsa_key, [], [exec, exec_compressed, shell, known_hosts]},
+ {dsa_pass_key, [], [pass_phrase]},
+ {rsa_pass_key, [], [pass_phrase]}
].
init_per_group(dsa_key, Config) ->
@@ -124,6 +128,16 @@ init_per_group(rsa_key, Config) ->
PrivDir = ?config(priv_dir, Config),
ssh_test_lib:setup_rsa(DataDir, PrivDir),
Config;
+init_per_group(rsa_pass_key, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_rsa_pass_pharse(DataDir, PrivDir, "Password"),
+ [{pass_phrase, {rsa_pass_phrase, "Password"}}| Config];
+init_per_group(dsa_pass_key, Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa_pass_pharse(DataDir, PrivDir, "Password"),
+ [{pass_phrase, {dsa_pass_phrase, "Password"}}| Config];
init_per_group(_, Config) ->
Config.
@@ -135,6 +149,14 @@ end_per_group(rsa_key, Config) ->
PrivDir = ?config(priv_dir, Config),
ssh_test_lib:clean_rsa(PrivDir),
Config;
+end_per_group(dsa_pass_key, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_dsa(PrivDir),
+ Config;
+end_per_group(rsa_pass_key, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ ssh_test_lib:clean_rsa(PrivDir),
+ Config;
end_per_group(_, Config) ->
Config.
@@ -424,6 +446,29 @@ known_hosts(Config) when is_list(Config) ->
"ssh-" ++ _ = Alg,
ssh:stop_daemon(Pid).
+pass_phrase(doc) ->
+ ["Test that we can use keyes protected by pass phrases"];
+
+pass_phrase(suite) ->
+ [];
+
+pass_phrase(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+ PhraseArg = ?config(pass_phrase, Config),
+
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ PhraseArg,
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+ {ok, _ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ssh:stop_daemon(Pid).
+
%%--------------------------------------------------------------------
%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub
deleted file mode 100644
index 9406116777..0000000000
--- a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-dss AAAAB3NzaC1kc3MAAACBAN+LZ+VJNlmh/BPjJBPQ2KRf8sY1PtQ94H9cRZ7/Gi8RgISV9pAA8WLFe8SBfCiiOZnmSJBErMszf3AE/SM8REtudld844PQ8OfDSFoyHt0PtcpUyh38SKBWAd/+oF0zYzzLPWz+tEXufVSktLKnOIqOTMKbsmhJDbNtYg92YEhfAAAAFQDID5Ka+0qtzu7B3W/A+tNQ0Y6BMQAAAIAw5DEN8HYV3yi7Pob3p/9Q7NEwj8p2/yRhgpYkgZj6lFiss/JjNR4nOfBmt44mCtzMBf6W4ecoVYnYOeTkLJ5eTrtayvukn/gwEwM4p4hLRLyqhIE3z4qunv1+AD7JLch+puQku0u7gQFoJfiYpAhfj76Tjh3hTmVzym372GUQjwAAAIEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+euEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AXCy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34= Dsa
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa
index 79968bdd7d..9d7e0dd5fb 100644
--- a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa
+++ b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa
@@ -1,16 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
-zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
-6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
-AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
-NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
-udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
-WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
-n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
-sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
-+SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
-64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
-m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
-tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
+DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
+zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
+AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
+TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
+CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
+SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
+z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
+WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
+sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
+xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
+dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
+ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
-----END RSA PRIVATE KEY-----
-
diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub
deleted file mode 100644
index 95bce6bc61..0000000000
--- a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== ingela@dain
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index d8dd4cc0ac..26bbdf5c5c 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -248,6 +248,35 @@ clean_rsa(UserDir) ->
file:delete(filename:join(UserDir,"known_hosts")),
file:delete(filename:join(UserDir,"authorized_keys")).
+setup_dsa_pass_pharse(DataDir, UserDir, Phrase) ->
+ {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_dsa")),
+ setup_pass_pharse(KeyBin, filename:join(UserDir, "id_dsa"), Phrase),
+ System = filename:join(UserDir, "system"),
+ file:make_dir(System),
+ file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")),
+ file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")),
+ setup_dsa_known_host(DataDir, UserDir),
+ setup_dsa_auth_keys(DataDir, UserDir).
+
+setup_rsa_pass_pharse(DataDir, UserDir, Phrase) ->
+ {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_rsa")),
+ setup_pass_pharse(KeyBin, filename:join(UserDir, "id_rsa"), Phrase),
+ System = filename:join(UserDir, "system"),
+ file:make_dir(System),
+ file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")),
+ file:copy(filename:join(DataDir, "ssh_host_rsa_key.pub"), filename:join(System, "ssh_host_rsa_key.pub")),
+ setup_rsa_known_host(DataDir, UserDir),
+ setup_rsa_auth_keys(DataDir, UserDir).
+
+setup_pass_pharse(KeyBin, OutFile, Phrase) ->
+ [{KeyType, _,_} = Entry0] = public_key:pem_decode(KeyBin),
+ Key = public_key:pem_entry_decode(Entry0),
+ Salt = crypto:rand_bytes(8),
+ Entry = public_key:pem_entry_encode(KeyType, Key,
+ {{"DES-CBC", Salt}, Phrase}),
+ Pem = public_key:pem_encode([Entry]),
+ file:write_file(OutFile, Pem).
+
setup_dsa_known_host(SystemDir, UserDir) ->
{ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_dsa_key.pub")),
[{Key, _}] = public_key:ssh_decode(SshBin, public_key),
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_rsa_key.pub
deleted file mode 100644
index 75d2025c71..0000000000
--- a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_rsa_key.pub
+++ /dev/null
@@ -1,5 +0,0 @@
----- BEGIN SSH2 PUBLIC KEY ----
-AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
-semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
-RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
----- END SSH2 PUBLIC KEY ----