From 2916e7f2aa523411717c3ed4e275ab96cb03b6ee Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 24 Jan 2012 17:55:54 +0100 Subject: 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 --- lib/ssh/src/ssh_auth.erl | 87 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 28 deletions(-) (limited to 'lib/ssh/src/ssh_auth.erl') 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), <> = SigWLen, <> = 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), + <>; +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) -> + <> = 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. + -- cgit v1.2.3 From 8d20de278b3ef69ea470bfb35e5999750214e3a1 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Tue, 31 Jan 2012 16:12:30 +0100 Subject: Removed no longer needed code --- lib/ssh/src/ssh_auth.erl | 65 ++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 41 deletions(-) (limited to 'lib/ssh/src/ssh_auth.erl') diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index a39c664c45..3b087262d8 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -27,7 +27,6 @@ -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, @@ -38,12 +37,11 @@ %%-------------------------------------------------------------------- %%% Internal application API %%-------------------------------------------------------------------- -publickey_msg([Cb, #ssh{user = User, +publickey_msg([Alg, #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()), @@ -51,15 +49,15 @@ publickey_msg([Cb, #ssh{user = User, {ok, Key} -> PubKeyBlob = ssh_file:encode_public_key(Key), SigData = build_sig_data(SessionId, - User, Service, Key, PubKeyBlob), + User, Service, PubKeyBlob, Alg), Sig = sign(SigData, Hash, Key), - SigBlob = list_to_binary([?string(algorithm(Key)), ?binary(Sig)]), + SigBlob = list_to_binary([?string(Alg), ?binary(Sig)]), ssh_transport:ssh_packet( #ssh_msg_userauth_request{user = User, service = Service, method = "publickey", data = [?TRUE, - ?string(algorithm(Key)), + ?string(Alg), ?binary(PubKeyBlob), ?binary(SigBlob)]}, Ssh); @@ -108,12 +106,12 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> service = "ssh-connection", method = "none", data = <<>>}, - CbFirst = proplists:get_value(public_key_alg, Opts, - ?PREFERRED_PK_ALG), - CbSecond = other_cb(CbFirst), + FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts, + ?PREFERRED_PK_ALG)), + SecondAlg = other_alg(FirstAlg), AllowUserInt = proplists:get_value(allow_user_interaction, Opts, true), - Prefs = method_preference(CbFirst, CbSecond, AllowUserInt), + Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, userauth_preference = Prefs, userauth_methods = none, @@ -233,7 +231,6 @@ handle_userauth_info_request( PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data), Resps = keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos), - %%?dbg(true, "keyboard_interactive_reply: resps=~n#~p ~n", [Resps]), RespBin = list_to_binary( lists:map(fun(S) -> <> end, Resps)), @@ -268,15 +265,15 @@ userauth_messages() -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -method_preference(Callback1, Callback2, true) -> - [{"publickey", ?MODULE, publickey_msg, [Callback1]}, - {"publickey", ?MODULE, publickey_msg,[Callback2]}, +method_preference(Alg1, Alg2, true) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"publickey", ?MODULE, publickey_msg,[Alg2]}, {"password", ?MODULE, password_msg, []}, {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []} ]; -method_preference(Callback1, Callback2, false) -> - [{"publickey", ?MODULE, publickey_msg, [Callback1]}, - {"publickey", ?MODULE, publickey_msg,[Callback2]}, +method_preference(Alg1, Alg2, false) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"publickey", ?MODULE, publickey_msg,[Alg2]}, {"password", ?MODULE, password_msg, []} ]. @@ -300,7 +297,6 @@ user_name(Opts) -> end. check_password(User, Password, Opts) -> - %%?dbg(true, " ~p ~p ~p ~n", [User, Password, Opts]), case proplists:get_value(pwdfun, Opts) of undefined -> Static = get_password_option(Opts, User), @@ -322,8 +318,8 @@ verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) -> {ok, OurKey} -> case OurKey of Key -> - PlainText = build_sig_data(SessionId, - User, Service, Key, KeyBlob), + PlainText = build_sig_data(SessionId, User, + Service, KeyBlob, Alg), <> = SigWLen, <> = AlgSig, @@ -334,29 +330,21 @@ verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) -> Error -> Error end. -build_sig_data(SessionId, User, Service, Key, KeyBlob) -> +build_sig_data(SessionId, User, Service, KeyBlob, Alg) -> Sig = [?binary(SessionId), ?SSH_MSG_USERAUTH_REQUEST, ?string(User), ?string(Service), ?binary(<<"publickey">>), ?TRUE, - ?string(algorithm(Key)), + ?string(Alg), ?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". + "ssh-dss". sign(SigData, Hash, #'DSAPrivateKey'{} = Key) -> DerSignature = public_key:sign(SigData, Hash, Key), @@ -364,17 +352,13 @@ sign(SigData, Hash, #'DSAPrivateKey'{} = Key) -> <>; 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) -> <> = 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). + public_key:verify(PlainText, Hash, Sig, Key). decode_keyboard_interactive_prompts(NumPrompts, Data) -> Types = lists:append(lists:duplicate(NumPrompts, [string, boolean])), @@ -447,8 +431,7 @@ userauth_pk_messages() -> binary]} % key blob ]. -other_cb(ssh_rsa) -> - ssh_dsa; -other_cb(ssh_dsa) -> - ssh_rsa. - +other_alg("ssh-rsa") -> + "ssh-dss"; +other_alg("ssh-dss") -> + "ssh-rsa". -- cgit v1.2.3 From f5f4a7015569dd5bbd7114d89a370ea1bed09023 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin Date: Mon, 6 Feb 2012 11:23:53 +0100 Subject: Cleaned up code so that ssh_file can become a template for a documented ssh_keys behavior --- lib/ssh/src/ssh_auth.erl | 74 ++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 34 deletions(-) (limited to 'lib/ssh/src/ssh_auth.erl') diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index 3b087262d8..a2e74a12bb 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -41,16 +41,17 @@ publickey_msg([Alg, #ssh{user = User, session_id = SessionId, service = Service, opts = Opts} = Ssh]) -> - + Hash = sha, %% Maybe option?! ssh_bits:install_messages(userauth_pk_messages()), - - case ssh_file:private_identity_key(Alg, Opts) of + KeyCb = proplists:get_value(key_cb, Opts, ssh_file), + + case KeyCb:user_key(Alg, Opts) of {ok, Key} -> - PubKeyBlob = ssh_file:encode_public_key(Key), + PubKeyBlob = encode_public_key(Key), SigData = build_sig_data(SessionId, User, Service, PubKeyBlob, Alg), - Sig = sign(SigData, Hash, Key), + Sig = ssh_transport:sign(SigData, Hash, Key), SigBlob = list_to_binary([?string(Alg), ?binary(Sig)]), ssh_transport:ssh_packet( #ssh_msg_userauth_request{user = User, @@ -313,21 +314,19 @@ get_password_option(Opts, User) -> end. verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) -> - {ok, Key} = ssh_file:decode_public_key_v2(KeyBlob, Alg), - case ssh_file:lookup_user_key(Key, User, Alg, Opts) of - {ok, OurKey} -> - case OurKey of - Key -> - PlainText = build_sig_data(SessionId, User, - Service, KeyBlob, Alg), - <> = SigWLen, - <> = AlgSig, - verify(PlainText, sha, Sig, Key); - _ -> - {error, key_unacceptable} - end; - Error -> Error + {ok, Key} = decode_public_key_v2(KeyBlob, Alg), + KeyCb = proplists:get_value(key_cb, Opts, ssh_file), + + case KeyCb:is_auth_key(Key, User, Alg, Opts) of + true -> + PlainText = build_sig_data(SessionId, User, + Service, KeyBlob, Alg), + <> = SigWLen, + <> = AlgSig, + ssh_transport:verify(PlainText, sha, Sig, Key); + false -> + {error, key_unacceptable} end. build_sig_data(SessionId, User, Service, KeyBlob, Alg) -> @@ -346,20 +345,6 @@ algorithm(ssh_rsa) -> algorithm(ssh_dsa) -> "ssh-dss". -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), - <>; -sign(SigData, Hash, Key) -> - public_key:sign(SigData, Hash, Key). - -verify(PlainText, Hash, Sig, {_, #'Dss-Parms'{}} = Key) -> - <> = 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, Hash, Sig, Key). - decode_keyboard_interactive_prompts(NumPrompts, Data) -> Types = lists:append(lists:duplicate(NumPrompts, [string, boolean])), pairwise_tuplify(ssh_bits:decode(Data, Types)). @@ -435,3 +420,24 @@ other_alg("ssh-rsa") -> "ssh-dss"; other_alg("ssh-dss") -> "ssh-rsa". +decode_public_key_v2(K_S, "ssh-rsa") -> + case ssh_bits:decode(K_S,[string,mpint,mpint]) of + ["ssh-rsa", E, N] -> + {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, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}}; + _ -> + {error, bad_format} + end; +decode_public_key_v2(_, _) -> + {error, bad_format}. + +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]). -- cgit v1.2.3