From 01d1e4dc9a6e7ea958683ab419dea38bf576a39f Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Tue, 13 Oct 2015 09:21:02 +0200
Subject: ssh, public_key: Change EC Public Key representation to what was
 intended

---
 lib/public_key/src/pubkey_ssh.erl      |  76 ++++++++--------
 lib/public_key/src/public_key.erl      |  16 ++++
 lib/ssh/src/ssh.hrl                    |  13 ++-
 lib/ssh/src/ssh_auth.erl               |  17 ++--
 lib/ssh/src/ssh_connection_handler.erl |   1 +
 lib/ssh/src/ssh_file.erl               |  13 +--
 lib/ssh/src/ssh_message.erl            | 162 ++++++++++++++-------------------
 lib/ssh/src/ssh_transport.erl          | 100 +++++++++++---------
 lib/ssh/test/ssh_test_lib.erl          |  11 +--
 lib/ssh/test/ssh_trpt_test_lib.erl     |   2 +-
 10 files changed, 204 insertions(+), 207 deletions(-)

diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index 26fbeb68ce..3addbfe3c6 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -21,7 +21,8 @@
 
 -include("public_key.hrl").
 
--export([decode/2, encode/2]).
+-export([decode/2, encode/2
+	]).
 
 -define(UINT32(X), X:32/unsigned-big-integer).
 -define(STRING(X), ?UINT32((size(X))), (X)/binary).
@@ -33,6 +34,7 @@
 %% are still compliant.)" So we choose to use 68 also.
 -define(ENCODED_LINE_LENGTH, 68).
 
+
 %%====================================================================
 %% Internal application API
 %%====================================================================
@@ -133,12 +135,11 @@ rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary,
      #'Dss-Parms'{p = erlint(SizeP, P),
 		  q = erlint(SizeQ, Q),
 		  g = erlint(SizeG, G)}};
-rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary,
+rfc4716_pubkey_decode(<<?UINT32(Len), ECDSA_SHA2_etc:Len/binary,
 			?UINT32(SizeId), Id:SizeId/binary,
-			?UINT32(SizeQ), Q:SizeQ/binary>>) when Type == <<"ecdsa-sha2-nistp256">>;
-							       Type == <<"ecdsa-sha2-nistp384">>;
-							       Type == <<"ecdsa-sha2-nistp521">> ->
-    {#'ECPoint'{point = Q}, Id}.
+			?UINT32(SizeQ), Q:SizeQ/binary>>) ->
+    <<"ecdsa-sha2-", Id/binary>> = ECDSA_SHA2_etc,
+    {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}}.
 
 openssh_decode(Bin, FileType) ->
     Lines = binary:split(Bin, <<"\n">>, [global]),
@@ -192,26 +193,28 @@ do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) ->
     end;
 
 do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) ->
-    case split_n(2, Line, []) of
-	[KeyType, Base64Enc] when KeyType == <<"ssh-rsa">>;
-				  KeyType == <<"ssh-dss">>;
-				  KeyType == <<"ecdsa-sha2-nistp256">>;
-				  KeyType == <<"ecdsa-sha2-nistp384">>;
-				  KeyType == <<"ecdsa-sha2-nistp521">> ->
+    [KeyType, Base64Enc | Comment0] = split_n(2, Line, []),
+    KnownKeyType = 
+	case KeyType of
+	    <<"ssh-rsa">> -> true;
+	    <<"ssh-dss">> -> true;
+	    <<"ecdsa-sha2-",Curve/binary>> -> is_ssh_curvename(Curve);
+	    _ -> false
+	end,
+
+    case Comment0 of
+	[] when KnownKeyType==true ->
 	    do_openssh_decode(FileType, Lines,
 			      [{openssh_pubkey_decode(KeyType, Base64Enc),
 				[]} | Acc]);
-	[KeyType, Base64Enc | Comment0] when KeyType == <<"ssh-rsa">>;
-					     KeyType == <<"ssh-dss">>;
-					     KeyType == <<"ecdsa-sha2-nistp256">>;
-					     KeyType == <<"ecdsa-sha2-nistp384">>;
-					     KeyType == <<"ecdsa-sha2-nistp521">> ->
+	_ when KnownKeyType==true ->
 	    Comment = string:strip(string_decode(iolist_to_binary(Comment0)), right, $\n),
 	    do_openssh_decode(FileType, Lines,
 			      [{openssh_pubkey_decode(KeyType, Base64Enc),
 				[{comment, Comment}]} | Acc])
     end.
 
+
 decode_comment([]) ->
     [];
 decode_comment(Comment) ->
@@ -244,7 +247,7 @@ openssh_pubkey_decode(<<"ecdsa-sha2-", Id/binary>>, Base64Enc) ->
       ?UINT32(SizeId), Id:SizeId/binary,
       ?UINT32(SizeQ), Q:SizeQ/binary>>
 	= base64:mime_decode(Base64Enc),
-    {#'ECPoint'{point = Q}, Id};
+    {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}};
 
 openssh_pubkey_decode(KeyType, Base64Enc) ->
     {KeyType, base64:mime_decode(Base64Enc)}.
@@ -372,12 +375,9 @@ line_end("") ->
 line_end(Comment) ->
     [" ", Comment, "\n"].
 
