File 2533-public_key-Add-support-for-EDDSA-key-on-RFC-5958-for.patch of Package erlang
From 37a58368d7876e325710a4c269f0af27b40434c6 Mon Sep 17 00:00:00 2001
From: Ingela Anderton Andin <ingela@erlang.org>
Date: Fri, 9 Apr 2021 12:34:00 +0200
Subject: [PATCH 3/8] public_key: Add support for EDDSA key on RFC 5958 format
For now make minimal ASN-1 addition. We probably want to modernize
all ASN-1 specs.
---
lib/public_key/asn1/ECPrivateKey.asn1 | 7 +++-
lib/public_key/asn1/PKCS-8.asn1 | 16 ++++++++
lib/public_key/src/pubkey_pem.erl | 2 +
lib/public_key/src/public_key.erl | 38 +++++++++++++++++--
lib/public_key/test/public_key_SUITE.erl | 16 +++++++-
.../eddsa_key_rfc5958.pem | 5 +++
6 files changed, 78 insertions(+), 6 deletions(-)
create mode 100644 lib/public_key/test/public_key_SUITE_data/eddsa_key_rfc5958.pem
diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1
index 5f7267506f..e0f4c3a011 100644
--- a/lib/public_key/asn1/ECPrivateKey.asn1
+++ b/lib/public_key/asn1/ECPrivateKey.asn1
@@ -18,9 +18,14 @@ ECPrivateKey ::= SEQUENCE {
version INTEGER,
privateKey CurvePrivateKey,
parameters [0] EcpkParameters OPTIONAL,
- publicKey [1] BIT STRING OPTIONAL
+ publicKey [1] CurvePublicKey OPTIONAL,
+ -- Should be PKCS-8 Attributes but problem at the moment with PKCS-8 beeing part
+ -- of PCKS-FRAME and PKIX1Algorithms88 is part of OTP-PUB-KEY. Procrastinate
+ -- the solution as it mostly not used anyway
+ attributes ANY OPTIONAL
}
CurvePrivateKey ::= OCTET STRING
+CurvePublicKey ::= BIT STRING
END
diff --git a/lib/public_key/asn1/PKCS-8.asn1 b/lib/public_key/asn1/PKCS-8.asn1
index 292a7b2029..87b3ecd99c 100644
--- a/lib/public_key/asn1/PKCS-8.asn1
+++ b/lib/public_key/asn1/PKCS-8.asn1
@@ -51,6 +51,22 @@ PrivateKeyInfo ::= SEQUENCE {
privateKey PrivateKey,
attributes [0] Attributes OPTIONAL }
+-- START FROM RFC 5958
+OneAsymmetricKey ::= SEQUENCE {
+ version Version,
+ privateKeyAlgorithm AlgorithmIdentifier {{...}},
+ privateKey PrivateKey,
+ attributes [0] Attributes OPTIONAL,
+ ...,
+ [[2: publicKey [1] PublicKey OPTIONAL ]],
+ ...
+ }
+
+PublicKey ::= BIT STRING
+ -- Content varies based on type of key. The
+ -- algorithm identifier dictates the format of
+ -- the key.
+-- END FROM RFC 5958
Version ::= INTEGER {v1(0)} (v1,...)
PrivateKey ::= OCTET STRING
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index a33db4ecf0..a4d54c9e63 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -212,6 +212,8 @@ pem_start('DHParameter') ->
<<"-----BEGIN DH PARAMETERS-----">>;
pem_start('PrivateKeyInfo') ->
<<"-----BEGIN PRIVATE KEY-----">>;
+pem_start('OneAsymmetricKey') ->
+ <<"-----BEGIN PRIVATE KEY-----">>;
pem_start('EncryptedPrivateKeyInfo') ->
<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>;
pem_start('CertificationRequest') ->
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 4f097a1e2d..b9eeac1b12 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -291,7 +291,7 @@ der_decode(Asn1Type, Der) when (((Asn1Type == 'PrivateKeyInfo')
der_priv_key_decode(Decoded)
catch
error:{badmatch, {error, _}} = Error ->
- erlang:error(Error)
+ handle_pkcs_frame_error(Asn1Type, Der, Error)
end;
der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
@@ -303,6 +303,17 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
erlang:error(Error)
end.
+handle_pkcs_frame_error('PrivateKeyInfo', Der, _) ->
+ try
+ {ok, Decoded} = 'PKCS-FRAME':decode('OneAsymmetricKey', Der),
+ der_priv_key_decode(Decoded)
+ catch
+ error:{badmatch, {error, _}} = Error ->
+ erlang:error(Error)
+ end;
+handle_pkcs_frame_error(_, _, Error) ->
+ erlang:error(Error).
+
der_priv_key_decode({'PrivateKeyInfo', v1,
{'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
EcPrivKey = der_decode('ECPrivateKey', PrivKey),
@@ -312,6 +323,13 @@ der_priv_key_decode({'PrivateKeyInfo', v1,
CurveOId == ?'id-Ed25519'orelse
CurveOId == ?'id-Ed448' ->
#'ECPrivateKey'{version = 1, parameters = {namedCurve, CurveOId}, privateKey = PrivKey};
+der_priv_key_decode({'OneAsymmetricKey', _,
+ {'OneAsymmetricKey_privateKeyAlgorithm', CurveOId, _}, PrivKey, Attr, PubKey}) when
+ CurveOId == ?'id-Ed25519'orelse
+ CurveOId == ?'id-Ed448' ->
+ #'ECPrivateKey'{version = 2, parameters = {namedCurve, CurveOId}, privateKey = PrivKey,
+ attributes = Attr,
+ publicKey = PubKey};
der_priv_key_decode({'PrivateKeyInfo', v1,
{'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', _}, PrivKey, _}) ->
der_decode('RSAPrivateKey', PrivKey);
@@ -351,10 +369,10 @@ der_encode('PrivateKeyInfo', #'RSAPrivateKey'{} = PrivKey) ->
der_encode('PrivateKeyInfo', {#'RSAPrivateKey'{} = PrivKey, Parameters}) ->
der_encode('PrivateKeyInfo',
{'PrivateKeyInfo', v1,
- {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-RSASSA-PSS',
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-RSASSA-PSS',
{asn1_OPENTYPE, der_encode('RSASSA-PSS-params', Parameters)}},
der_encode('RSAPrivateKey', PrivKey), asn1_NOVALUE});
-der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = {namedCurve, CurveOId} = Parameters,
+der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = {namedCurve, CurveOId},
privateKey = PrivKey}) when
CurveOId == ?'id-Ed25519' orelse
CurveOId == ?'id-Ed448' ->
@@ -369,7 +387,19 @@ der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = Parameters} = PrivKey)
{asn1_OPENTYPE, der_encode('EcpkParameters', Parameters)}},
der_encode('ECPrivateKey', PrivKey#'ECPrivateKey'{parameters = asn1_NOVALUE}),
asn1_NOVALUE});
-der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
+der_encode('OneAsymmetricKey', #'ECPrivateKey'{parameters = {namedCurve, CurveOId},
+ privateKey = PrivKey,
+ attributes = Attr,
+ publicKey = PubKey}) ->
+ der_encode('OneAsymmetricKey',
+ {'OneAsymmetricKey', 1,
+ {'OneAsymmetricKey_privateKeyAlgorithm', CurveOId, asn1_NOVALUE},
+ PrivKey,
+ Attr,
+ PubKey
+ });
+der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') orelse
+ (Asn1Type == 'OneAsymmetricKey') orelse
(Asn1Type == 'EncryptedPrivateKeyInfo') ->
try
{ok, Encoded} = 'PKCS-FRAME':encode(Asn1Type, Entity),
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index ae16eca83e..bbd458c036 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -57,6 +57,8 @@
eddsa_priv_pkcs8/1,
eddsa_pub/0,
eddsa_pub/1,
+ eddsa_priv_rfc5958/0,
+ eddsa_priv_rfc5958/1,
init_ec_pem_encode_generated/1,
ec_pem_encode_generated/0,
ec_pem_encode_generated/1,
@@ -159,7 +161,7 @@ groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, rsa_pss_pss_pem, ec_pem, encrypted_pem,
dh_pem, cert_pem, pkcs7_pem, pkcs10_pem, ec_pem2,
rsa_priv_pkcs8, dsa_priv_pkcs8, ec_priv_pkcs8,
- eddsa_priv_pkcs8,
+ eddsa_priv_pkcs8, eddsa_priv_rfc5958,
ec_pem_encode_generated,
gen_ec_param_prime_field, gen_ec_param_char_2_field
]},
@@ -415,6 +417,19 @@ eddsa_pub(Config) when is_list(Config) ->
ECPemNoEndNewLines = strip_superfluous_newlines(EDDSAPubPem),
ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PemEntry])).
+eddsa_priv_rfc5958() ->
+ [{doc, "EDDSA PKCS8 private key decode/encode"}].
+eddsa_priv_rfc5958(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {ok, ECPrivPem} = file:read_file(filename:join(Datadir, "eddsa_key_rfc5958.pem")),
+ [{'PrivateKeyInfo', _, not_encrypted} = PKCS8Key] = public_key:pem_decode(ECPrivPem),
+ ECPrivKey = public_key:pem_entry_decode(PKCS8Key),
+ true = check_entry_type(ECPrivKey, 'ECPrivateKey'),
+ true = ECPrivKey#'ECPrivateKey'.parameters == {namedCurve, ?'id-Ed25519'},
+ PrivEntry0 = public_key:pem_entry_encode('OneAsymmetricKey', ECPrivKey),
+ ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem),
+ ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
+
init_ec_pem_encode_generated(Config) ->
case catch true = lists:member('secp384r1', crypto:ec_curves()) of
{'EXIT', _} -> {skip, {'secp384r1', not_supported}};
diff --git a/lib/public_key/test/public_key_SUITE_data/eddsa_key_rfc5958.pem b/lib/public_key/test/public_key_SUITE_data/eddsa_key_rfc5958.pem
new file mode 100644
index 0000000000..7179f294ba
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/eddsa_key_rfc5958.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC
+oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB
+Z9w7lshQhqowtrbLDFw4rXAxZuE=
+-----END PRIVATE KEY-----
\ No newline at end of file
--
2.26.2