aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ssh/src
diff options
context:
space:
mode:
authorIngela Anderton Andin <ingela@erlang.org>2012-01-24 17:55:54 +0100
committerIngela Anderton Andin <ingela@erlang.org>2012-02-10 15:24:38 +0100
commit2916e7f2aa523411717c3ed4e275ab96cb03b6ee (patch)
tree1a41a632fbd21b415579a4c9f66da4157b5e6d5e /lib/ssh/src
parentc3fb91d203412c16d008b4c36fb13c0d776d8c46 (diff)
downloadotp-2916e7f2aa523411717c3ed4e275ab96cb03b6ee.tar.gz
otp-2916e7f2aa523411717c3ed4e275ab96cb03b6ee.tar.bz2
otp-2916e7f2aa523411717c3ed4e275ab96cb03b6ee.zip
Use the public_key application for all public key handling
Also improved test suites to avoid copying of users keys to test server directories as this is a security liability
Diffstat (limited to 'lib/ssh/src')
-rw-r--r--lib/ssh/src/Makefile6
-rw-r--r--lib/ssh/src/ssh_auth.erl87
-rw-r--r--lib/ssh/src/ssh_dsa.erl42
-rw-r--r--lib/ssh/src/ssh_file.erl600
-rw-r--r--lib/ssh/src/ssh_rsa.erl233
-rw-r--r--lib/ssh/src/ssh_transport.erl105
6 files changed, 332 insertions, 741 deletions
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index da31d87369..a49f207564 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-2012. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -101,8 +101,8 @@ INTERNAL_HRL_FILES = $(ASN_HRLS) ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-ERL_COMPILE_FLAGS += -pa$(EBIN)
-
+ERL_COMPILE_FLAGS += -pa$(EBIN)\
+ -pz $(ERL_TOP)/lib/public_key/ebin
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 9dbd95886e..a39c664c45 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,11 +21,13 @@
-module(ssh_auth).
--include("ssh.hrl").
+-include_lib("public_key/include/public_key.hrl").
+-include("ssh.hrl").
-include("ssh_auth.hrl").
-include("ssh_transport.hrl").
+
-export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1,
service_request_msg/1, init_userauth_request_msg/1,
userauth_request_msg/1, handle_userauth_request/3,
@@ -40,26 +42,29 @@ publickey_msg([Cb, #ssh{user = User,
session_id = SessionId,
service = Service,
opts = Opts} = Ssh]) ->
+
+ Alg = algorithm(Cb),
+ Hash = sha, %% Maybe option?!
ssh_bits:install_messages(userauth_pk_messages()),
- Alg = Cb:alg_name(),
+
case ssh_file:private_identity_key(Alg, Opts) of
- {ok, PrivKey} ->
- PubKeyBlob = ssh_file:encode_public_key(PrivKey),
+ {ok, Key} ->
+ PubKeyBlob = ssh_file:encode_public_key(Key),
SigData = build_sig_data(SessionId,
- User, Service, Alg, PubKeyBlob),
- Sig = Cb:sign(PrivKey, SigData),
- SigBlob = list_to_binary([?string(Alg), ?binary(Sig)]),
+ User, Service, Key, PubKeyBlob),
+ Sig = sign(SigData, Hash, Key),
+ SigBlob = list_to_binary([?string(algorithm(Key)), ?binary(Sig)]),
ssh_transport:ssh_packet(
#ssh_msg_userauth_request{user = User,
service = Service,
method = "publickey",
data = [?TRUE,
- ?string(Alg),
+ ?string(algorithm(Key)),
?binary(PubKeyBlob),
?binary(SigBlob)]},
Ssh);
- _Error ->
- not_ok
+ _Error ->
+ not_ok
end.
password_msg([#ssh{opts = Opts, io_cb = IoCb,
@@ -192,12 +197,12 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
?TRUE ->
case verify_sig(SessionId, User, "ssh-connection", Alg,
KeyBlob, SigWLen, Opts) of
- ok ->
+ true ->
{authorized, User,
ssh_transport:ssh_packet(
#ssh_msg_userauth_success{}, Ssh)};
- {error, Reason} ->
- {not_authorized, {User, {error, Reason}},
+ false ->
+ {not_authorized, {User, {error, "Invalid signature"}},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
authentications="publickey,password",
partial_success = false}, Ssh)}
@@ -312,35 +317,65 @@ get_password_option(Opts, User) ->
end.
verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) ->
- case ssh_file:lookup_user_key(User, Alg, Opts) of
+ {ok, Key} = ssh_file:decode_public_key_v2(KeyBlob, Alg),
+ case ssh_file:lookup_user_key(Key, User, Alg, Opts) of
{ok, OurKey} ->
- {ok, Key} = ssh_file:decode_public_key_v2(KeyBlob, Alg),
case OurKey of
Key ->
- NewSig = build_sig_data(SessionId,
- User, Service, Alg, KeyBlob),
+ PlainText = build_sig_data(SessionId,
+ User, Service, Key, KeyBlob),
<<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen,
<<?UINT32(AlgLen), _Alg:AlgLen/binary,
- ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig,
- M = alg_to_module(Alg),
- M:verify(OurKey, NewSig, Sig);
+ ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig,
+ verify(PlainText, sha, Sig, Key);
_ ->
{error, key_unacceptable}
end;
Error -> Error
end.
-build_sig_data(SessionId, User, Service, Alg, KeyBlob) ->
+build_sig_data(SessionId, User, Service, Key, KeyBlob) ->
Sig = [?binary(SessionId),
?SSH_MSG_USERAUTH_REQUEST,
?string(User),
?string(Service),
?binary(<<"publickey">>),
?TRUE,
- ?string(Alg),
+ ?string(algorithm(Key)),
?binary(KeyBlob)],
list_to_binary(Sig).
+algorithm(ssh_rsa) ->
+ "ssh-rsa";
+algorithm(ssh_dsa) ->
+ "ssh-dss";
+algorithm(#'RSAPrivateKey'{}) ->
+ "ssh-rsa";
+algorithm(#'DSAPrivateKey'{}) ->
+ "ssh-dss";
+algorithm({_, #'Dss-Parms'{}}) ->
+ "ssh-dss";
+algorithm(#'RSAPublicKey'{}) ->
+ "ssh-rsa".
+
+sign(SigData, Hash, #'DSAPrivateKey'{} = Key) ->
+ DerSignature = public_key:sign(SigData, Hash, Key),
+ #'Dss-Sig-Value'{r = R, s = S} = public_key:der_decode('Dss-Sig-Value', DerSignature),
+ <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>;
+sign(SigData, Hash, Key) ->
+ public_key:sign(SigData, Hash, Key).
+%% sign(SigData, _, #'DSAPrivateKey'{} = Key) ->
+%% ssh_dsa:sign(Key, SigData).
+
+verify(PlainText, Hash, Sig, {_, #'Dss-Parms'{}} = Key) ->
+ <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>> = Sig,
+ Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}),
+ public_key:verify(PlainText, Hash, Signature, Key);
+verify(PlainText, Hash, Sig, Key) ->
+ public_key:verify(PlainText, sha, Sig, Key).
+%% verify(PlainText, _Hash, Sig, {_, #'Dss-Parms'{}} = Key) ->
+%% ssh_dsa:verify(Key, PlainText, Sig).
+
decode_keyboard_interactive_prompts(NumPrompts, Data) ->
Types = lists:append(lists:duplicate(NumPrompts, [string, boolean])),
pairwise_tuplify(ssh_bits:decode(Data, Types)).
@@ -412,12 +447,8 @@ userauth_pk_messages() ->
binary]} % key blob
].
-alg_to_module("ssh-dss") ->
- ssh_dsa;
-alg_to_module("ssh-rsa") ->
- ssh_rsa.
-
other_cb(ssh_rsa) ->
ssh_dsa;
other_cb(ssh_dsa) ->
ssh_rsa.
+
diff --git a/lib/ssh/src/ssh_dsa.erl b/lib/ssh/src/ssh_dsa.erl
index cb2632beac..6650b8b99b 100644
--- a/lib/ssh/src/ssh_dsa.erl
+++ b/lib/ssh/src/ssh_dsa.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,28 +23,14 @@
-module(ssh_dsa).
--export([verify/3]).
+-export([verify/3, verify/4]).
-export([sign/2]).
-export([alg_name/0]).
-include("ssh.hrl").
+-include_lib("public_key/include/public_key.hrl").
-%% start() ->
-%% crypto:start().
-
-%% sign_file(File, Opts) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:private_host_dsa_key(user, Opts),
-%% sign(Key, Bin).
-
-%% verify_file(File, Sig) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:public_host_key(user, dsa),
-%% verify(Key, Bin, Sig).
-
-sign(_Private=#ssh_key { private={P,Q,G,X} },Mb) ->
+sign(_Private= #'DSAPrivateKey'{p = P, q = Q, g = G, x = X},Mb) ->
K = ssh_bits:irandom(160) rem Q,
R = ssh_math:ipow(G, K, P) rem Q,
Ki = ssh_math:invert(K, Q),
@@ -52,28 +38,18 @@ sign(_Private=#ssh_key { private={P,Q,G,X} },Mb) ->
S = (Ki * (M + X*R)) rem Q,
<<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>.
-
-%% the paramiko client sends a bad sig sometimes,
-%% instead of crashing, we nicely return error, the
-%% typcally manifests itself as Sb being 39 bytes
-%% instead of 40.
+verify(PlainText, sha, Sig, {Y, {_, P, Q, G}}) ->
+ verify(#ssh_key{type = dsa,
+ public = {P,Q,G,Y}}, PlainText, Sig).
verify(Public, Mb, Sb) ->
case catch xverify(Public, Mb, Sb) of
{'EXIT', _Reason} ->
- %store({Public, Mb, Sb, _Reason}),
- {error, inconsistent_key};
+ false;
ok ->
- %store({Public, Mb, Sb, ok})
- ok
+ true
end.
-%% store(Term) ->
-%% {ok, Fd} = file:open("/tmp/dsa", [append]),
-%% io:format(Fd, "~p~n~n~n", [Term]),
-%% file:close(Fd).
-
-
xverify(_Public=#ssh_key { public={P,Q,G,Y} },Mb,Sb) ->
<<R0:160/big-unsigned-integer, S0:160/big-unsigned-integer>> = Sb,
?ssh_assert(R0 >= 0 andalso R0 < Q andalso
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 12180f56bb..64dc286b92 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,21 +23,19 @@
-module(ssh_file).
--include("ssh.hrl").
--include("PKCS-1.hrl").
--include("DSS.hrl").
-
+-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/file.hrl").
+-include("ssh.hrl").
+
-export([public_host_dsa_key/2,private_host_dsa_key/2,
public_host_rsa_key/2,private_host_rsa_key/2,
public_host_key/2,private_host_key/2,
- lookup_host_key/3, add_host_key/3, % del_host_key/2,
- lookup_user_key/3, ssh_dir/2, file_name/3]).
+ lookup_host_key/3, add_host_key/3,
+ lookup_user_key/4, ssh_dir/2, file_name/3]).
-export([private_identity_key/2,
public_identity_key/2]).
-%% identity_keys/2]).
-export([encode_public_key/1, decode_public_key_v2/2]).
@@ -48,38 +46,149 @@
-define(PERM_700, 8#700).
-define(PERM_644, 8#644).
+
%% API
public_host_dsa_key(Type, Opts) ->
File = file_name(Type, "ssh_host_dsa_key.pub", Opts),
- read_public_key_v2(File, "ssh-dss").
+ decode(File, public_key).
private_host_dsa_key(Type, Opts) ->
File = file_name(Type, "ssh_host_dsa_key", Opts),
- read_private_key_v2(File, "ssh-dss").
+ Password = proplists:get_value(password, Opts, ignore),
+ decode(File, Password).
public_host_rsa_key(Type, Opts) ->
File = file_name(Type, "ssh_host_rsa_key.pub", Opts),
- read_public_key_v2(File, "ssh-rsa").
+ decode(File, public_key).
private_host_rsa_key(Type, Opts) ->
File = file_name(Type, "ssh_host_rsa_key", Opts),
- read_private_key_v2(File, "ssh-rsa").
+ Password = proplists:get_value(password, Opts, ignore),
+ decode(File, Password).
public_host_key(Type, Opts) ->
File = file_name(Type, "ssh_host_key", Opts),
- case read_private_key_v1(File,public) of
- {error, enoent} ->
- read_public_key_v1(File++".pub");
- Result ->
- Result
+ decode(File, public_key).
+
+private_host_key(Type, Opts) ->
+ File = file_name(Type, "ssh_host_key", Opts),
+ Password = proplists:get_value(password, Opts, ignore),
+ decode(File, Password).
+
+private_identity_key(Alg, Opts) ->
+ File = file_name(user, identity_key_filename(Alg), Opts),
+ Password = proplists:get_value(password, Opts, ignore),
+ decode(File, Password).
+
+public_identity_key(Alg, Opts) ->
+ File = file_name(user, identity_key_filename(Alg) ++ ".pub", Opts),
+ decode(File, public_key).
+
+encode_public_key(#'RSAPrivateKey'{publicExponent = E, modulus = N}) ->
+ ssh_bits:encode(["ssh-rsa",E,N], [string,mpint,mpint]);
+encode_public_key(#'DSAPrivateKey'{p = P, q = Q, g = G, y = Y}) ->
+ ssh_bits:encode(["ssh-dss",P,Q,G,Y], [string,mpint,mpint,mpint,mpint]).
+
+decode(File, Password) ->
+ try
+ {ok, decode_ssh_file(read_ssh_file(File), Password)}
+ catch
+ throw:Reason ->
+ {error, Reason};
+ error:Reason ->
+ {error, Reason}
+ end.
+
+read_ssh_file(File) ->
+ {ok, Bin} = file:read_file(File),
+ Bin.
+
+%% Public key
+decode_ssh_file(SshBin, public_key) ->
+ public_key:ssh_decode(SshBin, public_key);
+
+%% Private Key
+decode_ssh_file(Pem, Password) ->
+ case public_key:pem_decode(Pem) of
+ [{_, _, not_encrypted} = Entry] ->
+ public_key:pem_entry_decode(Entry);
+ [Entry] when Password =/= ignore ->
+ public_key:pem_entry_decode(Entry, Password);
+ _ ->
+ throw("No pass phrase provided for private key file")
end.
+
+
+%% lookup_host_key
+%% return {ok, Key(s)} or {error, not_found}
+%%
+
+lookup_host_key(Host, Alg, Opts) ->
+ Host1 = replace_localhost(Host),
+ do_lookup_host_key(Host1, Alg, Opts).
-private_host_key(Type, Opts) ->
- File = file_name(Type, "ssh_host_key", Opts),
- read_private_key_v1(File,private).
+add_host_key(Host, Key, Opts) ->
+ Host1 = add_ip(replace_localhost(Host)),
+ KnownHosts = file_name(user, "known_hosts", Opts),
+ case file:open(KnownHosts, [write,append]) of
+ {ok, Fd} ->
+ ok = file:change_mode(KnownHosts, ?PERM_644),
+ Res = add_key_fd(Fd, Host1, Key),
+ file:close(Fd),
+ Res;
+ Error ->
+ Error
+ end.
+
+lookup_user_key(Key, User, Alg, Opts) ->
+ SshDir = ssh_dir({remoteuser,User}, Opts),
+ case lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys", Opts) of
+ {ok, Key} ->
+ {ok, Key};
+ _ ->
+ lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys2", Opts)
+ end.
+
+
+%%
+%% Utils
+%%
+%% server use this to find individual keys for
+%% an individual user when user tries to login
+%% with publickey
+ssh_dir({remoteuser, User}, Opts) ->
+ case proplists:get_value(user_dir_fun, Opts) of
+ undefined ->
+ case proplists:get_value(user_dir, Opts) of
+ undefined ->
+ default_user_dir();
+ Dir ->
+ Dir
+ end;
+ FUN ->
+ FUN(User)
+ end;
+%% client use this to find client ssh keys
+ssh_dir(user, Opts) ->
+ case proplists:get_value(user_dir, Opts, false) of
+ false -> default_user_dir();
+ D -> D
+ end;
+
+%% server use this to find server host keys
+ssh_dir(system, Opts) ->
+ proplists:get_value(system_dir, Opts, "/etc/ssh").
+
+
+file_name(Type, Name, Opts) ->
+ FN = filename:join(ssh_dir(Type, Opts), Name),
+ %%?dbg(?DBG_PATHS, "file_name: ~p\n", [FN]),
+ FN.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% in: "host" out: "host,1.2.3.4.
add_ip(Host) ->
@@ -98,449 +207,112 @@ replace_localhost("localhost") ->
replace_localhost(Host) ->
Host.
-%% lookup_host_key
-%% return {ok, Key(s)} or {error, not_found}
-%%
-
-lookup_host_key(Host, Alg, Opts) ->
- Host1 = replace_localhost(Host),
- do_lookup_host_key(Host1, Alg, Opts).
-
do_lookup_host_key(Host, Alg, Opts) ->
- case file:open(file_name(user, "known_hosts", Opts), [read]) of
+ case file:open(file_name(user, "known_hosts", Opts), [read, binary]) of
{ok, Fd} ->
Res = lookup_host_key_fd(Fd, Host, Alg),
file:close(Fd),
- Res;
+ {ok, Res};
{error, enoent} -> {error, not_found};
Error -> Error
end.
-add_host_key(Host, Key, Opts) ->
- Host1 = add_ip(replace_localhost(Host)),
- KnownHosts = file_name(user, "known_hosts", Opts),
- case file:open(KnownHosts, [write,append]) of
- {ok, Fd} ->
- ok = file:change_mode(KnownHosts, ?PERM_644),
- Res = add_key_fd(Fd, Host1, Key),
- file:close(Fd),
- Res;
- Error ->
- Error
- end.
-
-%% del_host_key(Host, Opts) ->
-%% Host1 = replace_localhost(Host),
-%% case file:open(file_name(user, "known_hosts", Opts),[write,read]) of
-%% {ok, Fd} ->
-%% Res = del_key_fd(Fd, Host1),
-%% file:close(Fd),
-%% Res;
-%% Error ->
-%% Error
-%% end.
-
identity_key_filename("ssh-dss") -> "id_dsa";
identity_key_filename("ssh-rsa") -> "id_rsa".
-private_identity_key(Alg, Opts) ->
- Path = file_name(user, identity_key_filename(Alg), Opts),
- read_private_key_v2(Path, Alg).
-
-public_identity_key(Alg, Opts) ->
- Path = file_name(user, identity_key_filename(Alg) ++ ".pub", Opts),
- read_public_key_v2(Path, Alg).
-
-
-read_public_key_v2(File, Type) ->
- case file:read_file(File) of
- {ok,Bin} ->
- List = binary_to_list(Bin),
- case lists:prefix(Type, List) of
- true ->
- List1 = lists:nthtail(length(Type), List),
- K_S = ssh_bits:b64_decode(List1),
- decode_public_key_v2(K_S, Type);
- false ->
- {error, bad_format}
- end;
- Error ->
- Error
- end.
-
decode_public_key_v2(K_S, "ssh-rsa") ->
case ssh_bits:decode(K_S,[string,mpint,mpint]) of
["ssh-rsa", E, N] ->
- {ok, #ssh_key { type = rsa,
- public = {N,E},
- comment=""}};
+ {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}};
_ ->
{error, bad_format}
end;
-decode_public_key_v2(K_S, "ssh-dss") ->
- case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
- ["ssh-dss",P,Q,G,Y] ->
- {ok,#ssh_key { type = dsa,
- public = {P,Q,G,Y}
- }};
- _A ->
- {error, bad_format}
- end;
+decode_public_key_v2(K_S, "ssh-dss") ->
+ case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
+ ["ssh-dss",P,Q,G,Y] ->
+ {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}};
+ _A ->
+ {error, bad_format}
+ end;
decode_public_key_v2(_, _) ->
{error, bad_format}.
-
-read_public_key_v1(File) ->
- case file:read_file(File) of
- {ok,Bin} ->
- List = binary_to_list(Bin),
- case io_lib:fread("~d ~d ~d ~s", List) of
- {ok,[_Sz,E,N,Comment],_} ->
- {ok,#ssh_key { type = rsa,
- public ={N,E},
- comment = Comment }};
- _Error ->
- {error, bad_format}
- end;
- Error ->
- Error
- end.
-
-%% pem_type("ssh-dss") -> "DSA";
-%% pem_type("ssh-rsa") -> "RSA".
-
-read_private_key_v2(File, Type) ->
- case file:read_file(File) of
- {ok, PemBin} ->
- case catch (public_key:pem_decode(PemBin)) of
- [{_, Bin, not_encrypted}] ->
- decode_private_key_v2(Bin, Type);
- Error -> %% Note we do not handle password encrypted keys at the moment
- {error, Error}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-%% case file:read_file(File) of
-%% {ok,Bin} ->
-%% case read_pem(binary_to_list(Bin), pem_type(Type)) of
-%% {ok,Bin1} ->
-%% decode_private_key_v2(Bin1, Type);
-%% Error ->
-%% Error
-%% end;
-%% Error ->
-%% Error
-%% end.
-
-decode_private_key_v2(Private,"ssh-rsa") ->
- case 'PKCS-1':decode( 'RSAPrivateKey', Private) of
- {ok,RSA} -> %% FIXME Check for two-prime version
- {ok, #ssh_key { type = rsa,
- public = {RSA#'RSAPrivateKey'.modulus,
- RSA#'RSAPrivateKey'.publicExponent},
- private = {RSA#'RSAPrivateKey'.modulus,
- RSA#'RSAPrivateKey'.privateExponent}
- }};
- Error ->
- Error
- end;
-decode_private_key_v2(Private, "ssh-dss") ->
- case 'DSS':decode('DSAPrivateKey', Private) of
- {ok,DSA} -> %% FIXME Check for two-prime version
- {ok, #ssh_key { type = dsa,
- public = {DSA#'DSAPrivateKey'.p,
- DSA#'DSAPrivateKey'.q,
- DSA#'DSAPrivateKey'.g,
- DSA#'DSAPrivateKey'.y},
- private= {DSA#'DSAPrivateKey'.p,
- DSA#'DSAPrivateKey'.q,
- DSA#'DSAPrivateKey'.g,
- DSA#'DSAPrivateKey'.x}
- }};
- _ ->
- {error,bad_format}
- end.
-
-%% SSH1 private key format
-%% <<"SSH PRIVATE KEY FILE FORMATE 1.1\n" 0:8
-%% CipherNum:8, Reserved:32,
-%% NSz/uint32, N/bignum, E/bignum, Comment/string,
-%%
-%% [ R0:8 R1:8 R0:8 R1:8, D/bignum, IQMP/bignum, Q/bignum, P/bignum, Pad(8)]>>
-%%
-%% where [ ] is encrypted using des3 (ssh1 version) and
-%% a posssibly empty pass phrase using md5(passphase) as key
-%%
-
-read_private_key_v1(File, Type) ->
- case file:read_file(File) of
- {ok,<<"SSH PRIVATE KEY FILE FORMAT 1.1\n",0,
- CipherNum,_Resereved:32,Bin/binary>>} ->
- decode_private_key_v1(Bin, CipherNum,Type);
- {ok,_} ->
- {error, bad_format};
- Error ->
- Error
- end.
-
-decode_private_key_v1(Bin, CipherNum, Type) ->
- case ssh_bits:decode(Bin,0,[uint32, bignum, bignum, string]) of
- {Offset,[_NSz,N,E,Comment]} ->
- if Type == public ->
- {ok,#ssh_key { type=rsa,
- public={N,E},
- comment=Comment}};
- Type == private ->
- <<_:Offset/binary, Encrypted/binary>> = Bin,
- case ssh_bits:decode(decrypt1(Encrypted, CipherNum),0,
- [uint32, bignum, bignum,
- bignum, bignum,{pad,8}]) of
- {_,[_,D,IQMP,Q,P]} ->
- {ok,#ssh_key { type=rsa,
- public={N,E},
- private={D,IQMP,Q,P},
- comment=Comment}};
- _ ->
- {error,bad_format}
- end
- end;
- _ ->
- {error,bad_format}
- end.
-
-
-decrypt1(Bin, CipherNum) ->
- decrypt1(Bin, CipherNum,"").
-
-decrypt1(Bin, CipherNum, Phrase) ->
- if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" ->
- Bin;
- CipherNum == ?SSH_CIPHER_3DES ->
- <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase),
- K3 = K1,
- IV = <<0,0,0,0,0,0,0,0>>,
- Bin1 = crypto:des_cbc_decrypt(K3,IV,Bin),
- Bin2 = crypto:des_cbc_encrypt(K2,IV,Bin1),
- crypto:des_cbc_decrypt(K1,IV,Bin2)
- end.
-
-%% encrypt1(Bin, CipherNum) ->
-%% encrypt1(Bin, CipherNum,"").
-
-%% encrypt1(Bin, CipherNum, Phrase) ->
-%% if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" ->
-%% Bin;
-%% CipherNum == ?SSH_CIPHER_3DES ->
-%% <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase),
-%% K3 = K1,
-%% IV = <<0,0,0,0,0,0,0,0>>,
-%% Bin1 = crypto:des_cbc_encrypt(K1,IV,Bin),
-%% Bin2 = crypto:des_cbc_decrypt(K2,IV,Bin1),
-%% crypto:des_cbc_encrypt(K3,IV,Bin2)
-%% end.
-
-lookup_host_key_fd(Fd, Host, Alg) ->
+lookup_host_key_fd(Fd, Host, KeyType) ->
case io:get_line(Fd, '') of
eof ->
{error, not_found};
Line ->
- case string:tokens(Line, " ") of
- [HostList, Alg, KeyData] ->
-%% io:format(" ~p lookup_host_key_fd: HostList ~p Alg ~p KeyData ~p\n",
-%% [Host, HostList, Alg, KeyData]),
- case lists:member(Host, string:tokens(HostList, ",")) of
- true ->
- decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg);
- false ->
- lookup_host_key_fd(Fd, Host, Alg)
- end;
- _ ->
- lookup_host_key_fd(Fd, Host, Alg)
+ case public_key:ssh_decode(Line, known_hosts) of
+ [{Key, Attributes}] ->
+ handle_host(Fd, Host, proplists:get_value(hostnames, Attributes), Key, KeyType);
+ [] ->
+ lookup_host_key_fd(Fd, Host, KeyType)
end
end.
-
-
-%% del_key_fd(Fd, Host) ->
-%% del_key_fd(Fd, Host, 0, 0).
-
-%% del_key_fd(Fd, Host, ReadPos0, WritePos0) ->
-%% case io:get_line(Fd, '') of
-%% eof ->
-%% if ReadPos0 == WritePos0 ->
-%% ok;
-%% true ->
-%% file:truncate(Fd)
-%% end;
-%% Line ->
-%% {ok,ReadPos1} = file:position(Fd, cur),
-%% case string:tokens(Line, " ") of
-%% [HostList, _Type, _KeyData] ->
-%% case lists:member(Host, string:tokens(HostList, ",")) of
-%% true ->
-%% del_key_fd(Fd, Host, ReadPos1, WritePos0);
-%% false ->
-%% if ReadPos0 == WritePos0 ->
-%% del_key_fd(Fd, Host, ReadPos1, ReadPos1);
-%% true ->
-%% file:position(Fd, WritePos0),
-%% file:write(Fd, Line),
-%% {ok,WritePos1} = file:position(Fd,cur),
-%% del_key_fd(Fd, Host, ReadPos1, WritePos1)
-%% end
-%% end;
-%% _ ->
-%% if ReadPos0 == WritePos0 ->
-%% del_key_fd(Fd, Host, ReadPos1, ReadPos1);
-%% true ->
-%% file:position(Fd, WritePos0),
-%% file:write(Fd, Line),
-%% {ok,WritePos1} = file:position(Fd,cur),
-%% del_key_fd(Fd, Host, ReadPos1, WritePos1)
-%% end
-%% end
-%% end.
-
-
-add_key_fd(Fd, Host, Key) ->
- case Key#ssh_key.type of
- rsa ->
- {N,E} = Key#ssh_key.public,
- DK = ssh_bits:b64_encode(
- ssh_bits:encode(["ssh-rsa",E,N],
- [string,mpint,mpint])),
- file:write(Fd, [Host, " ssh-rsa ", DK, "\n"]);
- dsa ->
- {P,Q,G,Y} = Key#ssh_key.public,
- DK = ssh_bits:b64_encode(
- ssh_bits:encode(["ssh-dss",P,Q,G,Y],
- [string,mpint,mpint,mpint,mpint])),
- file:write(Fd, [Host, " ssh-dss ", DK, "\n"])
+handle_host(Fd, Host, HostList, Key, KeyType) ->
+ Host1 = host_name(Host),
+ case lists:member(Host1, HostList) and key_match(Key, KeyType) of
+ true ->
+ Key;
+ false ->
+ lookup_host_key_fd(Fd, Host, KeyType)
end.
+host_name(Atom) when is_atom(Atom) ->
+ atom_to_list(Atom);
+host_name(List) ->
+ List.
-%% read_pem(Cs, Type) ->
-%% case read_line(Cs) of
-%% {"-----BEGIN "++Rest,Cs1} ->
-%% case string:tokens(Rest, " ") of
-%% [Type, "PRIVATE", "KEY-----"] ->
-%% read_pem64(Cs1, [], Type);
-%% _ ->
-%% {error, bad_format}
-%% end;
-%% {"",Cs1} when Cs1 =/= "" ->
-%% read_pem(Cs1,Type);
-%% {_,""} ->
-%% {error, bad_format}
-%% end.
-
-%% read_pem64(Cs, Acc, Type) ->
-%% case read_line(Cs) of
-%% {"-----END "++Rest,_Cs1} ->
-%% case string:tokens(Rest, " ") of
-%% [Type, "PRIVATE", "KEY-----"] ->
-%% {ok,ssh_bits:b64_decode(append(reverse(Acc)))};
-%% Toks ->
-%% error_logger:format("ssh: TOKENS=~p\n", [Toks]),
-%% {error, bad_format}
-%% end;
-%% {B64, Cs1} when Cs1 =/= "" ->
-%% read_pem64(Cs1, [B64|Acc], Type);
-%% _What ->
-%% {error, bad_format}
-%% end.
-
-
-%% read_line(Cs) -> read_line(Cs,[]).
-%% read_line([$\r,$\n|T], Acc) -> {reverse(Acc), T};
-%% read_line([$\n|T], Acc) -> {reverse(Acc), T};
-%% read_line([C|T], Acc) -> read_line(T,[C|Acc]);
-%% read_line([], Acc) -> {reverse(Acc),[]}.
-
-lookup_user_key(User, Alg, Opts) ->
- SshDir = ssh_dir({remoteuser,User}, Opts),
- case lookup_user_key_f(User, SshDir, Alg, "authorized_keys", Opts) of
- {ok, Key} ->
- {ok, Key};
- _ ->
- lookup_user_key_f(User, SshDir, Alg, "authorized_keys2", Opts)
- end.
+key_match(#'RSAPublicKey'{}, "ssh-rsa") ->
+ true;
+key_match({_, #'Dss-Parms'{}}, "ssh-dss") ->
+ true;
+key_match(_, _) ->
+ false.
+
+add_key_fd(Fd, Host,Key) ->
+ SshBin = public_key:ssh_encode([{Key, [{hostnames, [Host]}]}], known_hosts),
+ file:write(Fd, SshBin).
-lookup_user_key_f(_User, [], _Alg, _F, _Opts) ->
+lookup_user_key_f(_, _User, [], _Alg, _F, _Opts) ->
{error, nouserdir};
-lookup_user_key_f(_User, nouserdir, _Alg, _F, _Opts) ->
+lookup_user_key_f(_, _User, nouserdir, _Alg, _F, _Opts) ->
{error, nouserdir};
-lookup_user_key_f(_User, Dir, Alg, F, _Opts) ->
+lookup_user_key_f(Key, _User, Dir, _Alg, F, _Opts) ->
FileName = filename:join(Dir, F),
- case file:open(FileName, [read]) of
+ case file:open(FileName, [read, binary]) of
{ok, Fd} ->
- Res = lookup_user_key_fd(Fd, Alg),
+ Res = lookup_user_key_fd(Fd, Key),
file:close(Fd),
Res;
{error, Reason} ->
{error, {{openerr, Reason}, {file, FileName}}}
end.
-lookup_user_key_fd(Fd, Alg) ->
+lookup_user_key_fd(Fd, Key) ->
case io:get_line(Fd, '') of
eof ->
{error, not_found};
Line ->
- case string:tokens(Line, " ") of
- [Alg, KeyData, _] ->
- %% io:format("lookup_user_key_fd: HostList ~p Alg ~p KeyData ~p\n",
- %% [HostList, Alg, KeyData]),
- decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg);
- _Other ->
- %%?dbg(false, "key_fd Other: ~w ~w\n", [Alg, _Other]),
- lookup_user_key_fd(Fd, Alg)
+ case public_key:ssh_decode(Line, auth_keys) of
+ [{AuthKey, _}] ->
+ case is_auth_key(Key, AuthKey) of
+ true ->
+ {ok, Key};
+ false ->
+ lookup_user_key_fd(Fd, Key)
+ end;
+ [] ->
+ lookup_user_key_fd(Fd, Key)
end
end.
+is_auth_key(Key, Key) ->
+ true;
+is_auth_key(_,_) ->
+ false.
-encode_public_key(#ssh_key{type = rsa, public = {N, E}}) ->
- ssh_bits:encode(["ssh-rsa",E,N],
- [string,mpint,mpint]);
-encode_public_key(#ssh_key{type = dsa, public = {P,Q,G,Y}}) ->
- ssh_bits:encode(["ssh-dss",P,Q,G,Y],
- [string,mpint,mpint,mpint,mpint]).
-
-%%
-%% Utils
-%%
-
-%% server use this to find individual keys for
-%% an individual user when user tries to login
-%% with publickey
-ssh_dir({remoteuser, User}, Opts) ->
- case proplists:get_value(user_dir_fun, Opts) of
- undefined ->
- case proplists:get_value(user_dir, Opts) of
- undefined ->
- default_user_dir();
- Dir ->
- Dir
- end;
- FUN ->
- FUN(User)
- end;
-
-%% client use this to find client ssh keys
-ssh_dir(user, Opts) ->
- case proplists:get_value(user_dir, Opts, false) of
- false -> default_user_dir();
- D -> D
- end;
-
-%% server use this to find server host keys
-ssh_dir(system, Opts) ->
- proplists:get_value(system_dir, Opts, "/etc/ssh").
-
-file_name(Type, Name, Opts) ->
- FN = filename:join(ssh_dir(Type, Opts), Name),
- %%?dbg(?DBG_PATHS, "file_name: ~p\n", [FN]),
- FN.
default_user_dir()->
{ok,[[Home|_]]} = init:get_argument(home),
diff --git a/lib/ssh/src/ssh_rsa.erl b/lib/ssh/src/ssh_rsa.erl
index 77c411b09f..03c55319b7 100644
--- a/lib/ssh/src/ssh_rsa.erl
+++ b/lib/ssh/src/ssh_rsa.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,40 +23,23 @@
-module(ssh_rsa).
+-include_lib("public_key/include/public_key.hrl").
+
-export([verify/3, sign/2]).
-export([alg_name/0]).
-include("ssh.hrl").
--include("PKCS-1.hrl").
-
-define(MGF(Seed,Len), mgf1((Seed),(Len))).
-define(HASH(X), crypto:sha((X))).
-define(HLen, 20).
-%% start() ->
-%% crypto:start().
-
-%% sign_file(File) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:private_host_rsa_key(user),
-%% sign(Key, Bin).
-
-%% verify_file(File, Sig) ->
-%% start(),
-%% {ok,Bin} = file:read_file(File),
-%% {ok,Key} = ssh_file:public_host_rsa_key(user),
-%% verify(Key, Bin, Sig).
-
sign(Private,Mb) ->
rsassa_pkcs1_v1_5_sign(Private,Mb).
verify(Public,Mb,Sb) ->
rsassa_pkcs1_v1_5_verify(Public,Mb,Sb).
-
-
%% Integer to octet string
i2osp(X, XLen) ->
ssh_bits:i2bin(X, XLen).
@@ -65,125 +48,23 @@ i2osp(X, XLen) ->
os2ip(X) ->
ssh_bits:bin2i(X).
-%% decrypt1, M = message representative
-%% rsaep(#ssh_key { public={N,E}}, M) ->
-%% ?ssh_assert(M >= 0 andalso M =< N-1, out_of_range),
-%% ssh_math:ipow(M, E, N).
-
-%% encrypt1, C = cipher representative
-%% rsadp(#ssh_key { public={N,_}, private={_,D}}, C) ->
-%% ?ssh_assert(C >= 0 andalso C =< N-1, out_of_range),
-%% ssh_math:ipow(C, D, N).
-
%% sign1, M = message representative
-rsasp1(#ssh_key { public={N,_}, private={_,D}}, M) ->
+rsasp1(#'RSAPrivateKey'{modulus = N, privateExponent = D}, M) ->
?ssh_assert((M >= 0 andalso M =< N-1), out_of_range),
ssh_math:ipow(M, D, N).
%% verify1, S =signature representative
-rsavp1(#ssh_key { public={N,E}}, S) ->
+rsavp1(#'RSAPublicKey'{publicExponent = E, modulus = N}, S) ->
?ssh_assert(S >= 0 andalso S =< N-1, out_of_range),
ssh_math:ipow(S, E, N).
-%% M messaage
-%% rsaes_oaep_encrypt(Public, M) ->
-%% rsaes_oaep_encrypt(Public, M, <<>>).
-
-%% rsaes_oaep_encrypt(Public=#ssh_key { public={N,_E}}, M, L) ->
-%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long),
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% MLen = size(M),
-%% %% LLen = size(L),
-%% ?ssh_assert(MLen =< K - 2*?HLen - 2, message_to_long),
-%% LHash = ?HASH(L),
-%% PS = ssh_bits:fill_bits(K - MLen - 2*?HLen - 2, 0),
-%% DB = <<LHash/binary, PS/binary, 16#01, M/binary>>,
-%% Seed = ssh_bits:random(?HLen),
-%% DbMask = ?MGF(Seed, K - ?HLen - 1),
-%% MaskedDB = ssh_bits:xor_bits(DB, DbMask),
-%% SeedMask = ?MGF(MaskedDB, ?HLen),
-%% MaskedSeed = ssh_bits:xor_bits(Seed, SeedMask),
-%% EM = <<16#00, MaskedSeed/binary, MaskedDB/binary>>,
-%% Mc = os2ip(EM),
-%% C = rsaep(Public, Mc),
-%% i2osp(C, K).
-
-%% rsaes_oaep_decrypt(Key, C) ->
-%% rsaes_oaep_decrypt(Key, C, <<>>).
-
-%% rsaes_oaep_decrypt(Private=#ssh_key { public={N,_},private={_,_}},Cb,L) ->
-%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long),
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% ?ssh_assert(K == 2*?HLen + 2, decryption_error),
-%% C = os2ip(Cb),
-%% M = rsadp(Private, C),
-%% EM = i2osp(M, K),
-%% LHash = ?HASH(L),
-%% MLen = K - ?HLen -1,
-%% case EM of
-%% <<16#00, MaskedSeed:?HLen/binary, MaskedDB:MLen>> ->
-%% SeedMask = ?MGF(MaskedDB, ?HLen),
-%% Seed = ssh_bits:xor_bits(MaskedSeed, SeedMask),
-%% DbMask = ?MGF(Seed, K - ?HLen - 1),
-%% DB = ssh_bits:xor_bits(MaskedDB, DbMask),
-%% PSLen = K - MLen - 2*?HLen - 2,
-%% case DB of
-%% <<LHash:?HLen, _PS:PSLen/binary, 16#01, M/binary>> ->
-%% M;
-%% _ ->
-%% exit(decryption_error)
-%% end;
-%% _ ->
-%% exit(decryption_error)
-%% end.
-
-
-%% rsaes_pkcs1_v1_5_encrypt(Public=#ssh_key { public={N,_}}, M) ->
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% MLen = size(M),
-%% ?ssh_assert(MLen =< K - 11, message_to_long),
-%% PS = ssh_bits:random(K - MLen - 3),
-%% EM = <<16#00,16#02,PS/binary,16#00,M/binary>>,
-%% Mc = os2ip(EM),
-%% C = rsaep(Public, Mc),
-%% i2osp(C, K).
-
-
-%% rsaes_pkcs1_v1_5_decrypt(Private=#ssh_key { public={N,_},private={_,_}},
-%% Cb) ->
-%% K = (ssh_bits:isize(N)+7) div 8,
-%% CLen = size(Cb),
-%% ?ssh_assert(CLen == K andalso K >= 11, decryption_error),
-%% C = os2ip(Cb),
-%% M = rsadp(Private, C),
-%% EM = i2osp(M, K),
-%% PSLen = K - CLen - 3,
-%% case EM of
-%% <<16#00, 16#02, _PS:PSLen/binary, 16#00, M>> ->
-%% M;
-%% _ ->
-%% exit(decryption_error)
-%% end.
-
-%% rsassa_pss_sign(Private=#ssh_key { public={N,_},private={_,_}},Mb) ->
-%% ModBits = ssh_bits:isize(N),
-%% K = (ModBits+7) div 8,
-%% EM = emsa_pss_encode(Mb, ModBits - 1),
-%% M = os2ip(EM),
-%% S = rsasp1(Private, M),
-%% i2osp(S, K).
-
-%% rsassa_pss_verify(Public=#ssh_key { public={N,_E}},Mb,Sb) ->
-%% ModBits = ssh_bits:isize(N),
-%% K = (ModBits+7) div 8,
-%% ?ssh_assert(size(Sb) == K, invalid_signature),
-%% S = os2ip(Sb),
-%% M = rsavp1(Public,S),
-%% EMLen = (ModBits-1+7) div 8,
-%% EM = i2osp(M, EMLen),
-%% emsa_pss_verify(Mb, EM, ModBits-1).
-
+rsassa_pkcs1_v1_5_sign(#'RSAPrivateKey'{modulus = N} = Private, Mb) ->
+ K = (ssh_bits:isize(N)+7) div 8,
+ EM = emsa_pkcs1_v1_5_encode(Mb, K),
+ M = os2ip(EM),
+ S = rsasp1(Private, M),
+ i2osp(S, K);
rsassa_pkcs1_v1_5_sign(Private=#ssh_key { public={N,_},private={_,_D}},Mb) ->
K = (ssh_bits:isize(N)+7) div 8,
@@ -192,7 +73,7 @@ rsassa_pkcs1_v1_5_sign(Private=#ssh_key { public={N,_},private={_,_D}},Mb) ->
S = rsasp1(Private, M),
i2osp(S, K).
-rsassa_pkcs1_v1_5_verify(Public=#ssh_key { public={N,_E}}, Mb, Sb) ->
+rsassa_pkcs1_v1_5_verify(#'RSAPublicKey'{modulus = N} = Public, Mb, Sb) ->
K = (ssh_bits:isize(N)+7) div 8,
?ssh_assert(size(Sb) == K, invalid_signature),
S = os2ip(Sb),
@@ -200,9 +81,9 @@ rsassa_pkcs1_v1_5_verify(Public=#ssh_key { public={N,_E}}, Mb, Sb) ->
EM = i2osp(M, K),
%?dbg(true, "verify K=~p S=~w ~n#M=~w~n#EM=~w~n", [K, S, M, EM]),
case emsa_pkcs1_v1_5_encode(Mb, K) of
- EM -> ok;
- _S ->
- {error, invalid_signature}
+ EM -> true;
+ _S -> false
+ %%{error, invalid_signature}
end.
@@ -211,87 +92,13 @@ emsa_pkcs1_v1_5_encode(M, EMLen) ->
%% Must use speical xxNull types here!
Alg = #'AlgorithmNull' { algorithm = ?'id-sha1',
parameters = <<>> },
- {ok,TCode} = 'PKCS-1':encode('DigestInfoNull',
- #'DigestInfoNull'{ digestAlgorithm = Alg,
- digest = H }),
- T = list_to_binary(TCode),
- TLen = size(T),
+ TCode = public_key:der_encode('DigestInfoNull',
+ #'DigestInfoNull'{ digestAlgorithm = Alg,
+ digest = H }),
+ TLen = size(TCode),
?ssh_assert(EMLen >= TLen + 11, message_to_short),
PS = ssh_bits:fill_bits(EMLen - TLen - 3, 16#ff),
- <<16#00, 16#01, PS/binary, 16#00, T/binary>>.
-
-
-%% emsa_pss_encode(M, EMBits) ->
-%% emsa_pss_encode(M, EMBits, 0).
-
-%% emsa_pss_encode(M, EMBits, SLen) ->
-%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long),
-%% EMLen = (EMBits + 7) div 8,
-%% MHash = ?HASH(M),
-%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, encoding_error),
-%% Salt = ssh_bits:random(SLen),
-%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
-%% MHash, Salt],
-%% H = ?HASH(M1),
-%% PS = ssh_bits:fill_bits(EMLen-SLen-?HLen-2, 0),
-%% DB = <<PS/binary, 16#01, Salt/binary>>,
-%% DbMask = ?MGF(H, EMLen - ?HLen -1),
-%% MaskedDB = ssh_bits:xor_bits(DB, DbMask),
-%% ZLen = 8*EMLen - EMBits,
-%% NZLen = (8 - (ZLen rem 8)) rem 8,
-%% <<_:ZLen, NZ:NZLen, MaskedDB1/binary>> = MaskedDB,
-%% MaskedDB2 = <<0:ZLen, NZ:NZLen, MaskedDB1/binary>>,
-%% <<MaskedDB2/binary, H/binary, 16#BC>>.
-
-
-%% emsa_pss_verify(M, EM, EMBits) ->
-%% emsa_pss_verify(M, EM, EMBits, 0).
-
-%% emsa_pss_verify(M, EM, EMBits, SLen) ->
-%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long),
-%% EMLen = (EMBits + 7) div 8,
-%% MHash = ?HASH(M),
-%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, inconsistent),
-%% MaskLen = (EMLen - ?HLen - 1)-1,
-%% ZLen = 8*EMLen - EMBits,
-%% NZLen = (8 - (ZLen rem 8)) rem 8,
-%% case EM of
-%% <<0:ZLen,Nz:NZLen,MaskedDB1:MaskLen/binary, H:?HLen/binary, 16#BC>> ->
-%% MaskedDB = <<0:ZLen,Nz:NZLen,MaskedDB1/binary>>,
-%% DbMask = ?MGF(H, EMLen - ?HLen - 1),
-%% DB = ssh_bits:xor_bits(MaskedDB, DbMask),
-%% PSLen1 = (EMLen - SLen - ?HLen - 2) - 1,
-%% PS = ssh_bits:fill_bits(PSLen1, 0),
-%% case DB of
-%% <<_:ZLen,0:NZLen,PS:PSLen1/binary,16#01,Salt:SLen/binary>> ->
-%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
-%% MHash, Salt],
-%% case ?HASH(M1) of
-%% H -> ok;
-%% _ -> exit(inconsistent)
-%% end;
-%% _ ->
-%% exit(inconsistent)
-%% end;
-%% _ ->
-%% exit(inconsistent)
-%% end.
-
-
-
-%% Mask generating function MGF1
-%% mgf1(MGFSeed, MaskLen) ->
-%% T = mgf1_loop(0, ((MaskLen + ?HLen -1) div ?HLen) - 1, MGFSeed, ""),
-%% <<R:MaskLen/binary, _/binary>> = T,
-%% R.
-
-%% mgf1_loop(Counter, N, _, T) when Counter > N ->
-%% list_to_binary(T);
-%% mgf1_loop(Counter, N, MGFSeed, T) ->
-%% C = i2osp(Counter, 4),
-%% mgf1_loop(Counter+1, N, MGFSeed, [T, ?HASH([MGFSeed, C])]).
-
-
+ <<16#00, 16#01, PS/binary, 16#00, TCode/binary>>.
alg_name() ->
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index de3e29e2f1..f610c71efa 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,10 +23,11 @@
-module(ssh_transport).
--include("ssh_transport.hrl").
+-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/inet.hrl").
+-include("ssh_transport.hrl").
-include("ssh.hrl").
--include_lib("kernel/include/inet.hrl").
-export([connect/5, accept/4]).
-export([versions/2, hello_version_msg/1]).
@@ -331,6 +332,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) ->
}, Ssh0),
%%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]),
%%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]),
+ %%Hash = crypto:sha(PlainText),
{ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}},
shared_secret = K,
exchanged_hash = H,
@@ -364,6 +366,7 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey, f = F,
H = kex_h(Ssh0, HostKey, Public, F, K),
%%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]),
%%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]),
+ %%Hash = crypto:sha(PlainText),
case verify_host_key(Ssh0, HostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -427,8 +430,8 @@ get_host_key(SSH) ->
case ALG#alg.hkey of
'ssh-rsa' ->
case Mod:private_host_rsa_key(Scope, Opts) of
- {ok,Key=#ssh_key { public={N,E}} } ->
- %%?dbg(true, "x~n", []),
+ {ok, #'RSAPrivateKey'{modulus = N, publicExponent = E} = Key} ->
+ %%?dbg(true, "x~n", []),
{Key,
ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])};
Error ->
@@ -437,7 +440,7 @@ get_host_key(SSH) ->
end;
'ssh-dss' ->
case Mod:private_host_dsa_key(Scope, Opts) of
- {ok,Key=#ssh_key { public={P,Q,G,Y}}} ->
+ {ok, #'DSAPrivateKey'{y = Y, p = P, q = Q, g = G} = Key} ->
{Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y],
[string,mpint,mpint,mpint,mpint])};
Error ->
@@ -447,59 +450,60 @@ get_host_key(SSH) ->
exit({error, bad_key_type})
end.
-sign_host_key(Ssh, Private, H) ->
- ALG = Ssh#ssh.algorithms,
- Module = case ALG#alg.hkey of
- 'ssh-rsa' ->
- ssh_rsa;
- 'ssh-dss' ->
- ssh_dsa
- end,
- case catch Module:sign(Private, H) of
- {'EXIT', Reason} ->
- error_logger:format("SIGN FAILED: ~p\n", [Reason]),
- {error, Reason};
- SIG ->
- ssh_bits:encode([Module:alg_name() ,SIG],[string,binary])
- end.
+sign_host_key(_Ssh, #'RSAPrivateKey'{} = Private, H) ->
+ Hash = sha, %% Option ?!
+ Signature = public_key:sign(H, Hash, Private),
+ ssh_bits:encode(["ssh-rsa", Signature],[string, binary]);
+sign_host_key(_Ssh, #'DSAPrivateKey'{} = Private, H) ->
+ Hash = sha, %% Option ?!
+ DerSignature = public_key:sign(H, Hash, Private),
+ #'Dss-Sig-Value'{r = R, s = S} = public_key:der_decode('Dss-Sig-Value', DerSignature),
+ RawSignature = <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>,
+ ssh_bits:encode(["ssh-dss", RawSignature],[string, binary]).
verify_host_key(SSH, K_S, H, H_SIG) ->
ALG = SSH#ssh.algorithms,
case ALG#alg.hkey of
'ssh-rsa' ->
- case ssh_bits:decode(K_S,[string,mpint,mpint]) of
- ["ssh-rsa", E, N] ->
- ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
- Public = #ssh_key { type=rsa, public={N,E} },
- case catch ssh_rsa:verify(Public, H, SIG) of
- {'EXIT', Reason} ->
- error_logger:format("VERIFY FAILED: ~p\n", [Reason]),
- {error, bad_signature};
- ok ->
- known_host_key(SSH, Public, "ssh-rsa")
- end;
- _ ->
- {error, bad_format}
- end;
+ verify_host_key_rsa(SSH, K_S, H, H_SIG);
'ssh-dss' ->
- case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
- ["ssh-dss",P,Q,G,Y] ->
- ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
- Public = #ssh_key { type=dsa, public={P,Q,G,Y} },
- case catch ssh_dsa:verify(Public, H, SIG) of
- {'EXIT', Reason} ->
- error_logger:format("VERIFY FAILED: ~p\n", [Reason]),
- {error, bad_signature};
- ok ->
- known_host_key(SSH, Public, "ssh-dss")
- end;
- _ ->
- {error, bad_host_key_format}
- end;
+ verify_host_key_dss(SSH, K_S, H, H_SIG);
_ ->
{error, bad_host_key_algorithm}
end.
+verify_host_key_rsa(SSH, K_S, H, H_SIG) ->
+ case ssh_bits:decode(K_S,[string,mpint,mpint]) of
+ ["ssh-rsa", E, N] ->
+ ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
+ Public = #'RSAPublicKey'{publicExponent = E, modulus = N},
+ case public_key:verify(H, sha, SIG, Public) of
+ false ->
+ {error, bad_signature};
+ true ->
+ known_host_key(SSH, Public, "ssh-rsa")
+ end;
+ _ ->
+ {error, bad_format}
+ end.
+
+verify_host_key_dss(SSH, K_S, H, H_SIG) ->
+ case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
+ ["ssh-dss",P,Q,G,Y] ->
+ ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
+ Public = {Y, #'Dss-Parms'{p = P, q = Q, g = G}},
+ <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>> = SIG,
+ Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}),
+ case public_key:verify(H, sha, Signature, Public) of
+ false ->
+ {error, bad_signature};
+ true ->
+ known_host_key(SSH, Public, "ssh-dss")
+ end;
+ _ ->
+ {error, bad_host_key_format}
+ end.
+
accepted_host(Ssh, PeerName, Opts) ->
case proplists:get_value(silently_accept_hosts, Opts, false) of
true ->
@@ -1055,6 +1059,7 @@ kex_h(SSH, K_S, E, F, K) ->
[string,string,binary,binary,binary,
mpint,mpint,mpint]),
crypto:sha(L).
+
kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
L = if Min==-1; Max==-1 ->
@@ -1075,7 +1080,7 @@ kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
Prime, Gen, E,F,K], Ts)
end,
crypto:sha(L).
-
+
mac_key_size('hmac-sha1') -> 20*8;
mac_key_size('hmac-sha1-96') -> 20*8;
mac_key_size('hmac-md5') -> 16*8;