-key_type(#'RSAPublicKey'{}) ->
-    <<"ssh-rsa">>;
-key_type({_, #'Dss-Parms'{}}) ->
-    <<"ssh-dss">>;
-key_type({#'ECPoint'{}, Id}) ->
-    <<"ecdsa-sha2-",Id/binary>>.
+key_type(#'RSAPublicKey'{})   -> <<"ssh-rsa">>;
+key_type({_, #'Dss-Parms'{}}) -> <<"ssh-dss">>;
+key_type({#'ECPoint'{}, {namedCurve,Curve}}) -> <<"ecdsa-sha2-", (public_key:oid2ssh_curvename(Curve))/binary>>.
 
 comma_list_encode([Option], [])  ->
     Option;
@@ -408,25 +408,18 @@ ssh2_pubkey_encode({Y,  #'Dss-Parms'{p = P, q = Q, g = G}}) ->
       QBin/binary,
       GBin/binary,
       YBin/binary>>;
-ssh2_pubkey_encode({#'ECPoint'{point = Q}, Id}) ->
-    TypeStr = <<"ecdsa-sha2-", Id/binary>>,
+ssh2_pubkey_encode(Key={#'ECPoint'{point = Q}, {namedCurve,OID}}) ->
+    TypeStr = key_type(Key),
     StrLen = size(TypeStr),
+    IdB = public_key:oid2ssh_curvename(OID),
     <<?UINT32(StrLen), TypeStr:StrLen/binary,
-      (string(Id))/binary,
+      (string(IdB))/binary,
       (string(Q))/binary>>.
 
-is_key_field(<<"ssh-dss">>) ->
-    true;
-is_key_field(<<"ssh-rsa">>) ->
-    true;
-is_key_field(<<"ecdsa-sha2-nistp256">>) ->
-    true;
-is_key_field(<<"ecdsa-sha2-nistp384">>) ->
-    true;
-is_key_field(<<"ecdsa-sha2-nistp521">>) ->
-    true;
-is_key_field(_) ->
-    false.
+is_key_field(<<"ssh-dss">>) ->  true;
+is_key_field(<<"ssh-rsa">>) ->  true;
+is_key_field(<<"ecdsa-sha2-",Id/binary>>) -> is_ssh_curvename(Id);
+is_key_field(_) -> false.
 
 is_bits_field(Part) ->
     try list_to_integer(binary_to_list(Part)) of
@@ -546,3 +539,8 @@ string(X) when is_binary(X) ->
     << ?STRING(X) >>;
 string(X) ->
     << ?STRING(list_to_binary(X)) >>.
+
+is_ssh_curvename(Id) -> try public_key:ssh_curvename2oid(Id) of _ -> true
+			catch _:_  -> false
+			end.
+
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 2f4cc64c2a..2b04b3f79b 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -47,6 +47,7 @@
 	 pkix_normalize_name/1,
 	 pkix_path_validation/3,
 	 ssh_decode/2, ssh_encode/2,
+	 ssh_curvename2oid/1, oid2ssh_curvename/1,
 	 pkix_crls_validate/3,
 	 pkix_dist_point/1,
 	 pkix_dist_points/1,
@@ -741,6 +742,21 @@ ssh_encode(Entries, Type) when is_list(Entries),
 			       Type == known_hosts ->
     pubkey_ssh:encode(Entries, Type).
 
+%%--------------------------------------------------------------------
+%% Description: Converts from the ssh name of elliptic curves to
+%% the OIDs.
+%%--------------------------------------------------------------------
+ssh_curvename2oid(<<"nistp256">>) ->  ?'secp256r1';
+ssh_curvename2oid(<<"nistp384">>) ->  ?'secp384r1';
+ssh_curvename2oid(<<"nistp521">>) ->  ?'secp521r1'.
+
+%%--------------------------------------------------------------------
+%% Description: Converts from elliptic curve OIDs to the ssh name.
+%%--------------------------------------------------------------------
+oid2ssh_curvename(?'secp256r1') -> <<"nistp256">>;
+oid2ssh_curvename(?'secp384r1') -> <<"nistp384">>;
+oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>.
+
 %%--------------------------------------------------------------------
 %%% Internal functions
 %%--------------------------------------------------------------------
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index da64e4abf9..fc9d60c500 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -37,13 +37,16 @@
 -define(FALSE, 0).
 -define(TRUE,  1).
 %% basic binary constructors
--define(BOOLEAN(X),  X:8/unsigned-big-integer).
--define(BYTE(X),     X:8/unsigned-big-integer).
--define(UINT16(X),   X:16/unsigned-big-integer).
--define(UINT32(X),   X:32/unsigned-big-integer).
--define(UINT64(X),   X:64/unsigned-big-integer).
+-define(BOOLEAN(X),  (X):8/unsigned-big-integer).
+-define(BYTE(X),     (X):8/unsigned-big-integer).
+-define(UINT16(X),   (X):16/unsigned-big-integer).
+-define(UINT32(X),   (X):32/unsigned-big-integer).
+-define(UINT64(X),   (X):64/unsigned-big-integer).
 -define(STRING(X),   ?UINT32((size(X))), (X)/binary).
 
+-define(DEC_BIN(X,Len),   ?UINT32(Len), X:Len/binary ).
+-define(DEC_MPINT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ).
+
 %% building macros
 -define(boolean(X),
 	case X of
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 0c16e19701..8c6ffceb4b 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -500,16 +500,15 @@ decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary,
 			 , "ssh-dss") ->
     {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}};
 decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary,
-		       ?UINT32(Len1), Id:Len1/binary, %% Id = <<"nistp256">> for example
+		       ?UINT32(Len1), IdB:Len1/binary, %% Id = <<"nistp256">> for example
 		       ?UINT32(Len2), Blob:Len2/binary>>,
-		     Curve) -> 
-    Id = 
-	case Curve of
-	    "ecdsa-sha2-nistp256" -> <<"nistp256">>;
-	    "ecdsa-sha2-nistp384" -> <<"nistp384">>;
-	    "ecdsa-sha2-nistp521" -> <<"nistp521">>
-	end,
-    {ok, {#'ECPoint'{point=Blob}, Id}};
+		     "ecdsa-sha2-" ++ IdS) -> 
+    case binary_to_list(IdB) of
+	IdS ->
+	    {ok, {#'ECPoint'{point=Blob}, {namedCurve,public_key:ssh_curvename2oid(IdB)}} };
+	_ ->
+	    {error, bad_format}
+    end;
 decode_public_key_v2(_, _) ->
     {error, bad_format}.
 
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 7fb86c1108..09ef03f3f8 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1348,6 +1348,7 @@ event(Event, StateName, State) ->
 	throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg}  ->
 	    handle_disconnect(DisconnectMsg, State, ErrorToDisplay);
 	_C:_Error ->
+ct:pal("*** FAIL ~p:~p(~p,...~n -> ~p:~p ",[?MODULE,StateName,Event,_C,_Error]),
 	    handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName),
 						  description = "Invalid state",
 						  language = "en"}, State)
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 4e6d58cbff..c087ce14d7 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -276,12 +276,13 @@ key_match(#'RSAPublicKey'{}, 'ssh-rsa') ->
     true;
 key_match({_, #'Dss-Parms'{}}, 'ssh-dss') ->
     true;
-key_match({#'ECPoint'{},<<"nistp256">>}, 'ecdsa-sha2-nistp256') ->
-    true;
-key_match({#'ECPoint'{},<<"nistp384">>}, 'ecdsa-sha2-nistp384') ->
-    true;
-key_match({#'ECPoint'{},<<"nistp521">>}, 'ecdsa-sha2-nistp521') ->
-    true;
+key_match({#'ECPoint'{},{namedCurve,Curve}}, Alg) ->
+    case atom_to_list(Alg) of
+	"ecdsa-sha2-"++IdS ->
+	    Curve == public_key:ssh_curvename2oid(list_to_binary(IdS));
+	_ ->
+	    false
+    end;
 key_match(_, _) ->
     false.
 
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index cfa11903fb..42e9b27b93 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -228,7 +228,7 @@ encode(#ssh_msg_kexdh_reply{
 	  h_sig = Signature
 	 }) ->
     EncKey = encode_host_key(Key),
-    EncSign = encode_sign(Key, Signature),
+    EncSign = encode_signature(Key, Signature),
     ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
 
 encode(#ssh_msg_kex_dh_gex_request{
@@ -256,7 +256,7 @@ encode(#ssh_msg_kex_dh_gex_reply{
 	  h_sig = Signature
 	 }) ->
     EncKey = encode_host_key(Key),
-    EncSign = encode_sign(Key, Signature),
+    EncSign = encode_signature(Key, Signature),
     ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
 
 encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
@@ -264,7 +264,7 @@ encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
 
 encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) ->
     EncKey = encode_host_key(Key),
-    EncSign = encode_sign(Key, Sign),
+    EncSign = encode_signature(Key, Sign),
     ssh_bits:encode([?SSH_MSG_KEX_ECDH_REPLY, EncKey, Q_s, EncSign], [byte, binary, mpint, binary]);
 
 encode(#ssh_msg_ignore{data = Data}) ->
@@ -280,8 +280,7 @@ encode(#ssh_msg_debug{always_display = Bool,
 
 
 %% Connection Messages
-decode(<<?BYTE(?SSH_MSG_GLOBAL_REQUEST), ?UINT32(Len), Name:Len/binary,
-	 ?BYTE(Bool), Data/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_GLOBAL_REQUEST), ?DEC_BIN(Name,__0), ?BYTE(Bool), Data/binary>>) ->
     #ssh_msg_global_request{
        name = Name,
        want_reply = erl_boolean(Bool),
@@ -292,8 +291,7 @@ decode(<<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>) ->
 decode(<<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>) ->
     #ssh_msg_request_failure{};
 decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN),
-	 ?UINT32(Len), Type:Len/binary,
-	 ?UINT32(Sender), ?UINT32(Window), ?UINT32(Max),
+	 ?DEC_BIN(Type,__0), ?UINT32(Sender), ?UINT32(Window), ?UINT32(Max),
 	 Data/binary>>) ->
     #ssh_msg_channel_open{
        channel_type = binary_to_list(Type),
@@ -313,7 +311,7 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_CONFIRMATION), ?UINT32(Recipient), ?UINT32(
        data = Data
       };
 decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_FAILURE),  ?UINT32(Recipient), ?UINT32(Reason),
-	 ?UINT32(Len0), Desc:Len0/binary,  ?UINT32(Len1), Lang:Len1/binary >>) ->
+	 ?DEC_BIN(Desc,__0), ?DEC_BIN(Lang,__1) >> ) ->
     #ssh_msg_channel_open_failure{
        recipient_channel = Recipient,
        reason = Reason,
@@ -326,13 +324,13 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_WINDOW_ADJUST), ?UINT32(Recipient), ?UINT32(Byte
        bytes_to_add = Bytes
     };
 
-decode(<<?BYTE(?SSH_MSG_CHANNEL_DATA), ?UINT32(Recipient), ?UINT32(Len), Data:Len/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_CHANNEL_DATA), ?UINT32(Recipient), ?DEC_BIN(Data,__0)>>) ->
     #ssh_msg_channel_data{
        recipient_channel = Recipient,
        data = Data
     };
 decode(<<?BYTE(?SSH_MSG_CHANNEL_EXTENDED_DATA), ?UINT32(Recipient), 
-	 ?UINT32(DataType), ?UINT32(Len), Data:Len/binary>>) ->
+	 ?UINT32(DataType), ?DEC_BIN(Data,__0)>>) ->
     #ssh_msg_channel_extended_data{
        recipient_channel = Recipient,
        data_type_code = DataType,
@@ -347,8 +345,7 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_CLOSE),  ?UINT32(Recipient)>>) ->
        recipient_channel = Recipient
       };
 decode(<<?BYTE(?SSH_MSG_CHANNEL_REQUEST), ?UINT32(Recipient),
-	 ?UINT32(Len), RequestType:Len/binary,
-	 ?BYTE(Bool), Data/binary>>) ->
+	 ?DEC_BIN(RequestType,__0), ?BYTE(Bool), Data/binary>>) ->
     #ssh_msg_channel_request{
        recipient_channel = Recipient,
        request_type = unicode:characters_to_list(RequestType),
@@ -366,9 +363,7 @@ decode(<<?BYTE(?SSH_MSG_CHANNEL_FAILURE),  ?UINT32(Recipient)>>) ->
 
 %%% Auth Messages
 decode(<<?BYTE(?SSH_MSG_USERAUTH_REQUEST),
-	 ?UINT32(Len0), User:Len0/binary,
-	 ?UINT32(Len1), Service:Len1/binary,
-	 ?UINT32(Len2), Method:Len2/binary,
+	 ?DEC_BIN(User,__0), ?DEC_BIN(Service,__1), ?DEC_BIN(Method,__2),
 	 Data/binary>>) ->
     #ssh_msg_userauth_request{
        user = unicode:characters_to_list(User),
@@ -378,7 +373,7 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_REQUEST),
       };
 
 decode(<<?BYTE(?SSH_MSG_USERAUTH_FAILURE),
-	 ?UINT32(Len0), Auths:Len0/binary,
+	 ?DEC_BIN(Auths,__0),
 	 ?BYTE(Bool)>>) ->
     #ssh_msg_userauth_failure {
        authentications = unicode:characters_to_list(Auths),
@@ -388,16 +383,14 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_FAILURE),
 decode(<<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>) ->
     #ssh_msg_userauth_success{};
 
-decode(<<?BYTE(?SSH_MSG_USERAUTH_BANNER),
-	       ?UINT32(Len0), Banner:Len0/binary,
-	       ?UINT32(Len1), Lang:Len1/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_USERAUTH_BANNER), ?DEC_BIN(Banner,__0), ?DEC_BIN(Lang,__1) >>) ->
     #ssh_msg_userauth_banner{
        message = Banner,
        language = Lang
       };
 
-decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary,
-	 ?UINT32(Len1), Inst:Len1/binary, ?UINT32(Len2), Lang:Len2/binary,
+decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST),
+	 ?DEC_BIN(Name,__0), ?DEC_BIN(Inst,__1), ?DEC_BIN(Lang,__2),
 	 ?UINT32(NumPromtps), Data/binary>>) ->
     #ssh_msg_userauth_info_request{
        name = Name,
@@ -407,15 +400,14 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary,
        data = Data};
 
 %%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST:
-decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?UINT32(Len0), Prompt:Len0/binary,
-	 ?UINT32(Len1), Lang:Len1/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?DEC_BIN(Prompt,__0), ?DEC_BIN(Lang,__1) >>) ->
     #ssh_msg_userauth_passwd_changereq{
        prompt = Prompt,
        languge = Lang
       };
 
 %%% Unhandled message, also masked by same 1:st byte value as ?SSH_MSG_USERAUTH_INFO_REQUEST:
-decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?UINT32(Len), Alg:Len/binary, KeyBlob/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?DEC_BIN(Alg,__0), KeyBlob/binary>>) ->
     #ssh_msg_userauth_pk_ok{
        algorithm_name = Alg,
        key_blob = KeyBlob
@@ -430,18 +422,15 @@ decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) ->
 decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>) ->
     decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10);
 
-decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?UINT32(Len), E:Len/big-signed-integer-unit:8>>) ->
+decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?DEC_MPINT(E,__0)>>) ->
     #ssh_msg_kexdh_init{e = E
 		       };
 
-decode(<<"dh", ?BYTE(?SSH_MSG_KEXDH_REPLY), 
-	 ?UINT32(Len0), Key:Len0/binary,
-	 ?UINT32(Len1), F:Len1/big-signed-integer-unit:8,
-	 ?UINT32(Len2), Hashsign:Len2/binary>>) ->
+decode(<<"dh", ?BYTE(?SSH_MSG_KEXDH_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) ->
     #ssh_msg_kexdh_reply{
        public_host_key = decode_host_key(Key),
        f = F,
-       h_sig = decode_sign(Hashsign)
+       h_sig = decode_signature(Hashsign)
       };
 
 decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST), ?UINT32(Min), ?UINT32(N), ?UINT32(Max)>>) ->
@@ -456,57 +445,48 @@ decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) ->
        n = N
       };
 
-decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP),  
-	 ?UINT32(Len0), Prime:Len0/big-signed-integer-unit:8,
-	 ?UINT32(Len1), Generator:Len1/big-signed-integer-unit:8>>) ->
+decode(<<"dh_gex",?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), ?DEC_MPINT(Prime,__0), ?DEC_MPINT(Generator,__1) >>) ->
     #ssh_msg_kex_dh_gex_group{
        p = Prime,
        g = Generator
       };
 
-decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?UINT32(Len), E:Len/big-signed-integer-unit:8>>) ->
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?DEC_MPINT(E,__0)>>) ->
     #ssh_msg_kex_dh_gex_init{
        e = E
       };
 
-decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), 
-	 ?UINT32(Len0), Key:Len0/binary,
-	 ?UINT32(Len1), F:Len1/big-signed-integer-unit:8,
-	 ?UINT32(Len2), Hashsign:Len2/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) ->
     #ssh_msg_kex_dh_gex_reply{
        public_host_key = decode_host_key(Key),
        f = F,
-       h_sig = decode_sign(Hashsign)
+       h_sig = decode_signature(Hashsign)
       };
 
-decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT),
-	 ?UINT32(Len0), Q_c:Len0/big-signed-integer-unit:8>>) ->
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_MPINT(Q_c,__0)>>) ->
     #ssh_msg_kex_ecdh_init{
        q_c = Q_c
       };
 
 decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
-	 ?UINT32(Len1), Key:Len1/binary,
-	 ?UINT32(Len2), Q_s:Len2/big-signed-integer-unit:8,
-	 ?UINT32(Len3), Sig:Len3/binary>>) ->
+	 ?DEC_BIN(Key,__1), ?DEC_MPINT(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->
     #ssh_msg_kex_ecdh_reply{
        public_host_key = decode_host_key(Key),
        q_s = Q_s,
-       h_sig = decode_sign(Sig)
+       h_sig = decode_signature(Sig)
       };
 
-decode(<<?SSH_MSG_SERVICE_REQUEST, ?UINT32(Len0), Service:Len0/binary>>) ->
+decode(<<?SSH_MSG_SERVICE_REQUEST, ?DEC_BIN(Service,__0)>>) ->
     #ssh_msg_service_request{
        name = unicode:characters_to_list(Service)
       };
 
-decode(<<?SSH_MSG_SERVICE_ACCEPT, ?UINT32(Len0), Service:Len0/binary>>) ->
+decode(<<?SSH_MSG_SERVICE_ACCEPT, ?DEC_BIN(Service,__0)>>) ->
     #ssh_msg_service_accept{
        name = unicode:characters_to_list(Service)
       };
 
-decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code),
-       ?UINT32(Len0), Desc:Len0/binary, ?UINT32(Len1), Lang:Len1/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc,__0), ?DEC_BIN(Lang,__1)>>) ->
     #ssh_msg_disconnect{
        code = Code,
        description = unicode:characters_to_list(Desc),
@@ -514,8 +494,7 @@ decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code),
       };
 
 %% Accept bad disconnects from ancient openssh clients that doesn't send language tag.  Use english as a work-around.
-decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code),
-       ?UINT32(Len0), Desc:Len0/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code), ?DEC_BIN(Desc,__0)>>) ->
     #ssh_msg_disconnect{
        code = Code,
        description = unicode:characters_to_list(Desc),
@@ -525,21 +504,25 @@ decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code),
 decode(<<?SSH_MSG_NEWKEYS>>) ->
     #ssh_msg_newkeys{};
 
-decode(<<?BYTE(?SSH_MSG_IGNORE), ?UINT32(Len), Data:Len/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_IGNORE), ?DEC_BIN(Data,__0)>>) ->
     #ssh_msg_ignore{data = Data};
 
 decode(<<?BYTE(?SSH_MSG_UNIMPLEMENTED), ?UINT32(Seq)>>) ->
     #ssh_msg_unimplemented{sequence = Seq};
 
-decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?UINT32(Len0), Msg:Len0/binary,
-	 ?UINT32(Len1), Lang:Len1/binary>>) ->
+decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?DEC_BIN(Msg,__0), ?DEC_BIN(Lang,__1)>>) ->
     #ssh_msg_debug{always_display = erl_boolean(Bool),
 		   message = Msg,
 		   language = Lang}.
 
+%%%================================================================
+%%%
+%%% Helper functions
+%%%
+
 decode_keyboard_interactive_prompts(<<>>, Acc) ->
     lists:reverse(Acc);
-decode_keyboard_interactive_prompts(<<?UINT32(Len), Prompt:Len/binary, ?BYTE(Bool), Bin/binary>>,
+decode_keyboard_interactive_prompts(<<?DEC_BIN(Prompt,__0), ?BYTE(Bool), Bin/binary>>,
 				    Acc) ->
     decode_keyboard_interactive_prompts(Bin, [{Prompt, erl_boolean(Bool)} | Acc]).
 
@@ -555,38 +538,34 @@ decode_kex_init(<<?BYTE(Bool)>>, Acc, 0) ->
     %% See rfc 4253 7.1
     X = 0,
     list_to_tuple(lists:reverse([X, erl_boolean(Bool) | Acc]));
-decode_kex_init(<<?UINT32(Len), Data:Len/binary, Rest/binary>>, Acc, N) ->
+decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) ->
     Names = string:tokens(unicode:characters_to_list(Data), ","),
     decode_kex_init(Rest, [Names | Acc], N -1).
 
 
+%%%================================================================
+%%%
+%%% Host key decode/encode
+%%%
 
