dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.14k stars 4.71k forks source link

ECDsa support in System.Security.Cryptography.Xml.SignedXml #36103

Open Nukepayload2 opened 4 years ago

Nukepayload2 commented 4 years ago

This feature request is related to the following problem:

When I'm using System.Security.Cryptography.Xml.SignedXml, if the type of SigningKey is ECDsa, ComputeSignature will throw CryptographicException. The exception was thrown at this line: https://github.com/dotnet/runtime/blob/30119554b2be144ceff06a41326345975dd178f9/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXml.cs#L401 If I set SignedInfo.SignatureMethod to "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256" by setting protected fields through a subclass, another exception will be thrown at: https://github.com/dotnet/runtime/blob/30119554b2be144ceff06a41326345975dd178f9/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXml.cs#L408

Description of what API need to be added or changed System.Security.Cryptography.Xml.SignedXml should be able to create and verify ECDsa xml signatures.

ghost commented 4 years ago

Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq Notify danmosemsft if you want to be subscribed.

vcsjones commented 4 years ago

I believe it is possible to get this working today if you are able to implementing the formatters and are able to ensure its correctness.

If you set the signature method URI before signing, it will attempt to resolve a SignatureDescription from the CryptoConfig. So you could do something like this:

CryptoConfig.AddAlgorithm(typeof(ECDsaP256SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256");
XmlDocument doc = GetDocument();
SignedXml sxml = new SignedXml(doc);
sxml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256";
using var ecdsa = ECDsa.Create(ECCurve.NamedCurves.nistP256);
sxml.SigningKey = ecdsa;

The trick then is to create and implement the ECDsaP256SHA256SignatureDescription, which is really just used for getting an AsymmetricSignatureDeformatter and AsymmetricSignatureFormatter, which are also abstract classes that need to be implemented for ECDSA. Looking at the XmlDSig spec, it expects signatures to be in {R,S} IEEE format, which I believe ECDsa produces by default.

I threw together a gist that implements a bare-bones example here: https://gist.github.com/vcsjones/07460cd1a0adf03ade27151efdf266e2. It bears repeating that this code is a quickly thrown together example to explore the feasibility of it.

olljanat commented 10 months ago

@vcsjones thanks for sharing. Example code in you gist looks to be working correctly.

On https://gist.github.com/olljanat/848c51c141634c7306712fe1bbb20727 I combined it with HLKX package signing code and hardware submission portal looks to be detecting it as correctly signed file.

However as far I see, there is not way to define SignatureMethod method when signing is done thorough PackageDigitalSignatureManager which why at least https://github.com/olljanat/dotnet-runtime/commit/0de728bec47b76de495de322e1f919c8733fb371 should be included to here.