diff options
Diffstat (limited to 'lib/public_key')
-rw-r--r-- | lib/public_key/src/pubkey_ssh.erl | 153 | ||||
-rw-r--r-- | lib/public_key/src/public_key.erl | 36 |
2 files changed, 114 insertions, 75 deletions
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl index 26fbeb68ce..82042550a0 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,13 +34,16 @@ %% are still compliant.)" So we choose to use 68 also. -define(ENCODED_LINE_LENGTH, 68). + %%==================================================================== %% Internal application API %%==================================================================== %%-------------------------------------------------------------------- -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. %%-------------------------------------------------------------------- @@ -52,15 +56,21 @@ 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). %%-------------------------------------------------------------------- -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. %%-------------------------------------------------------------------- +encode(Bin, ssh2_pubkey) -> + ssh2_pubkey_encode(Bin); encode(Entries, Type) -> iolist_to_binary(lists:map(fun({Key, Attributes}) -> do_encode(Type, Key, Attributes) @@ -133,12 +143,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,62 +201,41 @@ 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) -> [{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}, 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) -> @@ -372,12 +360,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 +393,48 @@ 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. + +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); +is_key_field(_) -> false. is_bits_field(Part) -> try list_to_integer(binary_to_list(Part)) of @@ -546,3 +554,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..8288f68f7f 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, @@ -711,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 @@ -724,12 +727,15 @@ 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). %%-------------------------------------------------------------------- --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. @@ -738,10 +744,30 @@ 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). %%-------------------------------------------------------------------- +-spec ssh_curvename2oid(binary()) -> oid(). + +%% Description: Converts from the ssh name of elliptic curves to +%% the OIDs. +%%-------------------------------------------------------------------- +ssh_curvename2oid(<<"nistp256">>) -> ?'secp256r1'; +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">>; +oid2ssh_curvename(?'secp384r1') -> <<"nistp384">>; +oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>. + +%%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- do_verify(DigestOrPlainText, DigestType, Signature, |