-decode_sign(<<?UINT32(Len), _Alg:Len/binary, ?UINT32(_), Signature/binary>>) ->
-    Signature.
-
-
-decode_host_key(<<?UINT32(Len), Alg:Len/binary, Rest/binary>>) ->
-    decode_host_key(Alg, Rest).
+decode_host_key(<<?DEC_BIN(Alg,__0), Rest/binary>>) -> decode_host_key(Alg, Rest).
 
 
-decode_host_key(<<"ssh-rsa">>, <<?UINT32(Len0), E:Len0/big-signed-integer-unit:8,
-				 ?UINT32(Len1), N:Len1/big-signed-integer-unit:8>>) ->
+decode_host_key(<<"ssh-rsa">>, <<?DEC_MPINT(E,__0), ?DEC_MPINT(N,__1)>>) ->
     #'RSAPublicKey'{publicExponent = E,
 		    modulus = N};
-
 decode_host_key(<<"ssh-dss">>,
-		<<?UINT32(Len0), P:Len0/big-signed-integer-unit:8,
-		  ?UINT32(Len1), Q:Len1/big-signed-integer-unit:8,
-		  ?UINT32(Len2), G:Len2/big-signed-integer-unit:8,
-		  ?UINT32(Len3), Y:Len3/big-signed-integer-unit:8>>) ->
+		<<?DEC_MPINT(P,__0),
+		  ?DEC_MPINT(Q,__1),
+		  ?DEC_MPINT(G,__2),
+		  ?DEC_MPINT(Y,__3)>>) ->
     {Y, #'Dss-Parms'{p = P,
 		     q = Q,
 		     g = G}};
