aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2017-10-16 12:02:05 +0200
committerHans Nilsson <[email protected]>2017-10-16 12:02:05 +0200
commit21fd1710a483fd6f0438feb89c6790b0fcf800bd (patch)
tree898e08bfc204c06c894ecf74c0db87d6537900e9
parent73f84b3df40f49df6a99d72696cd34b42020774b (diff)
parent667d1e91f10832ea5c90ab049cdab6e8dd77b60b (diff)
downloadotp-21fd1710a483fd6f0438feb89c6790b0fcf800bd.tar.gz
otp-21fd1710a483fd6f0438feb89c6790b0fcf800bd.tar.bz2
otp-21fd1710a483fd6f0438feb89c6790b0fcf800bd.zip
Merge branch 'hans/public_key/ssh2_pubkey_generate_fix/OTP-14570' into maint
-rw-r--r--lib/public_key/src/pubkey_ssh.erl138
-rw-r--r--lib/public_key/src/public_key.erl1
-rw-r--r--lib/ssh/src/ssh_message.erl20
-rw-r--r--lib/ssh/src/ssh_transport.erl30
4 files changed, 69 insertions, 120 deletions
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index 75c1880655..a7d018e440 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -29,7 +29,15 @@
]).
-define(UINT32(X), X:32/unsigned-big-integer).
--define(STRING(X), ?UINT32((size(X))), (X)/binary).
+-define(STRING(X), ?UINT32((byte_size(X))), (X)/binary).
+
+-define(DEC_BIN(X,Len), ?UINT32(Len), X:Len/binary ).
+-define(DEC_MPINT(I,Len), ?DEC_INT(I,Len) ).
+-define(DEC_INT(I,Len), ?UINT32(Len), I:Len/big-signed-integer-unit:8 ).
+
+-define(Empint(X), (mpint(X))/binary ).
+-define(Estring(X), (string(X))/binary ).
+
%% Max encoded line length is 72, but conformance examples use 68
%% Comment from rfc 4716: "The following are some examples of public
@@ -47,12 +55,12 @@
%% Description: Decodes a ssh file-binary.
%%--------------------------------------------------------------------
decode(Bin, public_key)->
- case binary:match(Bin, begin_marker()) of
- nomatch ->
- openssh_decode(Bin, openssh_public_key);
- _ ->
- rfc4716_decode(Bin)
- end;
+ PKtype =
+ case binary:match(Bin, begin_marker()) of
+ nomatch -> openssh_public_key;
+ _ -> rfc4716_public_key
+ end,
+ decode(Bin, PKtype);
decode(Bin, rfc4716_public_key) ->
rfc4716_decode(Bin);
decode(Bin, ssh2_pubkey) ->
@@ -164,26 +172,8 @@ join_entry([Line | Lines], Entry) ->
join_entry(Lines, [Line | Entry]).
-rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary,
- ?UINT32(SizeE), E:SizeE/binary,
- ?UINT32(SizeN), N:SizeN/binary>>) when Type == <<"ssh-rsa">> ->
- #'RSAPublicKey'{modulus = erlint(SizeN, N),
- publicExponent = erlint(SizeE, E)};
-
-rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary,
- ?UINT32(SizeP), P:SizeP/binary,
- ?UINT32(SizeQ), Q:SizeQ/binary,
- ?UINT32(SizeG), G:SizeG/binary,
- ?UINT32(SizeY), Y:SizeY/binary>>) when Type == <<"ssh-dss">> ->
- {erlint(SizeY, Y),
- #'Dss-Parms'{p = erlint(SizeP, P),
- q = erlint(SizeQ, Q),
- g = erlint(SizeG, G)}};
-rfc4716_pubkey_decode(<<?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)}}.
+rfc4716_pubkey_decode(BinKey) -> ssh2_pubkey_decode(BinKey).
+
openssh_decode(Bin, FileType) ->
Lines = binary:split(Bin, <<"\n">>, [global]),
@@ -267,18 +257,14 @@ decode_comment(Comment) ->
openssh_pubkey_decode(Type, Base64Enc) ->
try
- ssh2_pubkey_decode(Type, base64:mime_decode(Base64Enc))
+ <<?DEC_BIN(Type,_TL), Bin/binary>> = base64:mime_decode(Base64Enc),
+ ssh2_pubkey_decode(Type, Bin)
catch
_:_ ->
{Type, base64:mime_decode(Base64Enc)}
end.
-erlint(MPIntSize, MPIntValue) ->
- Bits= MPIntSize * 8,
- <<Integer:Bits/integer>> = MPIntValue,
- Integer.
-
ssh1_rsa_pubkey_decode(MBin, EBin) ->
#'RSAPublicKey'{modulus = integer_decode(MBin),
publicExponent = integer_decode(EBin)}.
@@ -411,71 +397,37 @@ comma_list_encode([Option | Rest], Acc) ->
ssh2_pubkey_encode(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
- ssh2_pubkey_encode({#'RSAPublicKey'{modulus = N, publicExponent = E}, 'ssh-rsa'});
-
-ssh2_pubkey_encode({Key, 'rsa-sha2-256'}) -> ssh2_pubkey_encode({Key, 'ssh-rsa'});
-ssh2_pubkey_encode({Key, 'rsa-sha2-512'}) -> ssh2_pubkey_encode({Key, 'ssh-rsa'});
-ssh2_pubkey_encode({#'RSAPublicKey'{modulus = N, publicExponent = E}, SignAlg}) ->
- SignAlgName = list_to_binary(atom_to_list(SignAlg)),
- StrLen = size(SignAlgName),
- EBin = mpint(E),
- NBin = mpint(N),
- <<?UINT32(StrLen), SignAlgName:StrLen/binary,
- EBin/binary,
- NBin/binary>>;
-ssh2_pubkey_encode({{_,#'Dss-Parms'{}}=Key, _}) ->
- ssh2_pubkey_encode(Key);
+ <<?STRING(<<"ssh-rsa">>), ?Empint(E), ?Empint(N)>>;
ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
- TypeStr = <<"ssh-dss">>,
- StrLen = size(TypeStr),
- PBin = mpint(P),
- QBin = mpint(Q),
- GBin = mpint(G),
- YBin = mpint(Y),
- <<?UINT32(StrLen), TypeStr:StrLen/binary,
- PBin/binary,
- QBin/binary,
- GBin/binary,
- YBin/binary>>;
-ssh2_pubkey_encode({{#'ECPoint'{},_}=Key, _}) ->
- ssh2_pubkey_encode(Key);
+ <<?STRING(<<"ssh-dss">>), ?Empint(P), ?Empint(Q), ?Empint(G), ?Empint(Y)>>;
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(IdB))/binary,
- (string(Q))/binary>>.
+ Curve = public_key:oid2ssh_curvename(OID),
+ <<?STRING(key_type(Key)), ?Estring(Curve), ?Estring(Q)>>.
-ssh2_pubkey_decode(Bin = <<?UINT32(Len), Type:Len/binary, _/binary>>) ->
+ssh2_pubkey_decode(<<?DEC_BIN(Type,_TL), Bin/binary>>) ->
ssh2_pubkey_decode(Type, Bin).
-ssh2_pubkey_decode(<<"rsa-sha2-256">>, Bin) -> ssh2_pubkey_decode(<<"ssh-rsa">>, Bin);
-ssh2_pubkey_decode(<<"rsa-sha2-512">>, Bin) -> ssh2_pubkey_decode(<<"ssh-rsa">>, Bin);
+%% ssh2_pubkey_decode(<<"rsa-sha2-256">>, Bin) -> ssh2_pubkey_decode(<<"ssh-rsa">>, Bin);
+%% ssh2_pubkey_decode(<<"rsa-sha2-512">>, Bin) -> ssh2_pubkey_decode(<<"ssh-rsa">>, 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)};
+ <<?DEC_INT(E, _EL),
+ ?DEC_INT(N, _NL)>>) ->
+ #'RSAPublicKey'{modulus = N,
+ publicExponent = 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)}};
+ <<?DEC_INT(P, _PL),
+ ?DEC_INT(Q, _QL),
+ ?DEC_INT(G, _GL),
+ ?DEC_INT(Y, _YL)>>) ->
+ {Y, #'Dss-Parms'{p = P,
+ q = Q,
+ g = 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,
+ <<?DEC_BIN(Id, _IL),
+ ?DEC_BIN(Q, _QL)>>) ->
{#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}}.
@@ -575,17 +527,16 @@ mpint(X) -> mpint_pos(X).
mpint_neg(X) ->
Bin = int_to_bin_neg(X, []),
- Sz = byte_size(Bin),
- <<?UINT32(Sz), Bin/binary>>.
+ <<?STRING(Bin)>>.
mpint_pos(X) ->
Bin = int_to_bin_pos(X, []),
<<MSB,_/binary>> = Bin,
- Sz = byte_size(Bin),
if MSB band 16#80 == 16#80 ->
- <<?UINT32((Sz+1)), 0, Bin/binary>>;
+ B = << 0, Bin/binary>>,
+ <<?STRING(B)>>;
true ->
- <<?UINT32(Sz), Bin/binary>>
+ <<?STRING(Bin)>>
end.
int_to_bin_pos(0,Ds=[_|_]) ->
@@ -602,7 +553,8 @@ int_to_bin_neg(X,Ds) ->
string(X) when is_binary(X) ->
<< ?STRING(X) >>;
string(X) ->
- << ?STRING(list_to_binary(X)) >>.
+ B = list_to_binary(X),
+ << ?STRING(B) >>.
is_ssh_curvename(Id) -> try public_key:ssh_curvename2oid(Id) of _ -> true
catch _:_ -> false
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 453f34de64..c6ab4d06ae 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -942,7 +942,6 @@ ssh_decode(SshBin, Type) when is_binary(SshBin),
%%--------------------------------------------------------------------
-spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) -> binary()
; (public_key(), ssh2_pubkey) -> binary()
- ; ({public_key(),atom()}, ssh2_pubkey) -> binary()
.
%%
%% Description: Encodes a list of ssh file entries (public keys and
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index b1fc05ae33..eb06f05a4a 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -252,12 +252,12 @@ encode(#ssh_msg_kexdh_init{e = E}) ->
<<?Ebyte(?SSH_MSG_KEXDH_INIT), ?Empint(E)>>;
encode(#ssh_msg_kexdh_reply{
- public_host_key = Key,
+ public_host_key = {Key,SigAlg},
f = F,
h_sig = Signature
}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
- EncSign = encode_signature(Key, Signature),
+ EncSign = encode_signature(Key, SigAlg, Signature),
<<?Ebyte(?SSH_MSG_KEXDH_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
encode(#ssh_msg_kex_dh_gex_request{
@@ -278,20 +278,20 @@ encode(#ssh_msg_kex_dh_gex_init{e = Public}) ->
encode(#ssh_msg_kex_dh_gex_reply{
%% Will be private key encode_host_key extracts only the public part!
- public_host_key = Key,
+ public_host_key = {Key,SigAlg},
f = F,
h_sig = Signature
}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
- EncSign = encode_signature(Key, Signature),
+ EncSign = encode_signature(Key, SigAlg, Signature),
<<?Ebyte(?SSH_MSG_KEX_DH_GEX_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
<<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Empint(Q_c)>>;
-encode(#ssh_msg_kex_ecdh_reply{public_host_key = Key, q_s = Q_s, h_sig = Sign}) ->
+encode(#ssh_msg_kex_ecdh_reply{public_host_key = {Key,SigAlg}, q_s = Q_s, h_sig = Sign}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
- EncSign = encode_signature(Key, Sign),
+ EncSign = encode_signature(Key, SigAlg, Sign),
<<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Empint(Q_s), ?Ebinary(EncSign)>>;
encode(#ssh_msg_ignore{data = Data}) ->
@@ -602,12 +602,12 @@ decode_signature(<<?DEC_BIN(Alg,__0), ?UINT32(_), Signature/binary>>) ->
{binary_to_list(Alg), Signature}.
-encode_signature({#'RSAPublicKey'{},Sign}, Signature) ->
- SignName = list_to_binary(atom_to_list(Sign)),
+encode_signature(#'RSAPublicKey'{}, SigAlg, Signature) ->
+ SignName = list_to_binary(atom_to_list(SigAlg)),
<<?Ebinary(SignName), ?Ebinary(Signature)>>;
-encode_signature({{_, #'Dss-Parms'{}},_}, Signature) ->
+encode_signature({_, #'Dss-Parms'{}}, _SigAlg, Signature) ->
<<?Ebinary(<<"ssh-dss">>), ?Ebinary(Signature)>>;
-encode_signature({{#'ECPoint'{}, {namedCurve,OID}},_}, Signature) ->
+encode_signature({#'ECPoint'{}, {namedCurve,OID}}, _SigAlg, Signature) ->
CurveName = public_key:oid2ssh_curvename(OID),
<<?Ebinary(<<"ecdsa-sha2-",CurveName/binary>>), ?Ebinary(Signature)>>.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 46154cf536..e92c727559 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -426,7 +426,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E},
K = compute_key(dh, E, Private, [P,G]),
MyPrivHostKey = get_host_key(Ssh0, SignAlg),
MyPubHostKey = extract_public_key(MyPrivHostKey),
- H = kex_hash(Ssh0, MyPubHostKey, SignAlg, sha(Kex), {E,Public,K}),
+ H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {E,Public,K}),
H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kexdh_reply{public_host_key = {MyPubHostKey,SignAlg},
@@ -451,13 +451,12 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = PeerPubHostKey,
f = F,
h_sig = H_SIG},
#ssh{keyex_key = {{Private, Public}, {G, P}},
- algorithms = #alg{kex=Kex,
- hkey=SignAlg}} = Ssh0) ->
+ algorithms = #alg{kex=Kex}} = Ssh0) ->
%% client
if
1=<F, F=<(P-1)->
K = compute_key(dh, F, Private, [P,G]),
- H = kex_hash(Ssh0, PeerPubHostKey, SignAlg, sha(Kex), {Public,F,K}),
+ H = kex_hash(Ssh0, PeerPubHostKey, sha(Kex), {Public,F,K}),
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -590,7 +589,7 @@ handle_kex_dh_gex_init(#ssh_msg_kex_dh_gex_init{e = E},
1<K, K<(P-1) ->
MyPrivHostKey = get_host_key(Ssh0, SignAlg),
MyPubHostKey = extract_public_key(MyPrivHostKey),
- H = kex_hash(Ssh0, MyPubHostKey, SignAlg, sha(Kex), {Min,NBits,Max,P,G,E,Public,K}),
+ H = kex_hash(Ssh0, MyPubHostKey, sha(Kex), {Min,NBits,Max,P,G,E,Public,K}),
H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
{SshPacket, Ssh} =
ssh_packet(#ssh_msg_kex_dh_gex_reply{public_host_key = {MyPubHostKey,SignAlg},
@@ -620,8 +619,7 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
h_sig = H_SIG},
#ssh{keyex_key = {{Private, Public}, {G, P}},
keyex_info = {Min, Max, NBits},
- algorithms = #alg{kex=Kex,
- hkey=SignAlg}} =
+ algorithms = #alg{kex=Kex}} =
Ssh0) ->
%% client
if
@@ -629,7 +627,7 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = PeerPubHostK
K = compute_key(dh, F, Private, [P,G]),
if
1<K, K<(P-1) ->
- H = kex_hash(Ssh0, PeerPubHostKey, SignAlg, sha(Kex), {Min,NBits,Max,P,G,Public,F,K}),
+ H = kex_hash(Ssh0, PeerPubHostKey, sha(Kex), {Min,NBits,Max,P,G,Public,F,K}),
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -676,7 +674,7 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
K ->
MyPrivHostKey = get_host_key(Ssh0, SignAlg),
MyPubHostKey = extract_public_key(MyPrivHostKey),
- H = kex_hash(Ssh0, MyPubHostKey, SignAlg, sha(Curve), {PeerPublic, MyPublic, K}),
+ H = kex_hash(Ssh0, MyPubHostKey, sha(Curve), {PeerPublic, MyPublic, K}),
H_SIG = sign(H, sha(SignAlg), MyPrivHostKey),
{SshPacket, Ssh1} =
ssh_packet(#ssh_msg_kex_ecdh_reply{public_host_key = {MyPubHostKey,SignAlg},
@@ -699,15 +697,15 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
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},
- algorithms = #alg{hkey=SignAlg}} = Ssh0
+ #ssh{keyex_key = {{MyPublic,MyPrivate}, Curve}
+ } = Ssh0
) ->
%% at client
try
compute_key(ecdh, PeerPublic, MyPrivate, Curve)
of
K ->
- H = kex_hash(Ssh0, PeerPubHostKey, SignAlg, sha(Curve), {MyPublic,PeerPublic,K}),
+ H = kex_hash(Ssh0, PeerPubHostKey, sha(Curve), {MyPublic,PeerPublic,K}),
case verify_host_key(Ssh0, PeerPubHostKey, H, H_SIG) of
ok ->
{SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0),
@@ -1794,11 +1792,11 @@ hash(K, H, Ki, N, HashAlg) ->
hash(K, H, <<Ki/binary, Kj/binary>>, N-128, HashAlg).
%%%----------------------------------------------------------------
-kex_hash(SSH, Key, SignAlg, HashAlg, Args) ->
- crypto:hash(HashAlg, kex_plaintext(SSH,Key,SignAlg,Args)).
+kex_hash(SSH, Key, HashAlg, Args) ->
+ crypto:hash(HashAlg, kex_plaintext(SSH,Key,Args)).
-kex_plaintext(SSH, Key, SignAlg, Args) ->
- EncodedKey = public_key:ssh_encode({Key,SignAlg}, ssh2_pubkey),
+kex_plaintext(SSH, Key, Args) ->
+ EncodedKey = public_key:ssh_encode(Key, ssh2_pubkey),
<<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
?Ebinary(SSH#ssh.c_keyinit), ?Ebinary(SSH#ssh.s_keyinit),
?Ebinary(EncodedKey),