Open ThreeSevenths opened 1 year ago
Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones See info in area-owners.md if you want to be subscribed.
Author: | ThreeSevenths |
---|---|
Assignees: | - |
Labels: | `api-suggestion`, `area-System.Security` |
Milestone: | - |
I've been thinking about this for a while and glad someone else proposed it 😄.
My immediate thoughts are:
Do we want to expose strings, or Oid
instances? I like the strings because they are cheaper than an Oid instance.
We need to figure out better names for these and how to organize them. We could do nested static classes:
public static class Oids {
public static class HashAlgs {
public const string SHA3_256 = "2.16.840.1.101.3.4.2.8";
}
}
but that might be arbitrary. Going full Registry like IsoUtu.Country.Us.Orgaization.Gov.Csor.HashAlgs.SHA3_256
would be silly, I think.
- Do we want to expose strings, or
Oid
instances? I like the strings because they are cheaper than an Oid instance.
I'd agree strings are the way to go. Oid isn't heavy, but it's definitely not as light as a string. Calling .Value or adding an equality comparer could work as well. It's also less work since they are strings today. In my usage I'm doing oidinstance.Value
anyway since I don't want to allocate a readonly Oid for a simple comparison.
- We need to figure out better names for these and how to organize them. We could do nested static classes:
I don't mind a logical hierarchy like your example. HashAlgorithms
, EnhancedKeyUsages
, Extensions
, etc. Some permutation of a component of the friendly name might be the most useful. I agree following the 'rich' hierarchy of actual oids would be silly and difficult to navigate.
Ultimately I initially was thinking what's easy to do, and Find internal > Replace public is almost no effort however there is some opportunity here to make it easier to use. I think you still need to know what you're doing to use these constants directly, and there is lots of public API today to make this work in many situations for the vast majority of use cases.
Find internal > Replace public is almost no effort however there is some opportunity here to make it easier to use
While that may be a reasonable starting point, each and every name would have to be examined for appropriateness. Esdh
doesn't seem like one we'd want to leave collapsed like that. Rsa
should arguably be RsaEncryption
, and maybe we want to say that in these consts RSA
should be capital since it's capital elsewhere in our API surface, etc.
We need to figure out better names for these and how to organize them. We could do nested static classes:
Two problems with this (though it might end up being the best answer anyways): 1) it's definitely arbitrary... id-rsaEncryption is one of the trickier ones to place... it can be a signature algorithm or an encryption algorithm, since it's just a generic "RSA will be used here, some other detail will provide better context". 2) nested types don't work equally well in all languages, so someone should see what the experience would be in C#, F#, VB.NET, and ideally even COBOL.NET. Yeah, we used nested types for well-known EC curves, but we also felt that the number of people using them would be small. While OID-users are still somewhat small, they're a bigger small than EC-curve specifiers/verifiers, so cross-language usability matters more.
Do we want to expose strings, or Oid instances?
Yep. The answer might be both... Foo
and FooOid
, maybe. The string form is nicer to switch over, and can avoid allocating unnecessarily. The Oid
form has the advantage that everyone can share the same reference, reducing long-term allocations. That's why we end up with both in our well-known OIDs tables. Verifiers typically want the string, creators typically want the shared Oid reference.
Another way for doing both would be to put strings as (e.g.) public const string System.Formats.Asn1.OidValues.Pkcs12CertBag = "...";
and Oids as (e.g.) public Oid System.Security.Cryptography.WellKnownOids.Pkcs12CertBag { get; } => s_pkcs12CertBag ??= InitializeOid(System.Formats.Asn1.OidValues.Pkcs12CertBag);
It will be great that WellKnown Oids became public.
I looked around a bit at other ecosystems to see if, or how, anyone else did this.
Java and Ruby use strings for OIDs. Go uses a typealias as []int
. So no good examples there.
Rust does. Rust has a very lean stdlib. All of their cryptography is in a separate crate, including OIDs. The RustCrypto project is as close as you could get to something in-box though.
They generate a list of... every... OID.
https://github.com/RustCrypto/formats/blob/master/const-oid/src/db/gen.rs
"all of them" is probably too much for most people's needs. I was more interested in how they are organized. They are all in separate modules by the RFC or document that that defines them. Loosely, Rust modules could be static classes or namespaces.
In .NET it would be something like:
namespace System.Security.Cryptography.Oids;
public static class Fips202 {
public static Oid SHA3_256 => MakeOid("2.16.840.1.101.3.4.2.8");
// etc
}
public static class Rfc4519 {
public static Oid CommonName => MakeOid("2.5.4.3");
}
There is a certain amount of this that I like, but some things going against it:
So I don't feel that rust gets us any close to a particular answer, but it does make me think a bit more strongly that any attempt to organize them is going to feel arbitrary.
I don't feel that I am particularly closer to having a better understanding of the direction .NET should take, and there isn't a ton of prior art to look at.
I think a point worth asking though, what OIDs do people feel that they are using frequently enough that would necessitate an accelerator?
I think it's sufficient to start with EKUs, algos that are in common usage in .NET, and x509 related [for my use case 😀]. Ideally, I'd say you should be able to read an ASN1 stream for a bog standard cert from signtool and match the OIDs that would be present. Most of the current OIDs seem to work toward that purpose.
- Most people probably don't know what RFC or document define some of the OIDs they are looking for. Would you expect CommonName in Rfc4519, or some class called X520?
I've always thought a key feature for .NET and friends is our excellent tooling, IntelliSense in this case. This greatly aids most developers to be able to discover something IF they can get close to the member name, irrespective of the namespace it is under.
- Rust has some luxury in being that it's a separate crate. Particularly they can add as many as they want and not worry about crate size or app size since Rust apps are statically linked and trimmed by default.
I guess because they'll be used in the box, we cannot have a separate NuGet package?
If this API proposal is accepted, I'd like to also see 1.3.6.1.5.5.7.3.1
(serverAuth) and 1.3.6.1.5.5.7.3.2
(clientAuth).
Will this be made public in .NET9?
Se la sont totalement priver, ça ne vous regarde pas je suis que sur ma page et pas celle des autres devant la loi personne ne pourras m'empècher sais pas a vous de me dire se que je doit faire et bon débarras avec vous mércie
De : Trevor Davis @.> Envoyé : jeudi 30 mai 2024 17:42 À : dotnet/runtime @.> Cc : Subscribed @.***> Objet : Re: [dotnet/runtime] [API Proposal]: Make System.Security.Cryptography.Oids constants public (Issue #87270)
Will this be made public in .NET9?
— Reply to this email directly, view it on GitHubhttps://github.com/dotnet/runtime/issues/87270#issuecomment-2139992833, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AUW2LQ7KUFHYZTIT7COOYC3ZE5CE7AVCNFSM6AAAAAAY7GGG3CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMZZHE4TEOBTGM. You are receiving this because you are subscribed to this thread.Message ID: @.***>
Will this be made public in .NET9?
This still has yet to be a complete API proposal and go through an API review. In particular, every name needs to be appropriate for public API.
Esdh
? How do we want to name the jack-of-all-trades RSA OID? Those are just specific examples that the name and organization probably needs work. Every one needs to be well understood.
Background and motivation
As a C# developer, I would like to have the Oids constants exposed to me so that I do not need to add my own constants for the same thing, thus reducing the size of my final output (every byte counts 😎) and reducing the chance of error.
The runtime already includes many constants as an internal class, dotnet/runtime - Oids.cs which could easily be made public instead of internal.
API Proposal
API Usage
Alternative Designs
An alternative design could include additional documentation, a big huge warning about their usage, or a tree hierarchy that maps the oids in oid hierarchy space.
Risks
There are no risks of any backward compatibility issues. There is a slight business risk that some developers that ought not to do their own certificate processing will be empowered to do so with these constants available to them.