-
 decode_host_key(<<"ecdsa-sha2-",Id/binary>>,
-		<<?UINT32(Len0), Id:Len0/binary, %% Id = <<"nistp256">> for example
-		  ?UINT32(Len1), Blob:Len1/binary>>) ->
-    {#'ECPoint'{point=Blob}, Id}.
+		<<?DEC_BIN(Id,__0), %% Id = <<"nistp256">> for example
+		  ?DEC_BIN(Blob,__1)>>) ->
+    {#'ECPoint'{point=Blob}, {namedCurve,public_key:ssh_curvename2oid(Id)}}.
 
 
 encode_host_key(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
@@ -594,30 +573,25 @@ encode_host_key(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
 encode_host_key({Y,  #'Dss-Parms'{p = P, q = Q, g = G}}) ->
     ssh_bits:encode(["ssh-dss", P, Q, G, Y],
 		    [string, mpint, mpint, mpint, mpint]);
-encode_host_key({#'ECPoint'{point = Q}, Id}) ->
-    ssh_bits:encode([<<"ecdsa-sha2-",Id/binary>>,Id,Q], [binary,binary,binary]);
+encode_host_key({#'ECPoint'{point = Q}, {namedCurve,OID}}) ->
+    CurveName = public_key:oid2ssh_curvename(OID),
+    ssh_bits:encode([<<"ecdsa-sha2-",CurveName/binary>>,CurveName,Q], [binary,binary,binary]).
 
-encode_host_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) ->
-    ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]);
-encode_host_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) ->
-    ssh_bits:encode(["ssh-dss", P, Q, G, Y],
-		    [string, mpint, mpint, mpint, mpint]);
-encode_host_key(#'ECPrivateKey'{parameters = Params, %{namedCurve,{1,2,840,10045,3,1,7}},
-				publicKey = Pub}) ->
-    Id = ecdsa_id(Params),
-    ssh_bits:encode(["ecdsa-sha2-"++Id, Id, Pub],
-                    [string, string, binary]).
+
+%%%================================================================
+%%%
+%%% Signature decode/encode
+%%%
+
+decode_signature(<<?DEC_BIN(_Alg,__0), ?UINT32(_), Signature/binary>>) ->
+    Signature.
 
 
-encode_sign(#'RSAPrivateKey'{}, Signature) ->
+encode_signature(#'RSAPublicKey'{}, Signature) ->
     ssh_bits:encode(["ssh-rsa", Signature],[string, binary]);
-encode_sign(#'DSAPrivateKey'{}, Signature) ->
+encode_signature({_, #'Dss-Parms'{}}, Signature) ->
     ssh_bits:encode(["ssh-dss", Signature],[string, binary]);
-encode_sign(#'ECPrivateKey'{parameters = Params}, Signature) ->
-    Id = "ecdsa-sha2-" ++ ecdsa_id(Params),
-    ssh_bits:encode([Id, Signature],[string, binary]).
-
+encode_signature({#'ECPoint'{}, {namedCurve,OID}}, Signature) ->
+    CurveName = public_key:oid2ssh_curvename(OID),
+    ssh_bits:encode([<<"ecdsa-sha2-",CurveName/binary>>, Signature], [binary,binary]).
 
-ecdsa_id({namedCurve,?'secp256r1'}) -> "nistp256";
-ecdsa_id({namedCurve,?'secp384r1'}) -> "nistp384";
-ecdsa_id({namedCurve,?'secp521r1'}) -> "nistp521".
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index a6438e69d4..080d6f74f7 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -380,13 +380,15 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
 	1=<E, E=<(P-1) ->
 	    {Public, Private} = generate_key(dh, [P,G]),
 	    K = compute_key(dh, E, Private, [P,G]),
-	    Key = get_host_key(Ssh0),
-	    H = kex_h(Ssh0, Key, E, Public, K),
-	    H_SIG = sign_host_key(Ssh0, Key, H),
-	    {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_reply{public_host_key = Key,
-								f = Public,
-								h_sig = H_SIG
-							       }, Ssh0),
+	    MyPrivHostKey = get_host_key(Ssh0),
+	    MyPubHostKey = extract_public_key(MyPrivHostKey),
+	    H = kex_h(Ssh0, MyPubHostKey, E, Public, K),
+	    H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H),
+	    {SshPacket, Ssh1} = 
+		ssh_packet(#ssh_msg_kexdh_reply{public_host_key = MyPubHostKey,
+						f = Public,
+						h_sig = H_SIG
+					       }, Ssh0),
 	    {ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}},
 				     shared_secret = K,
 				     exchanged_hash = H,
@@ -401,7 +403,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
 		   })
     end.
 
-handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey,
+handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey,
 					f = F,
 					h_sig = H_SIG}, 
 		   #ssh{keyex_key = {{Private, Public}, {G, P}}} = Ssh0) ->
@@ -409,9 +411,9 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey,
     if 
 	1=<F, F=<(P-1)->
 	    K = compute_key(dh, F, Private, [P,G]),
-	    H = kex_h(Ssh0, HostKey, Public, F, K),
+	    H = kex_h(Ssh0, PeerPubHostKey, Public, F, K),
 
-	    case verify_host_key(Ssh0, HostKey, H, H_SIG) of
+	    case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
 		ok ->
 		    {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
 		    {ok, SshPacket, Ssh#ssh{shared_secret  = K,
@@ -480,11 +482,12 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
 	    K = compute_key(dh, E, Private, [P,G]),
 	    if
 		1<K, K<(P-1) ->
-		    HostKey = get_host_key(Ssh0),
-		    H = kex_h(Ssh0, HostKey, Min, NBits, Max, P, G, E, Public, K),
-		    H_SIG = sign_host_key(Ssh0, HostKey, H),
+		    MyPrivHostKey = get_host_key(Ssh0),
+		    MyPubHostKey = extract_public_key(MyPrivHostKey),
+		    H = kex_h(Ssh0, MyPubHostKey, Min, NBits, Max, P, G, E, Public, K),
+		    H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H),
 		    {SshPacket, Ssh} = 
-			ssh_packet(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey, 
+			ssh_packet(#ssh_msg_kex_dh_gex_reply{public_host_key = MyPubHostKey,
 							     f = Public,
 							     h_sig = H_SIG}, Ssh0),
 		    {ok, SshPacket, Ssh#ssh{shared_secret = K,
@@ -508,7 +511,7 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
 		  })
     end.
 
-handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey, 
+handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostKey, 
 						  f = F,
 						  h_sig = H_SIG},
 			#ssh{keyex_key = {{Private, Public}, {G, P}},
@@ -520,9 +523,9 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey,
 	    K = compute_key(dh, F, Private, [P,G]),
 	    if
 		1<K, K<(P-1) ->
-		    H = kex_h(Ssh0, HostKey, Min, NBits, Max, P, G, Public, F, K),
+		    H = kex_h(Ssh0, PeerPubHostKey, Min, NBits, Max, P, G, Public, F, K),
 
-		    case verify_host_key(Ssh0, HostKey, H, H_SIG) of
+		    case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
 			ok ->
 			    {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
 			    {ok, SshPacket, Ssh#ssh{shared_secret  = K,
@@ -565,11 +568,12 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
 	true ->
             {MyPublic, MyPrivate} = generate_key(ecdh, Curve),
 	    K = compute_key(ecdh, PeerPublic, MyPrivate, Curve),
-	    HostKey = get_host_key(Ssh0),
-	    H = kex_h(Ssh0, Curve, HostKey, PeerPublic, MyPublic, K),
-	    H_SIG = sign_host_key(Ssh0, HostKey, H),
+	    MyPrivHostKey = get_host_key(Ssh0),
+	    MyPubHostKey = extract_public_key(MyPrivHostKey),
+	    H = kex_h(Ssh0, Curve, MyPubHostKey, PeerPublic, MyPublic, K),
+	    H_SIG = sign_host_key(Ssh0, MyPrivHostKey, H),
 	    {SshPacket, Ssh1} = 
-		ssh_packet(#ssh_msg_kex_ecdh_reply{public_host_key = HostKey,
+		ssh_packet(#ssh_msg_kex_ecdh_reply{public_host_key = MyPubHostKey,
 						   q_s = MyPublic,
 						   h_sig = H_SIG},
 			   Ssh0),
@@ -587,7 +591,7 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
 		  })
     end.
 
-handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = HostKey,
+handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
 					      q_s = PeerPublic,
 					      h_sig = H_SIG},
 		      #ssh{keyex_key = {{MyPublic,MyPrivate}, Curve}} = Ssh0
@@ -596,8 +600,8 @@ handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = HostKey,
     case ecdh_validate_public_key(PeerPublic, Curve) of
 	true ->
 	    K = compute_key(ecdh, PeerPublic, MyPrivate, Curve),
-	    H = kex_h(Ssh0, Curve, HostKey, MyPublic, PeerPublic, K), 
-	    case verify_host_key(Ssh0, HostKey, H, H_SIG) of
+	    H = kex_h(Ssh0, Curve, PeerPubHostKey, MyPublic, PeerPublic, K), 
+	    case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
 		ok ->
 		    {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
 		    {ok, SshPacket, Ssh#ssh{shared_secret  = K,
@@ -659,13 +663,20 @@ get_host_key(SSH) ->
 sign_host_key(_Ssh, PrivateKey, H) ->
      sign(H, sign_host_key_sha(PrivateKey), PrivateKey).
 
-sign_host_key_sha(#'ECPrivateKey'{parameters = {namedCurve, ?'secp256r1'}}) -> sha256;
-sign_host_key_sha(#'ECPrivateKey'{parameters = {namedCurve, ?'secp384r1'}}) -> sha384;
-sign_host_key_sha(#'ECPrivateKey'{parameters = {namedCurve, ?'secp521r1'}}) -> sha512;
+sign_host_key_sha(#'ECPrivateKey'{parameters = {namedCurve,OID}}) -> sha(OID);
 sign_host_key_sha(#'RSAPrivateKey'{}) -> sha;
 sign_host_key_sha(#'DSAPrivateKey'{}) -> sha.
 
 
+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 = Q}) ->
+    {#'ECPoint'{point=Q}, {namedCurve,OID}}.
+
+
 verify_host_key(SSH, PublicKey, Digest, Signature) ->
     case verify(Digest, host_key_sha(PublicKey), Signature, PublicKey) of
 	false ->
@@ -674,14 +685,16 @@ verify_host_key(SSH, PublicKey, Digest, Signature) ->
 	    known_host_key(SSH, PublicKey, public_algo(PublicKey))
     end.
 
-host_key_sha(#'RSAPublicKey'{}) ->   sha;
-host_key_sha({_, #'Dss-Parms'{}}) -> sha;
-host_key_sha({#'ECPoint'{},Id}) ->   sha(list_to_atom(binary_to_list(Id))).
 
+host_key_sha(#'RSAPublicKey'{})    -> sha;
+host_key_sha({_, #'Dss-Parms'{}})  -> sha;
+host_key_sha({#'ECPoint'{},{namedCurve,OID}}) -> sha(OID).
 
 public_algo(#'RSAPublicKey'{}) ->   'ssh-rsa';
 public_algo({_, #'Dss-Parms'{}}) -> 'ssh-dss';
-public_algo({#'ECPoint'{},Id}) -> list_to_atom("ecdsa-sha2-" ++ binary_to_list(Id)).
+public_algo({#'ECPoint'{},{namedCurve,OID}}) -> 
+    Curve = public_key:oid2ssh_curvename(OID),
+    list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
 
 
 accepted_host(Ssh, PeerName, Opts) ->
@@ -933,17 +946,12 @@ 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, {ECPoint=#'ECPoint'{}, Param}) ->
-    C = case Param of
-	    <<"nistp256">> -> {namedCurve, ?'secp256r1'};
-	    <<"nistp384">> -> {namedCurve, ?'secp384r1'};
-	    <<"nistp521">> -> {namedCurve, ?'secp521r1'}
-	end,
+verify(PlainText, Hash, Sig, {#'ECPoint'{},_} = Key) ->
     <<?UINT32(Rlen),R:Rlen/big-signed-integer-unit:8,
       ?UINT32(Slen),S:Slen/big-signed-integer-unit:8>> = Sig,
     Sval = #'ECDSA-Sig-Value'{r=R, s=S},
     DerEncodedSig = public_key:der_encode('ECDSA-Sig-Value',Sval),
-    public_key:verify(PlainText, Hash, DerEncodedSig, {ECPoint,C});
+    public_key:verify(PlainText, Hash, DerEncodedSig, Key);
 verify(PlainText, Hash, Sig, Key) ->
     public_key:verify(PlainText, Hash, Sig, Key).
 
@@ -1372,16 +1380,18 @@ kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
 	end,
     crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
   
-sha('nistp256') -> sha256;
-sha('secp256r1')-> sha256;
-sha('nistp384') -> sha384;
-sha('secp384r1')-> sha384;
-sha('nistp521') -> sha512;
-sha('secp521r1')-> sha512;
+
+sha(secp256r1) -> sha256;
+sha(secp384r1) -> sha384;
+sha(secp521r1) -> sha512;
 sha('diffie-hellman-group1-sha1') -> sha;
 sha('diffie-hellman-group14-sha1') -> sha;
 sha('diffie-hellman-group-exchange-sha1')   -> sha;
-sha('diffie-hellman-group-exchange-sha256') -> sha256.
+sha('diffie-hellman-group-exchange-sha256') -> sha256;
+sha(?'secp256r1') -> sha(secp256r1);
+sha(?'secp384r1') -> sha(secp384r1);
+sha(?'secp521r1') -> sha(secp521r1).
+
 
 mac_key_size('hmac-sha1')    -> 20*8;
 mac_key_size('hmac-sha1-96') -> 20*8;
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 87eaeec1bc..a269192785 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -403,18 +403,13 @@ setup_rsa_auth_keys(Dir, UserDir) ->
     PKey = #'RSAPublicKey'{publicExponent = E, modulus = N},
     setup_auth_keys([{ PKey, [{comment, "Test"}]}], UserDir).
 
-setup_ecdsa_auth_keys(Size, Dir, UserDir) ->
+setup_ecdsa_auth_keys(_Size, Dir, UserDir) ->
     {ok, Pem} = file:read_file(filename:join(Dir, "id_ecdsa")),
     ECDSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))),
     #'ECPrivateKey'{publicKey = Q,
-		    parameters = {namedCurve,Id0}} = ECDSA,
+		    parameters = Param = {namedCurve,_Id0}} = ECDSA,
     PKey = #'ECPoint'{point = Q},
-    Id = case pubkey_cert_records:namedCurves(Id0) of
-	     secp256r1 when Size=="256" -> <<"nistp256">>;
-	     secp384r1 when Size=="384" -> <<"nistp384">>;
-	     secp521r1 when Size=="521" -> <<"nistp521">>
-	 end,
-    setup_auth_keys([{ {PKey,Id}, [{comment, "Test"}]}], UserDir).
+    setup_auth_keys([{ {PKey,Param}, [{comment, "Test"}]}], UserDir).
 
 setup_auth_keys(Keys, Dir) ->
     AuthKeys = public_key:ssh_encode(Keys, auth_keys),
diff --git a/lib/ssh/test/ssh_trpt_test_lib.erl b/lib/ssh/test/ssh_trpt_test_lib.erl
index caf9bac3b6..772e50df87 100644
--- a/lib/ssh/test/ssh_trpt_test_lib.erl
+++ b/lib/ssh/test/ssh_trpt_test_lib.erl
@@ -743,7 +743,7 @@ print_traces(S) ->
 		      [case Len-length(Acc)-1 of
 			   0 ->
 			       io_lib:format(Fmt,Args);
-			   N ->
+			   _N ->
 			       io_lib:format(lists:concat(['~p --------~n',Fmt]),
 					     [Len-length(Acc)-1|Args])
 		       end | Acc]
-- 
cgit v1.2.3


From 19eec0552c6b4e5024e307d2376c061665007e4f Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Wed, 14 Oct 2015 17:47:13 +0200
Subject: ssh, public_key: use pubkey encode/decode in app public_key

---
 lib/public_key/src/pubkey_ssh.erl      | 71 ++++++++++++++++++++--------------
 lib/public_key/src/public_key.erl      |  6 ++-
 lib/ssh/src/ssh_auth.erl               | 68 ++++++++------------------------
 lib/ssh/src/ssh_connection_handler.erl |  1 -
 lib/ssh/src/ssh_message.erl            | 49 ++++-------------------
 lib/ssh/src/ssh_transport.erl          | 13 +++++--
 6 files changed, 78 insertions(+), 130 deletions(-)

diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index 3addbfe3c6..ba67abb4eb 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -54,6 +54,8 @@ decode(Bin, public_key)->
     end;
 decode(Bin, rfc4716_public_key) ->
     rfc4716_decode(Bin);
+decode(Bin, ssh2_pubkey) ->
+    ssh2_pubkey_decode(Bin);
 decode(Bin, Type) ->
     openssh_decode(Bin, Type).
 
@@ -63,6 +65,8 @@ decode(Bin, Type) ->
 %%
 %% Description: Encodes a list of ssh file entries.
 %%--------------------------------------------------------------------
+encode(Bin, ssh2_pubkey) ->
+    ssh2_pubkey_encode(Bin);
 encode(Entries, Type) ->
     iolist_to_binary(lists:map(fun({Key, Attributes}) ->
 					      do_encode(Type, Key, Attributes)
@@ -221,36 +225,13 @@ decode_comment(Comment) ->
     [{comment, string_decode(iolist_to_binary(Comment))}].
 
 
-openssh_pubkey_decode(<<"ssh-rsa">>, Base64Enc) ->
-    <<?UINT32(StrLen), _:StrLen/binary,
-      ?UINT32(SizeE), E:SizeE/binary,
-      ?UINT32(SizeN), N:SizeN/binary>>
-	= base64:mime_decode(Base64Enc),
-    #'RSAPublicKey'{modulus = erlint(SizeN, N),
-		    publicExponent = erlint(SizeE, E)};
-
-openssh_pubkey_decode(<<"ssh-dss">>, Base64Enc) ->
-    <<?UINT32(StrLen), _:StrLen/binary,
-      ?UINT32(SizeP), P:SizeP/binary,
-      ?UINT32(SizeQ), Q:SizeQ/binary,
-      ?UINT32(SizeG), G:SizeG/binary,
-      ?UINT32(SizeY), Y:SizeY/binary>>
-	= base64:mime_decode(Base64Enc),
-    {erlint(SizeY, Y),
-     #'Dss-Parms'{p = erlint(SizeP, P),
-		  q = erlint(SizeQ, Q),
-		  g = erlint(SizeG, G)}};
-
-openssh_pubkey_decode(<<"ecdsa-sha2-", Id/binary>>, Base64Enc) ->
-    %% rfc5656#section-3.1
-    <<?UINT32(StrLen), _:StrLen/binary,
-      ?UINT32(SizeId), Id:SizeId/binary,
-      ?UINT32(SizeQ), Q:SizeQ/binary>>
-	= base64:mime_decode(Base64Enc),
-    {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}};
-
-openssh_pubkey_decode(KeyType, Base64Enc) ->
-    {KeyType, base64:mime_decode(Base64Enc)}.
+openssh_pubkey_decode(Type,  Base64Enc) ->
+    try
+	ssh2_pubkey_decode(Type,  base64:mime_decode(Base64Enc))
+    catch
+	_:_ ->
+	    {Type, base64:mime_decode(Base64Enc)}
+    end.
 
 
 erlint(MPIntSize, MPIntValue) ->
@@ -416,6 +397,36 @@ ssh2_pubkey_encode(Key={#'ECPoint'{point = Q}, {namedCurve,OID}}) ->
       (string(IdB))/binary,
       (string(Q))/binary>>.
 
+
+ssh2_pubkey_decode(Bin = <<?UINT32(Len), Type:Len/binary, _/binary>>) ->
+    ssh2_pubkey_decode(Type, Bin).
+
+ssh2_pubkey_decode(<<"ssh-rsa">>,
+		   <<?UINT32(Len),   _:Len/binary,
+		     ?UINT32(SizeE), E:SizeE/binary,
+		     ?UINT32(SizeN), N:SizeN/binary>>) ->
+    #'RSAPublicKey'{modulus = erlint(SizeN, N),
+		    publicExponent = erlint(SizeE, E)};
+
+ssh2_pubkey_decode(<<"ssh-dss">>,
+		   <<?UINT32(Len),   _:Len/binary,
+		     ?UINT32(SizeP), P:SizeP/binary,
+		     ?UINT32(SizeQ), Q:SizeQ/binary,
+		     ?UINT32(SizeG), G:SizeG/binary,
+		     ?UINT32(SizeY), Y:SizeY/binary>>) ->
+    {erlint(SizeY, Y),
+     #'Dss-Parms'{p = erlint(SizeP, P),
+		  q = erlint(SizeQ, Q),
+		  g = erlint(SizeG, G)}};
+ssh2_pubkey_decode(<<"ecdsa-sha2-",Id/binary>>,
+		   <<?UINT32(Len), ECDSA_SHA2_etc:Len/binary,
+		     ?UINT32(SizeId), Id:SizeId/binary,
+		     ?UINT32(SizeQ), Q:SizeQ/binary>>) ->
+    <<"ecdsa-sha2-", Id/binary>> = ECDSA_SHA2_etc,
+    {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}}.
+
+
+
 is_key_field(<<"ssh-dss">>) ->  true;
 is_key_field(<<"ssh-rsa">>) ->  true;
 is_key_field(<<"ecdsa-sha2-",Id/binary>>) -> is_ssh_curvename(Id);
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 2b04b3f79b..941ade3dd7 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -725,7 +725,8 @@ ssh_decode(SshBin, Type) when is_binary(SshBin),
 			      Type == rfc4716_public_key;
 			      Type == openssh_public_key;
 			      Type == auth_keys;
-			      Type == known_hosts ->
+			      Type == known_hosts;
+			      Type == ssh2_pubkey ->
     pubkey_ssh:decode(SshBin, Type).
 
 %%--------------------------------------------------------------------
@@ -739,7 +740,8 @@ ssh_encode(Entries, Type) when is_list(Entries),
 			       Type == rfc4716_public_key;
 			       Type == openssh_public_key;
 			       Type == auth_keys;
-			       Type == known_hosts ->
+			       Type == known_hosts;
+			       Type == ssh2_pubkey ->
     pubkey_ssh:encode(Entries, Type).
 
 %%--------------------------------------------------------------------
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 8c6ffceb4b..04749fcf8e 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -44,15 +44,15 @@ publickey_msg([Alg, #ssh{user = User,
     Hash = sha, %% Maybe option?!
     KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
     case KeyCb:user_key(Alg, Opts) of
-	{ok, Key} ->
-	    StrAlgo = algorithm_string(Alg),
-            case encode_public_key(StrAlgo, Key) of
+	{ok, PrivKey} ->
+	    StrAlgo = atom_to_list(Alg),
+            case encode_public_key(StrAlgo, ssh_transport:extract_public_key(PrivKey)) of
 		not_ok ->
 		    not_ok;
 		PubKeyBlob ->
 		    SigData = build_sig_data(SessionId, 
 					     User, Service, PubKeyBlob, StrAlgo),
-		    Sig = ssh_transport:sign(SigData, Hash, Key),
+		    Sig = ssh_transport:sign(SigData, Hash, PrivKey),
 		    SigBlob = list_to_binary([?string(StrAlgo), ?binary(Sig)]),
 		    ssh_transport:ssh_packet(
 		      #ssh_msg_userauth_request{user = User,
@@ -430,12 +430,6 @@ build_sig_data(SessionId, User, Service, KeyBlob, Alg) ->
 	   ?binary(KeyBlob)],
     list_to_binary(Sig).
 
-algorithm_string('ssh-rsa') -> "ssh-rsa";
-algorithm_string('ssh-dss') -> "ssh-dss";
-algorithm_string('ecdsa-sha2-nistp256') -> "ecdsa-sha2-nistp256";
-algorithm_string('ecdsa-sha2-nistp384') -> "ecdsa-sha2-nistp384";
-algorithm_string('ecdsa-sha2-nistp521') -> "ecdsa-sha2-nistp521".
-
 
 
 decode_keyboard_interactive_prompts(_NumPrompts, Data) ->
@@ -487,46 +481,18 @@ keyboard_interact_fun(KbdInteractFun, Name, Instr,  PromptInfos, NumPrompts) ->
 				       language = "en"}})
     end.
 
-decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary,
-		       ?UINT32(Len1), E:Len1/big-signed-integer-unit:8,
-		       ?UINT32(Len2), N:Len2/big-signed-integer-unit:8>>
-			 ,"ssh-rsa") ->
-    {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}};
-decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary,
-		       ?UINT32(Len1), P:Len1/big-signed-integer-unit:8,
-		       ?UINT32(Len2), Q:Len2/big-signed-integer-unit:8,
-		       ?UINT32(Len3), G:Len3/big-signed-integer-unit:8,
-		       ?UINT32(Len4), Y:Len4/big-signed-integer-unit:8>>
-			 , "ssh-dss") ->
-    {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}};
-decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary,
-		       ?UINT32(Len1), IdB:Len1/binary, %% Id = <<"nistp256">> for example
-		       ?UINT32(Len2), Blob:Len2/binary>>,
-		     "ecdsa-sha2-" ++ IdS) -> 
-    case binary_to_list(IdB) of
-	IdS ->
-	    {ok, {#'ECPoint'{point=Blob}, {namedCurve,public_key:ssh_curvename2oid(IdB)}} };
-	_ ->
-	    {error, bad_format}
-    end;
-decode_public_key_v2(_, _) ->
-    {error, bad_format}.
-
-encode_public_key("ssh-rsa", #'RSAPrivateKey'{publicExponent = E, modulus = N}) ->
-    ssh_bits:encode(["ssh-rsa",E,N], [string,mpint,mpint]);
-encode_public_key("ssh-dss", #'DSAPrivateKey'{p = P, q = Q, g = G, y = Y}) ->
-    ssh_bits:encode(["ssh-dss",P,Q,G,Y], [string,mpint,mpint,mpint,mpint]);
-encode_public_key("ecdsa-sha2-"++Curve, #'ECPrivateKey'{parameters = Params,
-							publicKey = Pub}) ->
-    Id = ecdsa_id(Params),
-    if
-	Id =/= Curve ->
-	    not_ok;
-	true ->
-	    ssh_bits:encode(["ecdsa-sha2-"++Id, Id, Pub],
-			    [string, string, binary])
+decode_public_key_v2(Bin, _Type) ->
+    try 
+	public_key:ssh_decode(Bin, ssh2_pubkey)
+    of
+	Key -> {ok, Key}
+    catch
+	_:_ -> {error, bad_format}
     end.
 
-ecdsa_id({namedCurve,?'secp256r1'}) -> "nistp256";
-ecdsa_id({namedCurve,?'secp384r1'}) -> "nistp384";
-ecdsa_id({namedCurve,?'secp521r1'}) -> "nistp521".
+encode_public_key(_Alg, Key) ->
+    try
+	public_key:ssh_encode(Key, ssh2_pubkey)
+    catch
+	_:_ -> not_ok
+    end.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 09ef03f3f8..7fb86c1108 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1348,7 +1348,6 @@ event(Event, StateName, State) ->
 	throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg}  ->
 	    handle_disconnect(DisconnectMsg, State, ErrorToDisplay);
 	_C:_Error ->
-ct:pal("*** FAIL ~p:~p(~p,...~n -> ~p:~p ",[?MODULE,StateName,Event,_C,_Error]),
 	    handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName),
 						  description = "Invalid state",
 						  language = "en"}, State)
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 42e9b27b93..b6c4496be2 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -30,7 +30,7 @@
 -include("ssh_auth.hrl").
 -include("ssh_transport.hrl").
 
--export([encode/1, decode/1, encode_host_key/1, decode_keyboard_interactive_prompts/2]).
+-export([encode/1, decode/1, decode_keyboard_interactive_prompts/2]).
 
 encode(#ssh_msg_global_request{
 	  name = Name,
@@ -227,7 +227,7 @@ encode(#ssh_msg_kexdh_reply{
 	  f = F,
 	  h_sig = Signature
 	 }) ->
-    EncKey = encode_host_key(Key),
+    EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
     EncSign = encode_signature(Key, Signature),
     ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
 
@@ -255,7 +255,7 @@ encode(#ssh_msg_kex_dh_gex_reply{
 	  f = F,
 	  h_sig = Signature
 	 }) ->
-    EncKey = encode_host_key(Key),
+    EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
     EncSign = encode_signature(Key, Signature),
     ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
 
@@ -263,7 +263,7 @@ encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
     ssh_bits:encode([?SSH_MSG_KEX_ECDH_INIT, Q_c], [byte, mpint]);
 
 encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) ->
-    EncKey = encode_host_key(Key),
+    EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
     EncSign = encode_signature(Key, Sign),
     ssh_bits:encode([?SSH_MSG_KEX_ECDH_REPLY, EncKey, Q_s, EncSign], [byte, binary, mpint, binary]);
 
@@ -428,7 +428,7 @@ decode(<<"dh",?BYTE(?SSH_MSG_KEXDH_INIT), ?DEC_MPINT(E,__0)>>) ->
 
 decode(<<"dh", ?BYTE(?SSH_MSG_KEXDH_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) ->
     #ssh_msg_kexdh_reply{
-       public_host_key = decode_host_key(Key),
+       public_host_key = public_key:ssh_decode(Key, ssh2_pubkey),
        f = F,
        h_sig = decode_signature(Hashsign)
       };
@@ -458,7 +458,7 @@ decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_INIT), ?DEC_MPINT(E,__0)>>) ->
 
 decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1), ?DEC_BIN(Hashsign,__2)>>) ->
     #ssh_msg_kex_dh_gex_reply{
-       public_host_key = decode_host_key(Key),
+       public_host_key = public_key:ssh_decode(Key, ssh2_pubkey),
        f = F,
        h_sig = decode_signature(Hashsign)
       };
@@ -471,7 +471,7 @@ decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_MPINT(Q_c,__0)>>) ->
 decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
 	 ?DEC_BIN(Key,__1), ?DEC_MPINT(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->
     #ssh_msg_kex_ecdh_reply{
-       public_host_key = decode_host_key(Key),
+       public_host_key = public_key:ssh_decode(Key, ssh2_pubkey),
        q_s = Q_s,
        h_sig = decode_signature(Sig)
       };
@@ -543,41 +543,6 @@ decode_kex_init(<<?DEC_BIN(Data,__0), Rest/binary>>, Acc, N) ->
     decode_kex_init(Rest, [Names | Acc], N -1).
 
 
-%%%================================================================
-%%%
-%%% Host key decode/encode
-%%%
-
-decode_host_key(<<?DEC_BIN(Alg,__0), Rest/binary>>) -> decode_host_key(Alg, Rest).
-
-
-decode_host_key(<<"ssh-rsa">>, <<?DEC_MPINT(E,__0), ?DEC_MPINT(N,__1)>>) ->
-    #'RSAPublicKey'{publicExponent = E,
-		    modulus = N};
-decode_host_key(<<"ssh-dss">>,
-		<<?DEC_MPINT(P,__0),
-		  ?DEC_MPINT(Q,__1),
-		  ?DEC_MPINT(G,__2),
-		  ?DEC_MPINT(Y,__3)>>) ->
-    {Y, #'Dss-Parms'{p = P,
-		     q = Q,
-		     g = G}};
-decode_host_key(<<"ecdsa-sha2-",Id/binary>>,
-		<<?DEC_BIN(Id,__0), %% Id = <<"nistp256">> for example
-		  ?DEC_BIN(Blob,__1)>>) ->
-    {#'ECPoint'{point=Blob}, {namedCurve,public_key:ssh_curvename2oid(Id)}}.
-
-
-encode_host_key(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
-    ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]);
-encode_host_key({Y,  #'Dss-Parms'{p = P, q = Q, g = G}}) ->
-    ssh_bits:encode(["ssh-dss", P, Q, G, Y],
-		    [string, mpint, mpint, mpint, mpint]);
-encode_host_key({#'ECPoint'{point = Q}, {namedCurve,OID}}) ->
-    CurveName = public_key:oid2ssh_curvename(OID),
-    ssh_bits:encode([<<"ecdsa-sha2-",CurveName/binary>>,CurveName,Q], [binary,binary,binary]).
-
-
 %%%================================================================
 %%%
 %%% Signature decode/encode
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 080d6f74f7..500db91df5 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -44,6 +44,7 @@
 	 handle_kexdh_reply/2, 
 	 handle_kex_ecdh_init/2,
 	 handle_kex_ecdh_reply/2,
+	 extract_public_key/1,
 	 unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1,
 	 sign/3, verify/4]).
 
@@ -1344,38 +1345,42 @@ hash(K, H, Ki, N, HASH) ->
     hash(K, H, <<Ki/binary, Kj/binary>>, N-128, HASH).
 
 kex_h(SSH, Key, E, F, K) ->
+    KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
     L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
 			 SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
-			 ssh_message:encode_host_key(Key), E,F,K],
+			 KeyBin, E,F,K],
 			[string,string,binary,binary,binary,
 			 mpint,mpint,mpint]),
     crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
 %%  crypto:hash(sha,L).
 
 kex_h(SSH, Curve, Key, Q_c, Q_s, K) ->
+    KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
     L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
 			 SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
-			 ssh_message:encode_host_key(Key), Q_c, Q_s, K],
+			 KeyBin, Q_c, Q_s, K],
 			[string,string,binary,binary,binary,
 			 mpint,mpint,mpint]),
     crypto:hash(sha(Curve), L).
 
 kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
     L = if Min==-1; Max==-1 ->
+		KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
 		Ts = [string,string,binary,binary,binary,
 		      uint32,
 		      mpint,mpint,mpint,mpint,mpint],
 		ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version,
 				 SSH#ssh.c_keyinit,SSH#ssh.s_keyinit,
-				 ssh_message:encode_host_key(Key), NBits, Prime, Gen, E,F,K],
+				 KeyBin, NBits, Prime, Gen, E,F,K],
 				Ts);
 	   true ->
