Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:23
erlang
2532-public_key-Add-support-for-EDDSA.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2532-public_key-Add-support-for-EDDSA.patch of Package erlang
From a720a4eb918ab6b97daae02c0c6c9cd39e3a8819 Mon Sep 17 00:00:00 2001 From: Ingela Anderton Andin <ingela@erlang.org> Date: Tue, 6 Apr 2021 15:30:32 +0200 Subject: [PATCH 2/8] public_key: Add support for EDDSA --- lib/public_key/asn1/ECPrivateKey.asn1 | 4 +- lib/public_key/src/pubkey_cert.erl | 33 +++++-- lib/public_key/src/pubkey_cert_records.erl | 10 +- lib/public_key/src/public_key.erl | 99 ++++++++++++++++--- lib/public_key/test/public_key_SUITE.erl | 17 ++++ .../public_key_SUITE_data/eddsa_key_pkcs8.pem | 3 + 6 files changed, 145 insertions(+), 21 deletions(-) create mode 100644 lib/public_key/test/public_key_SUITE_data/eddsa_key_pkcs8.pem diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1 index a20fa4009c..5f7267506f 100644 --- a/lib/public_key/asn1/ECPrivateKey.asn1 +++ b/lib/public_key/asn1/ECPrivateKey.asn1 @@ -16,9 +16,11 @@ EcpkParameters FROM PKIX1Algorithms88; ECPrivateKey ::= SEQUENCE { version INTEGER, - privateKey OCTET STRING, + privateKey CurvePrivateKey, parameters [0] EcpkParameters OPTIONAL, publicKey [1] BIT STRING OPTIONAL } +CurvePrivateKey ::= OCTET STRING + END diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index e84edffd53..66d37ebf96 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -74,7 +74,7 @@ %%-------------------------------------------------------------------- -spec verify_data(DER::binary()) -> {DigestType, PlainText, Signature} - when DigestType :: md5 | crypto:sha1() | crypto:sha2(), + when DigestType :: md5 | crypto:sha1() | crypto:sha2() | none, PlainText :: binary(), Signature :: binary(). %% @@ -639,9 +639,12 @@ public_key_info(PublicKeyInfo, case PublicKeyParams of {null, 'NULL'} when WorkingAlgorithm == Algorithm -> WorkingParams; - {params, Params} -> + asn1_NOVALUE when Algorithm == ?'id-Ed25519'; + Algorithm == ?'id-Ed448' -> + {namedCurve, Algorithm}; + {params, Params} -> Params; - Params -> + Params -> Params end, {Algorithm, PublicKey, NewPublicKeyParams}. @@ -1256,6 +1259,10 @@ sign_algorithm({#'RSAPrivateKey'{} = Key,#'RSASSA-PSS-params'{} = Params}, _Opts sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> #'SignatureAlgorithm'{algorithm = ?'id-dsa-with-sha1', parameters = {params,#'Dss-Parms'{p=P, q=Q, g=G}}}; +sign_algorithm(#'ECPrivateKey'{parameters = {namedCurve, EDCurve}}, _Opts) when EDCurve == ?'id-Ed25519'; + EDCurve == ?'id-Ed448' -> + #'SignatureAlgorithm'{algorithm = EDCurve, + parameters = asn1_NOVALUE}; sign_algorithm(#'ECPrivateKey'{parameters = Parms}, Opts) -> Type = ecdsa_digest_oid(proplists:get_value(digest, Opts, sha1)), #'SignatureAlgorithm'{algorithm = Type, @@ -1363,9 +1370,23 @@ public_key(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}, _) -> parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}}, #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}; public_key(#'ECPrivateKey'{version = _Version, - privateKey = _PrivKey, - parameters = Params, - publicKey = PubKey}, _) -> + privateKey = _PrivKey, + parameters = {namedCurve, ?'id-Ed25519' = ID}, + publicKey = PubKey}, _) -> + Algo = #'PublicKeyAlgorithm'{algorithm= ID, parameters=asn1_NOVALUE}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, + subjectPublicKey = #'ECPoint'{point = PubKey}}; +public_key(#'ECPrivateKey'{version = _Version, + privateKey = _PrivKey, + parameters = {namedCurve, ?'id-Ed448' = ID}, + publicKey = PubKey}, _) -> + Algo = #'PublicKeyAlgorithm'{algorithm= ID, parameters=asn1_NOVALUE}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, + subjectPublicKey = #'ECPoint'{point = PubKey}}; +public_key(#'ECPrivateKey'{version = _Version, + privateKey = _PrivKey, + parameters = Params, + publicKey = PubKey}, _) -> Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params}, #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = #'ECPoint'{point = PubKey}}. diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl index b556314ad1..1e45afd8bf 100644 --- a/lib/public_key/src/pubkey_cert_records.erl +++ b/lib/public_key/src/pubkey_cert_records.erl @@ -111,7 +111,11 @@ supportedPublicKeyAlgorithms(?'id-dsa') -> 'DSAPublicKey'; supportedPublicKeyAlgorithms(?'dhpublicnumber') -> 'DHPublicKey'; supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey'; supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'; -supportedPublicKeyAlgorithms(?'id-RSASSA-PSS') -> 'RSAPublicKey'. +supportedPublicKeyAlgorithms(?'id-RSASSA-PSS') -> 'RSAPublicKey'; +supportedPublicKeyAlgorithms(?'id-Ed25519') -> 'ECPoint'; +supportedPublicKeyAlgorithms(?'id-Ed448') -> 'ECPoint'; +supportedPublicKeyAlgorithms(?'id-X25519') -> 'ECPoint'; +supportedPublicKeyAlgorithms(?'id-X448') -> 'ECPoint'. supportedCurvesTypes(?'characteristic-two-field') -> characteristic_two_field; supportedCurvesTypes(?'prime-field') -> prime_field; @@ -152,6 +156,8 @@ namedCurves(?'secp256r1') -> secp256r1; namedCurves(?'secp192r1') -> secp192r1; namedCurves(?'id-X25519') -> x25519; namedCurves(?'id-X448') -> x448; +namedCurves(?'id-Ed25519') -> ed25519; +namedCurves(?'id-Ed448') -> ed448; namedCurves(?'brainpoolP160r1') -> brainpoolP160r1; namedCurves(?'brainpoolP160t1') -> brainpoolP160t1; namedCurves(?'brainpoolP192r1') -> brainpoolP192r1; @@ -201,6 +207,8 @@ namedCurves(secp256r1) -> ?'secp256r1'; namedCurves(secp192r1) -> ?'secp192r1'; namedCurves(x25519) -> ?'id-X25519'; namedCurves(x448) -> ?'id-X448'; +namedCurves(ed25519) -> ?'id-Ed25519'; +namedCurves(ed448) -> ?'id-Ed448'; namedCurves(brainpoolP160r1) -> ?'brainpoolP160r1'; namedCurves(brainpoolP160t1) -> ?'brainpoolP160t1'; namedCurves(brainpoolP192r1) -> ?'brainpoolP192r1'; diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index 8c8b5585a0..4f097a1e2d 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -226,6 +226,18 @@ pem_entry_encode('SubjectPublicKeyInfo', Spki = {'SubjectPublicKeyInfo', {'AlgorithmIdentifier', ?'id-dsa', ParamDer}, KeyDer}, pem_entry_encode('SubjectPublicKeyInfo', Spki); +pem_entry_encode('SubjectPublicKeyInfo', + {#'ECPoint'{point = Key}, {namedCurve, ?'id-Ed25519' = ID}}) when is_binary(Key)-> + Spki = {'SubjectPublicKeyInfo', + {'AlgorithmIdentifier', ID, asn1_NOVALUE}, + Key}, + pem_entry_encode('SubjectPublicKeyInfo', Spki); +pem_entry_encode('SubjectPublicKeyInfo', + {#'ECPoint'{point = Key}, {namedCurve, ?'id-Ed448' = ID}}) when is_binary(Key)-> + Spki = {'SubjectPublicKeyInfo', + {'AlgorithmIdentifier', ID , asn1_NOVALUE}, + Key}, + pem_entry_encode('SubjectPublicKeyInfo', Spki); pem_entry_encode('SubjectPublicKeyInfo', {#'ECPoint'{point = Key}, ECParam}) when is_binary(Key)-> Params = der_encode('EcpkParameters',ECParam), @@ -270,9 +282,10 @@ pem_entry_encode(Asn1Type, Entity, {{Cipher, Salt} = CipherInfo, %% %% Description: Decodes a public key asn1 der encoded entity. %%-------------------------------------------------------------------- -der_decode(Asn1Type, Der) when (Asn1Type == 'PrivateKeyInfo') or - (Asn1Type == 'EncryptedPrivateKeyInfo') - andalso is_binary(Der) -> +der_decode(Asn1Type, Der) when (((Asn1Type == 'PrivateKeyInfo') + orelse + (Asn1Type == 'EncryptedPrivateKeyInfo')) + andalso is_binary(Der)) -> try {ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der), der_priv_key_decode(Decoded) @@ -294,6 +307,11 @@ der_priv_key_decode({'PrivateKeyInfo', v1, {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) -> EcPrivKey = der_decode('ECPrivateKey', PrivKey), EcPrivKey#'ECPrivateKey'{parameters = der_decode('EcpkParameters', Parameters)}; +der_priv_key_decode({'PrivateKeyInfo', v1, + {'PrivateKeyInfo_privateKeyAlgorithm', CurveOId, _}, PrivKey, _}) when + CurveOId == ?'id-Ed25519'orelse + CurveOId == ?'id-Ed448' -> + #'ECPrivateKey'{version = 1, parameters = {namedCurve, CurveOId}, privateKey = PrivKey}; der_priv_key_decode({'PrivateKeyInfo', v1, {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', _}, PrivKey, _}) -> der_decode('RSAPrivateKey', PrivKey); @@ -336,6 +354,14 @@ der_encode('PrivateKeyInfo', {#'RSAPrivateKey'{} = PrivKey, Parameters}) -> {'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, + privateKey = PrivKey}) when + CurveOId == ?'id-Ed25519' orelse + CurveOId == ?'id-Ed448' -> + der_encode('PrivateKeyInfo', + {'PrivateKeyInfo', v1, + {'PrivateKeyInfo_privateKeyAlgorithm', CurveOId, asn1_NOVALUE}, + PrivKey, asn1_NOVALUE}); der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = Parameters} = PrivKey) -> der_encode('PrivateKeyInfo', {'PrivateKeyInfo', v1, @@ -587,6 +613,12 @@ generate_key({rsa, ModulusSize, PublicExponent}) -> when OthersECDHkey :: #'ECPoint'{}, MyECDHkey :: #'ECPrivateKey'{}, SharedSecret :: binary(). +compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey, + parameters = {namedCurve, Curve} = Param}) + when (Curve == ?'id-X25519') orelse + (Curve == ?'id-X448') -> + ECCurve = ec_curve_spec(Param), + crypto:compute_key(eddh, Point, PrivKey, ECCurve); compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey, parameters = Param}) -> ECCurve = ec_curve_spec(Param), @@ -606,7 +638,7 @@ compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) -> {DigestType, SignatureType} when AlgorithmId :: oid(), %% Relevant dsa digest type is a subset of rsa_digest_type() - DigestType :: crypto:rsa_digest_type(), + DigestType :: crypto:rsa_digest_type() | none, SignatureType :: rsa | dsa | ecdsa . %% Description: %%-------------------------------------------------------------------- @@ -639,7 +671,11 @@ pkix_sign_types(?'ecdsa-with-SHA256') -> pkix_sign_types(?'ecdsa-with-SHA384') -> {sha384, ecdsa}; pkix_sign_types(?'ecdsa-with-SHA512') -> - {sha512, ecdsa}. + {sha512, ecdsa}; +pkix_sign_types(?'id-Ed25519') -> + {none, eddsa}; +pkix_sign_types(?'id-Ed448') -> + {none, eddsa}. %%-------------------------------------------------------------------- -spec pkix_hash_type(HashOid::oid()) -> DigestType:: md5 | crypto:sha1() | crypto:sha2(). @@ -833,10 +869,21 @@ pkix_verify(DerCert, {#'RSAPublicKey'{} = RSAKey, #'RSASSA-PSS-params'{} = Para {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), verify(PlainText, DigestType, Signature, RSAKey, rsa_opts(Params)); -pkix_verify(DerCert, Key = {#'ECPoint'{}, _}) - when is_binary(DerCert) -> - {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert), - verify(PlainText, DigestType, Signature, Key). +pkix_verify(DerCert, Key = {#'ECPoint'{}, {namedCurve, Curve}}) when (Curve == ?'id-Ed25519'orelse + Curve == ?'id-Ed448') andalso is_binary(DerCert) -> + case pubkey_cert:verify_data(DerCert) of + {none = DigestType, PlainText, Signature} -> + verify(PlainText, DigestType, Signature, Key); + _ -> + false + end; +pkix_verify(DerCert, Key = {#'ECPoint'{}, _}) when is_binary(DerCert) -> + case pubkey_cert:verify_data(DerCert) of + {none, _, _} -> + false; + {DigestType, PlainText, Signature} -> + verify(PlainText, DigestType, Signature, Key) + end. %%-------------------------------------------------------------------- -spec pkix_crl_verify(CRL, Cert) -> boolean() @@ -1366,8 +1413,13 @@ format_sign_key(Key = #'RSAPrivateKey'{}) -> {rsa, format_rsa_private_key(Key)}; format_sign_key(#'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) -> {dss, [P, Q, G, X]}; +format_sign_key(#'ECPrivateKey'{privateKey = PrivKey, parameters = {namedCurve, Curve} = Param}) + when (Curve == ?'id-Ed25519') orelse (Curve == ?'id-Ed448')-> + ECCurve = ec_curve_spec(Param), + {eddsa, [PrivKey, ECCurve]}; format_sign_key(#'ECPrivateKey'{privateKey = PrivKey, parameters = Param}) -> - {ecdsa, [PrivKey, ec_curve_spec(Param)]}; + ECCurve = ec_curve_spec(Param), + {ecdsa, [PrivKey, ECCurve]}; format_sign_key({ed_pri, Curve, _Pub, Priv}) -> {eddsa, [Priv,Curve]}; format_sign_key(_) -> @@ -1375,8 +1427,13 @@ format_sign_key(_) -> format_verify_key(#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) -> {rsa, [Exp, Mod]}; +format_verify_key({#'ECPoint'{point = Point}, {namedCurve, Curve} = Param}) when (Curve == ?'id-Ed25519') orelse + (Curve == ?'id-Ed448') -> + ECCurve = ec_curve_spec(Param), + {eddsa, [Point, ECCurve]}; format_verify_key({#'ECPoint'{point = Point}, Param}) -> - {ecdsa, [Point, ec_curve_spec(Param)]}; + ECCurve = ec_curve_spec(Param), + {ecdsa, [Point, ECCurve]}; format_verify_key({Key, #'Dss-Parms'{p = P, q = Q, g = G}}) -> {dss, [P, Q, G, Key]}; format_verify_key({ed_pub, Curve, Key}) -> @@ -1628,7 +1685,8 @@ format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E, -spec ec_generate_key(ecpk_parameters_api()) -> #'ECPrivateKey'{}. ec_generate_key(Params) -> Curve = ec_curve_spec(Params), - Term = crypto:generate_key(ecdh, Curve), + CurveType = ec_curve_type(Curve), + Term = crypto:generate_key(CurveType, Curve), NormParams = ec_normalize_params(Params), ec_key(Term, NormParams). @@ -1646,16 +1704,31 @@ ec_curve_spec( #'ECParameters'{fieldID = #'FieldID'{fieldType = Type, Curve = {PCurve#'Curve'.a, PCurve#'Curve'.b, none}, {Field, Curve, Base, Order, CoFactor}; ec_curve_spec({ecParameters, ECParams}) -> - ec_curve_spec(ECParams); + ec_curve_spec(ECParams); ec_curve_spec({namedCurve, OID}) when is_tuple(OID), is_integer(element(1,OID)) -> ec_curve_spec({namedCurve, pubkey_cert_records:namedCurves(OID)}); ec_curve_spec({namedCurve, x25519 = Name}) -> Name; ec_curve_spec({namedCurve, x448 = Name}) -> Name; +ec_curve_spec({namedCurve, ed25519 = Name}) -> + Name; +ec_curve_spec({namedCurve, ed448 = Name}) -> + Name; ec_curve_spec({namedCurve, Name}) when is_atom(Name) -> (Name). +ec_curve_type(ed25519) -> + eddsa; +ec_curve_type(ed448) -> + eddsa; +ec_curve_type(x25519) -> + eddh; +ec_curve_type(x448) -> + eddh; +ec_curve_type(_) -> + ecdh. + format_field(characteristic_two_field = Type, Params0) -> #'Characteristic-two'{ m = M, diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index cf3b5ea0c8..ae16eca83e 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -55,6 +55,8 @@ ec_pem2/1, ec_priv_pkcs8/0, ec_priv_pkcs8/1, + eddsa_priv_pkcs8/0, + eddsa_priv_pkcs8/1, init_ec_pem_encode_generated/1, ec_pem_encode_generated/0, ec_pem_encode_generated/1, @@ -157,6 +159,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, ec_pem_encode_generated, gen_ec_param_prime_field, gen_ec_param_char_2_field ]}, @@ -399,6 +402,20 @@ ec_priv_pkcs8(Config) when is_list(Config) -> ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem), ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])). +eddsa_priv_pkcs8() -> + [{doc, "EDDSA PKCS8 private key decode/encode"}]. +eddsa_priv_pkcs8(Config) when is_list(Config) -> + Datadir = proplists:get_value(data_dir, Config), + {ok, ECPrivPem} = file:read_file(filename:join(Datadir, "eddsa_key_pkcs8.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('PrivateKeyInfo', 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_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/eddsa_key_pkcs8.pem new file mode 100644 index 0000000000..e447080ae2 --- /dev/null +++ b/lib/public_key/test/public_key_SUITE_data/eddsa_key_pkcs8.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC +-----END PRIVATE KEY----- -- 2.26.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor