aboutsummaryrefslogtreecommitdiffstats
path: root/lib/public_key/src/pubkey_ssh.erl
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2015-09-28 12:10:06 +0200
committerHans Nilsson <[email protected]>2015-10-08 16:02:07 +0200
commit437448c16ac18208838a638717309ee0294b004e (patch)
tree196bc7445d659206cb6df5c2c6271e8bf4c4c234 /lib/public_key/src/pubkey_ssh.erl
parent794a6d1f2c904be72d4b4327a7c6faa759a25690 (diff)
downloadotp-437448c16ac18208838a638717309ee0294b004e.tar.gz
otp-437448c16ac18208838a638717309ee0294b004e.tar.bz2
otp-437448c16ac18208838a638717309ee0294b004e.zip
public_key: Add ssh2 ECDSA pub key handling + test case
Added encode/decode for ecdsa public keys in openssh and rfc4716 format. This is for the ssh public key algorithm ecdsa-sha2-*.
Diffstat (limited to 'lib/public_key/src/pubkey_ssh.erl')
-rw-r--r--lib/public_key/src/pubkey_ssh.erl49
1 files changed, 44 insertions, 5 deletions
diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl
index 7680d0ce59..26fbeb68ce 100644
--- a/lib/public_key/src/pubkey_ssh.erl
+++ b/lib/public_key/src/pubkey_ssh.erl
@@ -24,6 +24,8 @@
-export([decode/2, encode/2]).
-define(UINT32(X), X:32/unsigned-big-integer).
+-define(STRING(X), ?UINT32((size(X))), (X)/binary).
+
%% 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
@@ -130,7 +132,13 @@ rfc4716_pubkey_decode(<<?UINT32(Len), Type:Len/binary,
{erlint(SizeY, Y),
#'Dss-Parms'{p = erlint(SizeP, P),
q = erlint(SizeQ, Q),
- g = erlint(SizeG, G)}}.
+ g = erlint(SizeG, G)}};
+rfc4716_pubkey_decode(<<?UINT32(Len), Type: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}.
openssh_decode(Bin, FileType) ->
Lines = binary:split(Bin, <<"\n">>, [global]),
@@ -186,12 +194,18 @@ do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) ->
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 == <<"ssh-dss">>;
+ KeyType == <<"ecdsa-sha2-nistp256">>;
+ KeyType == <<"ecdsa-sha2-nistp384">>;
+ KeyType == <<"ecdsa-sha2-nistp521">> ->
do_openssh_decode(FileType, Lines,
[{openssh_pubkey_decode(KeyType, Base64Enc),
[]} | Acc]);
[KeyType, Base64Enc | Comment0] when KeyType == <<"ssh-rsa">>;
- KeyType == <<"ssh-dss">> ->
+ KeyType == <<"ssh-dss">>;
+ KeyType == <<"ecdsa-sha2-nistp256">>;
+ KeyType == <<"ecdsa-sha2-nistp384">>;
+ KeyType == <<"ecdsa-sha2-nistp521">> ->
Comment = string:strip(string_decode(iolist_to_binary(Comment0)), right, $\n),
do_openssh_decode(FileType, Lines,
[{openssh_pubkey_decode(KeyType, Base64Enc),
@@ -203,6 +217,7 @@ 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,
@@ -222,9 +237,19 @@ openssh_pubkey_decode(<<"ssh-dss">>, Base64Enc) ->
#'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)}.
+
erlint(MPIntSize, MPIntValue) ->
Bits= MPIntSize * 8,
<<Integer:Bits/integer>> = MPIntValue,
@@ -350,7 +375,9 @@ line_end(Comment) ->
key_type(#'RSAPublicKey'{}) ->
<<"ssh-rsa">>;
key_type({_, #'Dss-Parms'{}}) ->
- <<"ssh-dss">>.
+ <<"ssh-dss">>;
+key_type({#'ECPoint'{}, Id}) ->
+ <<"ecdsa-sha2-",Id/binary>>.
comma_list_encode([Option], []) ->
Option;
@@ -380,7 +407,13 @@ ssh2_pubkey_encode({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
PBin/binary,
QBin/binary,
GBin/binary,
- YBin/binary>>.
+ YBin/binary>>;
+ssh2_pubkey_encode({#'ECPoint'{point = Q}, Id}) ->
+ TypeStr = <<"ecdsa-sha2-", Id/binary>>,
+ StrLen = size(TypeStr),
+ <<?UINT32(StrLen), TypeStr:StrLen/binary,
+ (string(Id))/binary,
+ (string(Q))/binary>>.
is_key_field(<<"ssh-dss">>) ->
true;
@@ -507,3 +540,9 @@ 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) ->
+ << ?STRING(list_to_binary(X)) >>.