+		KeyBin = public_key:ssh_encode(Key, ssh2_pubkey),
 		Ts = [string,string,binary,binary,binary,
 		      uint32,uint32,uint32,
 		      mpint,mpint,mpint,mpint,mpint],
 		ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version,
 				 SSH#ssh.c_keyinit,SSH#ssh.s_keyinit,
-				 ssh_message:encode_host_key(Key), Min, NBits, Max,
+				 KeyBin, Min, NBits, Max,
 				 Prime, Gen, E,F,K], Ts)
 	end,
     crypto:hash(sha((SSH#ssh.algorithms)#alg.kex), L).
-- 
cgit v1.2.3


From 255f36937752404038f32ca67f438f13ef8ce4fb Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Thu, 15 Oct 2015 10:25:19 +0200
Subject: public_key: add/update -spec for ssh functions

---
 lib/public_key/src/pubkey_ssh.erl |  8 ++++++--
 lib/public_key/src/public_key.erl | 14 +++++++++++---
 lib/ssh/src/ssh_transport.erl     | 18 ++++++++----------
 3 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index ba67abb4eb..82042550a0 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -41,7 +41,9 @@
 
 %%--------------------------------------------------------------------
 -spec decode(binary(), public_key | public_key:ssh_file()) -> 
-		    [{public_key:public_key(), Attributes::list()}].
+		    [{public_key:public_key(), Attributes::list()}]
+	  ; (binary(), ssh2_pubkey) ->  public_key:public_key()
+	  .
 %%
 %% Description: Decodes a ssh file-binary.
 %%--------------------------------------------------------------------
@@ -61,7 +63,9 @@ decode(Bin, Type) ->
 
 %%--------------------------------------------------------------------
 -spec encode([{public_key:public_key(), Attributes::list()}], public_key:ssh_file()) ->
-		    binary().
+		    binary()
+	  ; (public_key:public_key(), ssh2_pubkey) -> binary()
+	  .
 %%
 %% Description: Encodes a list of ssh file entries.
 %%--------------------------------------------------------------------
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 941ade3dd7..8288f68f7f 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -712,7 +712,9 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
 
 
 %%--------------------------------------------------------------------
--spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}].
+-spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]
+	      ; (binary(), ssh2_pubkey) ->  public_key()
+	      .
 %%
 %% Description: Decodes a ssh file-binary. In the case of know_hosts
 %% or auth_keys the binary may include one or more lines of the
