summaryrefslogtreecommitdiff
path: root/lib/public_key/src/pubkey_ssh.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/public_key/src/pubkey_ssh.erl')
-rw-r--r--lib/public_key/src/pubkey_ssh.erl595
1 files changed, 8 insertions, 587 deletions
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index 9a9505f558..36c3ebf558 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2020. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2022. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,71 +19,17 @@
%%
-module(pubkey_ssh).
--include("public_key.hrl").
-include("pubkey_moduli.hrl").
-
--export([decode/2, encode/2,
- dh_gex_group/4,
- dh_gex_group_sizes/0,
-pad/2, new_openssh_encode/1, new_openssh_decode/1 % For test and experiments
+-export([dh_gex_group/4,
+ dh_gex_group_sizes/0
]).
--define(UINT32(X), X:32/unsigned-big-integer).
--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 ).
-
--define(b64enc(X), base64:encode(iolist_to_binary(X)) ).
--define(b64mime_dec(X), base64:mime_decode(iolist_to_binary(X)) ).
-
-%% Max encoded line length is 72, but conformance examples use 68
-%% Comment from rfc 4716: "The following are some examples of public
-%% key files that are compliant (note that the examples all wrap
-%% before 72 bytes to meet IETF document requirements; however, they
-%% are still compliant.)" So we choose to use 68 also.
--define(ENCODED_LINE_LENGTH, 68).
-
-
%%====================================================================
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
-%% Description: Decodes a ssh file-binary.
-%%--------------------------------------------------------------------
-decode(Bin, public_key)->
- 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) ->
- ssh2_pubkey_decode(Bin);
-decode(Bin, new_openssh) ->
- new_openssh_decode(Bin);
-decode(Bin, Type) ->
- openssh_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)
- end, Entries)).
-
-%%--------------------------------------------------------------------
%% Description: Returns Generator and Modulus given MinSize, WantedSize
%% and MaxSize
%%--------------------------------------------------------------------
@@ -102,6 +48,11 @@ dh_gex_group(Min, N, Max, Groups) ->
dh_gex_group_sizes()->
[KeyLen || {KeyLen,_} <- ?dh_default_groups].
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+
%% Select the one with K closest to N but within the interval [Min,Max]
select_by_keylen(Min, N, Max, [{K,_Gs}|Groups]) when K < Min ->
@@ -123,533 +74,3 @@ select_by_keylen(Min, N, Max, [{K,Gs}|Groups], {Kprev,GsPrev}) ->
select_by_keylen(_Min, _N, _Max, [],GPprev) ->
%% is between Min and Max
GPprev.
-
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-begin_marker() ->
- <<"---- BEGIN SSH2 PUBLIC KEY ----">>.
-end_marker() ->
- <<"---- END SSH2 PUBLIC KEY ----">>.
-
-rfc4716_decode(Bin) ->
- Lines = binary:split(Bin, <<"\n">>, [global]),
- do_rfc4716_decode(Lines, []).
-
-do_rfc4716_decode([<<"---- BEGIN SSH2 PUBLIC KEY ----", _/binary>> | Lines], Acc) ->
- do_rfc4716_decode(Lines, Acc);
-%% Ignore empty lines before or after begin/end - markers.
-do_rfc4716_decode([<<>> | Lines], Acc) ->
- do_rfc4716_decode(Lines, Acc);
-do_rfc4716_decode([], Acc) ->
- lists:reverse(Acc);
-do_rfc4716_decode(Lines, Acc) ->
- {Headers, PubKey, Rest} = rfc4716_decode_lines(Lines, []),
- case Headers of
- [_|_] ->
- do_rfc4716_decode(Rest, [{PubKey, [{headers, Headers}]} | Acc]);
- _ ->
- do_rfc4716_decode(Rest, [{PubKey, []} | Acc])
- end.
-
-rfc4716_decode_lines([Line | Lines], Acc) ->
- case binary:last(Line) of
- $\\ ->
- NewLine = binary:replace(Line,<<"\\">>, hd(Lines), []),
- rfc4716_decode_lines([NewLine | tl(Lines)], Acc);
- _ ->
- rfc4716_decode_line(Line, Lines, Acc)
- end.
-
-rfc4716_decode_line(Line, Lines, Acc) ->
- case binary:split(Line, <<":">>) of
- [Tag, Value] ->
- rfc4716_decode_lines(Lines, [{string_decode(Tag), unicode_decode(Value)} | Acc]);
- _ ->
- {Body, Rest} = join_entry([Line | Lines], []),
- {lists:reverse(Acc), rfc4716_pubkey_decode(?b64mime_dec(Body)), Rest}
- end.
-
-join_entry([<<"---- END SSH2 PUBLIC KEY ----", _/binary>>| Lines], Entry) ->
- {lists:reverse(Entry), Lines};
-join_entry([Line | Lines], Entry) ->
- join_entry(Lines, [Line | Entry]).
-
-
-rfc4716_pubkey_decode(BinKey) -> ssh2_pubkey_decode(BinKey).
-
-
-%% From https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
-new_openssh_decode(<<"openssh-key-v1",0,
- ?DEC_BIN(CipherName, _L1),
- ?DEC_BIN(KdfName, _L2),
- ?DEC_BIN(KdfOptions, _L3),
- ?UINT32(N), % number of keys
- ?DEC_BIN(PublicKey, _L4),
- ?DEC_BIN(Encrypted, _L5),
- _Rest/binary
- >>) ->
- %%io:format("CipherName = ~p~nKdfName = ~p~nKdfOptions = ~p~nPublicKey = ~p~nN = ~p~nEncrypted = ~p~nRest = ~p~n", [CipherName, KdfName, KdfOptions, PublicKey, N, Encrypted, _Rest]),
- new_openssh_decode(CipherName, KdfName, KdfOptions, PublicKey, N, Encrypted).
-
-new_openssh_decode(<<"none">>, <<"none">>, <<"">>, _PublicKey, 1,
- <<?UINT32(CheckInt),
- ?UINT32(CheckInt),
- ?DEC_BIN(Type, _Lt),
- ?DEC_BIN(PubKey, _Lpu),
- ?DEC_BIN(PrivPubKey, _Lpripub),
- ?DEC_BIN(_Comment, _C1),
- _Pad/binary>>) ->
- case {Type,PrivPubKey} of
- {<<"ssh-ed25519">>,
- <<PrivKey:32/binary, PubKey:32/binary>>} ->
- {ed_pri, ed25519, PubKey, PrivKey};
-
- {<<"ssh-ed448">>,
- <<PrivKey:57/binary, PubKey/binary>>} -> % "Intelligent" guess from
- % https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-ed448
- {ed_pri, ed448, PubKey, PrivKey}
- end.
-
-
-new_openssh_encode({ed_pri,_,PubKey,PrivKey}=Key) ->
- Type = key_type(Key),
- CheckInt = 17*256+17, %crypto:strong_rand_bytes(4),
- Comment = <<>>,
- PublicKey = <<?STRING(Type),?STRING(PubKey)>>,
- CipherName = <<"none">>,
- KdfName = <<"none">>,
- KdfOptions = <<>>,
- BlockSize = 8, % Crypto dependent
- NumKeys = 1,
- Encrypted0 = <<?UINT32(CheckInt),
- ?UINT32(CheckInt),
- ?STRING(Type),
- ?STRING(PubKey),
- ?STRING(<<PrivKey/binary,PubKey/binary>>),
- ?STRING(Comment)
- >>,
- Pad = pad(size(Encrypted0), BlockSize),
- Encrypted = <<Encrypted0/binary, Pad/binary>>,
- <<"openssh-key-v1",0,
- ?STRING(CipherName),
- ?STRING(KdfName),
- ?STRING(KdfOptions),
- ?UINT32(NumKeys),
- ?STRING(PublicKey),
- ?STRING(Encrypted)>>.
-
-pad(N, BlockSize) when N>BlockSize -> pad(N rem BlockSize, BlockSize);
-pad(N, BlockSize) -> list_to_binary(lists:seq(1,BlockSize-N)).
-
-
-openssh_decode(Bin, FileType) ->
- Lines = binary:split(Bin, <<"\n">>, [global]),
- do_openssh_decode(FileType, Lines, []).
-
-do_openssh_decode(_, [], Acc) ->
- lists:reverse(Acc);
-%% Ignore empty lines
-do_openssh_decode(FileType, [<<>> | Lines], Acc) ->
- do_openssh_decode(FileType, Lines, Acc);
-%% Ignore lines that start with #
-do_openssh_decode(FileType,[<<"#", _/binary>> | Lines], Acc) ->
- do_openssh_decode(FileType, Lines, Acc);
-do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) ->
- case decode_auth_keys(Line) of
- {ssh2, {options, [Options, KeyType, Base64Enc| Comment]}} ->
- do_openssh_decode(FileType, Lines,
- [{openssh_pubkey_decode(KeyType, Base64Enc),
- decode_comment(Comment) ++ [{options, comma_list_decode(Options)}]} | Acc]);
- {ssh2, {no_options, [KeyType, Base64Enc| Comment]}} ->
- do_openssh_decode(FileType, Lines,
- [{openssh_pubkey_decode(KeyType, Base64Enc),
- decode_comment(Comment)} | Acc]);
- {ssh1, {options, [Options, Bits, Exponent, Modulus | Comment]}} ->
- do_openssh_decode(FileType, Lines,
- [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
- decode_comment(Comment) ++ [{options, comma_list_decode(Options)},
- {bits, integer_decode(Bits)}]
- } | Acc]);
- {ssh1, {no_options, [Bits, Exponent, Modulus | Comment]}} ->
- do_openssh_decode(FileType, Lines,
- [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
- decode_comment(Comment) ++ [{bits, integer_decode(Bits)}]
- } | Acc])
- end;
-
-do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) ->
- case decode_known_hosts(Line) of
- {ssh2, [HostNames, KeyType, Base64Enc| Comment]} ->
- do_openssh_decode(FileType, Lines,
- [{openssh_pubkey_decode(KeyType, Base64Enc),
- decode_comment(Comment) ++
- [{hostnames, comma_list_decode(HostNames)}]}| Acc]);
- {ssh1, [HostNames, Bits, Exponent, Modulus | Comment]} ->
- do_openssh_decode(FileType, Lines,
- [{ssh1_rsa_pubkey_decode(Modulus, Exponent),
- decode_comment(Comment) ++
- [{hostnames, comma_list_decode(HostNames)},
- {bits, integer_decode(Bits)}]}
- | Acc])
- end;
-
-do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) ->
- [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);
- <<"ssh-ed25519">> -> true;
- <<"ssh-ed448">> -> true;
- _ -> false
- end,
-
- case Comment0 of
- [] when KnownKeyType==true ->
- do_openssh_decode(FileType, Lines,
- [{openssh_pubkey_decode(KeyType, Base64Enc),
- []} | Acc]);
- _ 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]);
- _ when KnownKeyType==false ->
- do_openssh_decode(FileType, Lines, Acc)
- end.
-
-
-decode_comment([]) ->
- [];
-decode_comment(Comment) ->
- [{comment, string_decode(iolist_to_binary(Comment))}].
-
-
-openssh_pubkey_decode(Type, Base64Enc) ->
- try
- <<?DEC_BIN(Type,_TL), Bin/binary>> = ?b64mime_dec(Base64Enc),
- ssh2_pubkey_decode(Type, Bin)
- catch
- _:_ ->
- {Type, ?b64mime_dec(Base64Enc)}
- end.
-
-
-ssh1_rsa_pubkey_decode(MBin, EBin) ->
- #'RSAPublicKey'{modulus = integer_decode(MBin),
- publicExponent = integer_decode(EBin)}.
-
-integer_decode(BinStr) ->
- list_to_integer(binary_to_list(BinStr)).
-
-string_decode(BinStr) ->
- unicode_decode(BinStr).
-
-unicode_decode(BinStr) ->
- unicode:characters_to_list(BinStr).
-
-comma_list_decode(BinOpts) ->
- CommaList = binary:split(BinOpts, <<",">>, [global]),
- lists:map(fun(Item) ->
- binary_to_list(Item)
- end, CommaList).
-
-do_encode(rfc4716_public_key, Key, Attributes) ->
- rfc4716_encode(Key, proplists:get_value(headers, Attributes, []), []);
-
-do_encode(Type, Key, Attributes) ->
- openssh_encode(Type, Key, Attributes).
-
-rfc4716_encode(Key, [],[]) ->
- iolist_to_binary([begin_marker(),"\n",
- split_lines(?b64enc(ssh2_pubkey_encode(Key))),
- "\n", end_marker(), "\n"]);
-rfc4716_encode(Key, [], [_|_] = Acc) ->
- iolist_to_binary([begin_marker(), "\n",
- lists:reverse(Acc),
- split_lines(?b64enc(ssh2_pubkey_encode(Key))),
- "\n", end_marker(), "\n"]);
-rfc4716_encode(Key, [ Header | Headers], Acc) ->
- LinesStr = rfc4716_encode_header(Header),
- rfc4716_encode(Key, Headers, [LinesStr | Acc]).
-
-rfc4716_encode_header({Tag, Value}) ->
- TagLen = length(Tag),
- ValueLen = length(Value),
- case TagLen + 1 + ValueLen of
- N when N > ?ENCODED_LINE_LENGTH ->
- NumOfChars = ?ENCODED_LINE_LENGTH - (TagLen + 1),
- {First, Rest} = lists:split(NumOfChars, Value),
- [Tag,":" , First, [$\\], "\n", rfc4716_encode_value(Rest) , "\n"];
- _ ->
- [Tag, ":", Value, "\n"]
- end.
-
-rfc4716_encode_value(Value) ->
- case length(Value) of
- N when N > ?ENCODED_LINE_LENGTH ->
- {First, Rest} = lists:split(?ENCODED_LINE_LENGTH, Value),
- [First, [$\\], "\n", rfc4716_encode_value(Rest)];
- _ ->
- Value
- end.
-
-openssh_encode(openssh_public_key, Key, Attributes) ->
- Comment = proplists:get_value(comment, Attributes, ""),
- Enc = ?b64enc(ssh2_pubkey_encode(Key)),
- iolist_to_binary([key_type(Key), " ", Enc, " ", Comment, "\n"]);
-
-openssh_encode(auth_keys, Key, Attributes) ->
- Comment = proplists:get_value(comment, Attributes, ""),
- Options = proplists:get_value(options, Attributes, undefined),
- Bits = proplists:get_value(bits, Attributes, undefined),
- case Bits of
- undefined ->
- openssh_ssh2_auth_keys_encode(Options, Key, Comment);
- _ ->
- openssh_ssh1_auth_keys_encode(Options, Bits, Key, Comment)
- end;
-openssh_encode(known_hosts, Key, Attributes) ->
- Comment = proplists:get_value(comment, Attributes, ""),
- Hostnames = proplists:get_value(hostnames, Attributes),
- Bits = proplists:get_value(bits, Attributes, undefined),
- case Bits of
- undefined ->
- openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment);
- _ ->
- openssh_ssh1_known_hosts_encode(Hostnames, Bits, Key, Comment)
- end.
-
-openssh_ssh2_auth_keys_encode(undefined, Key, Comment) ->
- iolist_to_binary([key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]);
-openssh_ssh2_auth_keys_encode(Options, Key, Comment) ->
- iolist_to_binary([comma_list_encode(Options, []), " ",
- key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]).
-
-openssh_ssh1_auth_keys_encode(undefined, Bits,
- #'RSAPublicKey'{modulus = N, publicExponent = E},
- Comment) ->
- iolist_to_binary([integer_to_list(Bits), " ", integer_to_list(E), " ", integer_to_list(N),
- line_end(Comment)]);
-openssh_ssh1_auth_keys_encode(Options, Bits,
- #'RSAPublicKey'{modulus = N, publicExponent = E},
- Comment) ->
- iolist_to_binary([comma_list_encode(Options, []), " ", integer_to_list(Bits),
- " ", integer_to_list(E), " ", integer_to_list(N), line_end(Comment)]).
-
-openssh_ssh2_know_hosts_encode(Hostnames, Key, Comment) ->
- iolist_to_binary([comma_list_encode(Hostnames, []), " ",
- key_type(Key)," ", ?b64enc(ssh2_pubkey_encode(Key)), line_end(Comment)]).
-
-openssh_ssh1_known_hosts_encode(Hostnames, Bits,
- #'RSAPublicKey'{modulus = N, publicExponent = E},
- Comment) ->
- iolist_to_binary([comma_list_encode(Hostnames, [])," ", integer_to_list(Bits)," ",
- integer_to_list(E)," ", integer_to_list(N), line_end(Comment)]).
-
-line_end("") ->
- "\n";
-line_end(Comment) ->
- [" ", Comment, "\n"].
-
-key_type(#'RSAPublicKey'{}) -> <<"ssh-rsa">>;
-key_type({_, #'Dss-Parms'{}}) -> <<"ssh-dss">>;
-key_type({ed_pub,ed25519,_}) -> <<"ssh-ed25519">>;
-key_type({ed_pub,ed448,_}) -> <<"ssh-ed448">>;
-key_type({ed_pri,ed25519,_,_}) -> <<"ssh-ed25519">>;
-key_type({ed_pri,ed448,_,_}) -> <<"ssh-ed448">>;
-key_type({#'ECPoint'{}, {namedCurve,Curve}}) -> <<"ecdsa-sha2-", (public_key:oid2ssh_curvename(Curve))/binary>>.
-
-comma_list_encode([Option], []) ->
- Option;
-comma_list_encode([Option], Acc) ->
- Acc ++ "," ++ Option;
-comma_list_encode([Option | Rest], []) ->
- comma_list_encode(Rest, Option);
-comma_list_encode([Option | Rest], Acc) ->
- comma_list_encode(Rest, Acc ++ "," ++ Option).
-
-
-ssh2_pubkey_encode(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
- <<?STRING(<<"ssh-rsa">>), ?Empint(E), ?Empint(N)>>;
-ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
- <<?STRING(<<"ssh-dss">>), ?Empint(P), ?Empint(Q), ?Empint(G), ?Empint(Y)>>;
-ssh2_pubkey_encode(Key={#'ECPoint'{point = Q}, {namedCurve,OID}}) ->
- Curve = public_key:oid2ssh_curvename(OID),
- <<?STRING(key_type(Key)), ?Estring(Curve), ?Estring(Q)>>;
-ssh2_pubkey_encode({ed_pub, ed25519, Key}) ->
- <<?STRING(<<"ssh-ed25519">>), ?Estring(Key)>>;
-ssh2_pubkey_encode({ed_pub, ed448, Key}) ->
- <<?STRING(<<"ssh-ed448">>), ?Estring(Key)>>.
-
-
-
-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(<<"ssh-rsa">>,
- <<?DEC_INT(E, _EL),
- ?DEC_INT(N, _NL)>>) ->
- #'RSAPublicKey'{modulus = N,
- publicExponent = E};
-
-ssh2_pubkey_decode(<<"ssh-dss">>,
- <<?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>>,
- <<?DEC_BIN(Id, _IL),
- ?DEC_BIN(Q, _QL)>>) ->
- {#'ECPoint'{point = Q}, {namedCurve,public_key:ssh_curvename2oid(Id)}};
-
-ssh2_pubkey_decode(<<"ssh-ed25519">>,
- <<?DEC_BIN(Key, _L)>>) ->
- {ed_pub, ed25519, Key};
-
-ssh2_pubkey_decode(<<"ssh-ed448">>,
- <<?DEC_BIN(Key, _L)>>) ->
- {ed_pub, ed448, Key}.
-
-
-
-
-is_key_field(<<"ssh-dss">>) -> true;
-is_key_field(<<"ssh-rsa">>) -> true;
-is_key_field(<<"ssh-ed25519">>) -> true;
-is_key_field(<<"ssh-ed448">>) -> 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
- _ ->
- true
- catch _:_ ->
- false
- end.
-
-split_lines(<<Text:?ENCODED_LINE_LENGTH/binary>>) ->
- [Text];
-split_lines(<<Text:?ENCODED_LINE_LENGTH/binary, Rest/binary>>) ->
- [Text, $\n | split_lines(Rest)];
-split_lines(Bin) ->
- [Bin].
-
-decode_auth_keys(Line) ->
- [First, Rest] = binary:split(Line, <<" ">>, []),
- case is_key_field(First) of
- true ->
- {ssh2, decode_auth_keys_ssh2(First, Rest)};
- false ->
- case is_bits_field(First) of
- true ->
- {ssh1, decode_auth_keys_ssh1(First, Rest)};
- false ->
- decode_auth_keys(First, Rest)
- end
- end.
-
-decode_auth_keys(First, Line) ->
- [Second, Rest] = binary:split(Line, <<" ">>, []),
- case is_key_field(Second) of
- true ->
- {ssh2, decode_auth_keys_ssh2(First, Second, Rest)};
- false ->
- case is_bits_field(Second) of
- true ->
- {ssh1, decode_auth_keys_ssh1(First, Second, Rest)};
- false ->
- decode_auth_keys(<<First/binary, Second/binary>>, Rest)
- end
- end.
-
-decode_auth_keys_ssh2(KeyType, Rest) ->
- {no_options, [KeyType | split_n(1, Rest, [])]}.
-
-decode_auth_keys_ssh2(Options, Next, Rest) ->
- {options, [Options, Next | split_n(1, Rest, [])]}.
-
-decode_auth_keys_ssh1(Options, Next, Rest) ->
- {options, [Options, Next | split_n(2, Rest, [])]}.
-
-decode_auth_keys_ssh1(First, Rest) ->
- {no_options, [First | split_n(2, Rest, [])]}.
-
-decode_known_hosts(Line) ->
- [First, Rest] = binary:split(Line, <<" ">>, []),
- [Second, Rest1] = binary:split(Rest, <<" ">>, []),
-
- case is_bits_field(Second) of
- true ->
- {ssh1, decode_known_hosts_ssh1(First, Second, Rest1)};
- false ->
- {ssh2, decode_known_hosts_ssh2(First, Second, Rest1)}
- end.
-
-decode_known_hosts_ssh1(Hostnames, Bits, Rest) ->
- [Hostnames, Bits | split_n(2, Rest, [])].
-
-decode_known_hosts_ssh2(Hostnames, KeyType, Rest) ->
- [Hostnames, KeyType | split_n(1, Rest, [])].
-
-split_n(0, <<>>, Acc) ->
- lists:reverse(Acc);
-split_n(0, Bin, Acc) ->
- lists:reverse([Bin | Acc]);
-split_n(N, Bin, Acc) ->
- case binary:split(Bin, <<" ">>, []) of
- [First, Rest] ->
- split_n(N-1, Rest, [First | Acc]);
- [Last] ->
- split_n(0, <<>>, [Last | Acc])
- end.
-%% large integer in a binary with 32bit length
-%% MP representaion (SSH2)
-mpint(X) when X < 0 -> mpint_neg(X);
-mpint(X) -> mpint_pos(X).
-
-mpint_neg(X) ->
- Bin = int_to_bin_neg(X, []),
- <<?STRING(Bin)>>.
-
-mpint_pos(X) ->
- Bin = int_to_bin_pos(X, []),
- <<MSB,_/binary>> = Bin,
- if MSB band 16#80 == 16#80 ->
- B = << 0, Bin/binary>>,
- <<?STRING(B)>>;
- true ->
- <<?STRING(Bin)>>
- end.
-
-int_to_bin_pos(0,Ds=[_|_]) ->
- list_to_binary(Ds);
-int_to_bin_pos(X,Ds) ->
- int_to_bin_pos(X bsr 8, [(X band 255)|Ds]).
-
-int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
- list_to_binary(Ds);
-int_to_bin_neg(X,Ds) ->
- int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
-
-
-string(X) when is_binary(X) ->
- << ?STRING(X) >>;
-string(X) ->
- B = list_to_binary(X),
- << ?STRING(B) >>.
-
-is_ssh_curvename(Id) -> try public_key:ssh_curvename2oid(Id) of _ -> true
- catch _:_ -> false
- end.
-