diff options
-rw-r--r-- | lib/public_key/doc/src/public_key.xml | 7 | ||||
-rw-r--r-- | lib/public_key/src/pubkey_ssh.erl | 138 | ||||
-rw-r--r-- | lib/public_key/src/public_key.erl | 1 | ||||
-rw-r--r-- | lib/ssh/src/ssh_message.erl | 20 | ||||
-rw-r--r-- | lib/ssh/src/ssh_transport.erl | 30 |
5 files changed, 73 insertions, 123 deletions
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 3040f2db0d..5230cef496 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -883,8 +883,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, </type> <desc> <p>This function checks that the <i>Presented Identifier</i> (e.g hostname) in a peer certificate - conforms with the Expected Identifier that the client wants to connect to. - This functions is intended to be added as an extra client check to the peer certificate when performing + is in agreement with the <i>Reference Identifier</i> that the client expects to be connected to. + The function is intended to be added as an extra client check of the peer certificate when performing <seealso marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso> </p> <p>See <url href="https://tools.ietf.org/html/rfc6125">RFC 6125</url> @@ -897,7 +897,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{}, <p>The <c>{OtherRefId,term()}</c> is defined by the user and is passed to the <c>match_fun</c>, if defined. If that term is a binary, it will be converted to a string. </p> - <p>The <c>ip</c> takes a 4-tuple or a + <p>The <c>ip</c> Reference ID takes an <seealso marker="inet:inet#type-ip_address">inet:ip_address()</seealso> + or an ip address in string format (E.g "10.0.1.1" or "1234::5678:9012") as second element. </p> </desc> </func> 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), |