@@ -730,8 +732,10 @@ ssh_decode(SshBin, Type) when is_binary(SshBin),
     pubkey_ssh:decode(SshBin, Type).
 
 %%--------------------------------------------------------------------
--spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) ->
-			binary().
+-spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) -> binary()
+	      ; (public_key(), ssh2_pubkey) -> binary()
+	      .
+%%
 %% Description: Encodes a list of ssh file entries (public keys and
 %% attributes) to a binary. Possible attributes depends on the file
 %% type.
@@ -745,6 +749,8 @@ ssh_encode(Entries, Type) when is_list(Entries),
     pubkey_ssh:encode(Entries, Type).
 
 %%--------------------------------------------------------------------
+-spec ssh_curvename2oid(binary()) -> oid().
+
 %% Description: Converts from the ssh name of elliptic curves to
 %% the OIDs.
 %%--------------------------------------------------------------------
@@ -753,6 +759,8 @@ ssh_curvename2oid(<<"nistp384">>) ->  ?'secp384r1';
 ssh_curvename2oid(<<"nistp521">>) ->  ?'secp521r1'.
 
 %%--------------------------------------------------------------------
+-spec oid2ssh_curvename(oid()) -> binary().
+
 %% Description: Converts from elliptic curve OIDs to the ssh name.
 %%--------------------------------------------------------------------
 oid2ssh_curvename(?'secp256r1') -> <<"nistp256">>;
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 500db91df5..d8574877f2 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -66,8 +66,8 @@ default_algorithms() -> [{K,default_algorithms(K)} || K <- algo_classes()].
 
 algo_classes() -> [kex, public_key, cipher, mac, compression].
 
