dotnet / runtime

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

COSE_Sign1 messages (single signer) can be read, validated, and created #32121

Closed bartonjs closed 2 years ago

bartonjs commented 4 years ago

Implement COSE Signing, IETF RFC 8152, section 4

Minimum Viable Product - Single Signer

This minimum viable product can be shipped as a NuGet package for verification by early adopters before continuing into the multiple signers scope.

Things that won't be covered on the MVP:

ryanbnl commented 3 years ago

We're using this in the wild with the EU Covid certificates; is this feature something that could figure in the coming 6-12 months? :-)

ref: https://github.com/ehn-dcc-development/hcert-spec/blob/main/hcert_spec.md

bartonjs commented 3 years ago

@ryanbnl We originally thought we had a highly engaged partner, then they turned out to need CBOR and one data structure from COSE, but not COSE itself, so we put this on the back burner.

The CBOR reader and writer are available: https://www.nuget.org/packages/System.Formats.Cbor.

I can't say how this will stack up against other things we want for 7, given that you're the first request for it. It's probably not too much work (I forget how big the spec is) to make it work in your own library code, given System.Formats.Cbor and the built-in System.Security.Cryptography types.

The harder problem for us will be the classic one: coming up with public API that we're happy with. (So far we've done not so great with SignedXml or SignedCms... third time's the charm?)

kevinmkane commented 3 years ago

@bartonjs Would it help if I made myself the second request? We're planning to use COSE_Sign1 as the signature format for an upcoming standard. In our C# prototype we're currently making do with the library at https://github.com/cose-wg/COSE-csharp.

ryanbnl commented 3 years ago

Thanks for replying @bartonjs :-)

The context of this is the EU Covid Vaccination project - we've used COSE/CBOR as part of the HCERT specifications. You can find the info here:

https://github.com/ehn-dcc-development/hcert-spec

We will start to see this implemented more broadly, especially as commercial players come on to the market. For now we are using the community implementations - so we're not blocked - but it would be great to have an official implementation. Especially given that you can share a single .Net implementation over apps (Xamarin), backend (asp.net etc) and web frontend (Blazor).

The .Net implementation is here (warning: it's very much proof-of-concept code to work as a quick example):

https://github.com/ehn-dcc-development/hcert-dotnet

SignedCms: the API isn't fantastic, but there's a lot of value having good crypto support on our platform. Between the Microsoft implementations, BouncyCastle ports and libsodium wrappers there's a lot of good, but I keep hearing from the crypto experts that Go and Python are amazing because of their crypto support.

ryanbnl commented 3 years ago

The HCERT is literally in EU law: https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX%3A32021D1073 :-)

bartonjs commented 3 years ago

Would it help if I made myself the second request?

Certainly doesn't hurt :smile:.

Putting a thumbs-up on the top post for the issue is helpful as it gives us a quick way to compare (however inacurately) the demand for one thing over another.

veikkoeeva commented 3 years ago

Could be interesting also at https://github.com/lumoin/Verifiable. Partially relatd to things @ryanbnl mentioned. So my thumb for CBOR too. :)

(Also that lib is still being established a few days in case someone goes to click around.)

veikkoeeva commented 3 years ago

@ryanbnl

SignedCms: the API isn't fantastic, but there's a lot of value having good crypto support on our platform. Between the Microsoft implementations, BouncyCastle ports and libsodium wrappers there's a lot of good, but I keep hearing from the crypto experts that Go and Python are amazing because of their crypto support.

Maybe they drop to Rust libraries undernath. Rust ecosystem seem to be where the action is. :)

I just wrote a simple wrapper to BouncyCastle, NSec and .NET libraries in https://github.com/lumoin/Verifiable. Basically the idea is an extension method with delegates (that can take Span<byte>) that abstract the different forms of the libraries and allow adding more libraries agnostic to these core libraries.

You can take a look if the idea is useful. This is like alpha stuff still (and other design that occurred to me could be something like Func<Delegate, Delegate>). Maybe this isn't the place to design. :) Sometime next week things ought to be put in place, readmes better written etc.

ryanbnl commented 3 years ago

Nice I'll have a look! I expect this to be a growth area in the future - particularly in Europe, but also because we're seeing a lot more systems in the wild that are built on crypto. I'm certainly extremely thankful to have spent the last year and a half building cool stuff that ships to millions of people with it :)

veikkoeeva commented 3 years ago

Growth surely as things are legislated -- and .NET is lacking here a bit. :)

The crypto related is at https://github.com/lumoin/Verifiable/blob/main/test/Verifiable.Tests/CryptographicCrossTests.cs. But a noted, I move things around, add comments and that sort of things next week. I think it boils down to looking at if this idea of abstracting could work for you too (I probably add a few tests that make the library specific plumbing go unvisible too, as the idea is ultimately to rely on general signature funcs that delegate to the libraries). :)

jeffhandley commented 2 years ago

https://github.com/dotnet/runtime/issues/32080 is a design/implementation detail of this item. That issue has been closed and captured here.

COSE_Key comes from IETF RFC 8152, section 7.

Some specs are already known that use COSE Key encodings that don't use all of COSE, so at a high level we should support going from AsymmetricAlgorithm to an encoded COSE_Key (byte[] / write to a Span<byte>), and going from a COSE_Key to AsymmetricAlgorithm types.

In order to maintain type safety, and reduce the risk of over-casting by callers, it probably should be something like

partial class CoseKey
{
    public CoseKeyType KeyType { get; }
    // For symmetry with certs, returns null when the key type isn't an RSA type.
    public RSA? GetRSAKey() => throw null;
    public static bool TryParseRSAKey(ReadOnlySpan<byte> encodedKey, out RSA key) => throw null;
    public static byte[] EncodeKey(RSA key);
}

Repeat for ECDsa and ECDiffieHellman. Technically it could also be defined for HMAC and symmetric key wrap, but it seems less valuable.

(Reading is probably needed before writing)