-default_algorithms(kex) -> 
-    supported_algorithms(kex, []); %% Just to have a call to supported_algorithms/2
+%% default_algorithms(kex) -> % Example of how to disable an algorithm
+%%     supported_algorithms(kex, ['ecdh-sha2-nistp521']);
 default_algorithms(Alg) ->
     supported_algorithms(Alg).
 
@@ -118,11 +118,11 @@ supported_algorithms(compression) ->
 	  'zlib'
 	 ]).
 
-supported_algorithms(Key, [{client2server,BL1},{server2client,BL2}]) ->
-    [{client2server,As1},{server2client,As2}] = supported_algorithms(Key),
-    [{client2server,As1--BL1},{server2client,As2--BL2}];
-supported_algorithms(Key, BlackList) ->
-    supported_algorithms(Key) -- BlackList.
+%% Dialyzer complains when not called...supported_algorithms(Key, [{client2server,BL1},{server2client,BL2}]) ->
+%% Dialyzer complains when not called...    [{client2server,As1},{server2client,As2}] = supported_algorithms(Key),
+%% Dialyzer complains when not called...    [{client2server,As1--BL1},{server2client,As2--BL2}];
+%% Dialyzer complains when not called...supported_algorithms(Key, BlackList) ->
+%% Dialyzer complains when not called...    supported_algorithms(Key) -- BlackList.
 
 select_crypto_supported(L) ->    
     Sup = [{ec_curve,crypto_supported_curves()} | crypto:supports()],
@@ -329,9 +329,7 @@ verify_algorithm(#alg{encrypt = undefined}) -> false;
 verify_algorithm(#alg{decrypt = undefined}) -> false;
 verify_algorithm(#alg{compress = undefined}) -> false;
 verify_algorithm(#alg{decompress = undefined}) -> false;
-
-verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex));
-verify_algorithm(_) -> false.
+verify_algorithm(#alg{kex = Kex}) -> lists:member(Kex, supported_algorithms(kex)).
 
 %%%----------------------------------------------------------------
 %%%
-- 
cgit v1.2.3


From 6af1014df69b4b2c019aead2435e537c20a39f15 Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Thu, 15 Oct 2015 18:44:11 +0200
Subject: ssh: Implemented ssh_transport:ecdh_validate_public_key (partly)

Defined in http://www.secg.org/sec1-v2.pdf '3.2.2 Validation of Elliptic Curve Public Keys'
according to RFC 5656 ch 4.

More to be done: check singularities, implement reading compressed points....
---
 lib/ssh/src/ssh_transport.erl | 56 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index d8574877f2..8b65806dc6 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -625,7 +625,61 @@ handle_kex_ecdh_reply(#ssh_msg_kex_ecdh_reply{public_host_key = PeerPubHostKey,
     end.
 
 
-ecdh_validate_public_key(_, _) -> true.		% FIXME: Far too many false positives :)
+%%%----------------------------------------------------------------
+%%%
+%%% Standards for Efficient Cryptography Group, "Elliptic Curve Cryptography", SEC 1
+%%% Section 3.2.2.1
+%%%
+
+ecdh_validate_public_key(Key, Curve) ->
+    case key_size(Curve) of
+	undefined ->
+	    false;
+
+	Sz ->
+	    case dec_key(Key, Sz) of
+		{ok,Q} ->
+		    case crypto:ec_curve(Curve) of
+			{{prime_field,P}, {A, B, _Seed},
+			 _P0Bin, _OrderBin, _CoFactorBin} ->
+			    on_curve(Q, bin2int(A), bin2int(B), bin2int(P))
+		    end;
+
+		{error,compressed_not_implemented} -> % Be a bit generous...
+		    true;
+
+		_Error -> 
+		    false
+	    end
+    end.
+
+
+on_curve({X,Y}, A, B, P) when 0 =< X,X =< (P-1),
+			      0 =< Y,Y =< (P-1) ->
+    %% Section 3.2.2.1, point 2
+    (Y*Y) rem P == (X*X*X + A*X + B) rem P;
+on_curve(_, _, _, _) ->
+    false.
+
+
+bin2int(B) ->
+    Sz = erlang:bit_size(B),
+    <<I:Sz/big-unsigned-integer>> = B,
+    I.
+
+key_size(secp256r1) -> 256;
+key_size(secp384r1) -> 384;
+key_size(secp521r1) -> 528; % Round 521 up to closest 8-bits.
+key_size(_) -> undefined.
+
+
+dec_key(Key, NBits) ->
+    Size = 8 + 2*NBits,
+    case <<Key:Size>> of
+	<<4:8, X:NBits, Y:NBits>> -> {ok,{X,Y}};
+	<<4:8, _/binary>> -> {error,bad_format};
+	_ -> {error,compressed_not_implemented}
+    end.
 
 %%%----------------------------------------------------------------
 handle_new_keys(#ssh_msg_newkeys{}, Ssh0) ->
-- 
cgit v1.2.3